Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consuming emit #119606

Merged
merged 14 commits into from
Jan 8, 2024
Merged

Consuming emit #119606

merged 14 commits into from
Jan 8, 2024

Commits on Jan 8, 2024

  1. Remove Clone impl for DiagnosticBuilder.

    It seems like a bad idea, just asking for diagnostics to be emitted
    multiple times.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    ca2fc42 View commit details
    Browse the repository at this point in the history
  2. Make DiagnosticBuilder::emit consuming.

    This works for most of its call sites. This is nice, because `emit` very
    much makes sense as a consuming operation -- indeed,
    `DiagnosticBuilderState` exists to ensure no diagnostic is emitted
    twice, but it uses runtime checks.
    
    For the small number of call sites where a consuming emit doesn't work,
    the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
    be removed in subsequent commits.)
    
    Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
    consuming, while `delay_as_bug_without_consuming` is added (which will
    also be removed in subsequent commits.)
    
    All this requires significant changes to `DiagnosticBuilder`'s chaining
    methods. Currently `DiagnosticBuilder` method chaining uses a
    non-consuming `&mut self -> &mut Self` style, which allows chaining to
    be used when the chain ends in `emit()`, like so:
    ```
        struct_err(msg).span(span).emit();
    ```
    But it doesn't work when producing a `DiagnosticBuilder` value,
    requiring this:
    ```
        let mut err = self.struct_err(msg);
        err.span(span);
        err
    ```
    This style of chaining won't work with consuming `emit` though. For
    that, we need to use to a `self -> Self` style. That also would allow
    `DiagnosticBuilder` production to be chained, e.g.:
    ```
        self.struct_err(msg).span(span)
    ```
    However, removing the `&mut self -> &mut Self` style would require that
    individual modifications of a `DiagnosticBuilder` go from this:
    ```
        err.span(span);
    ```
    to this:
    ```
        err = err.span(span);
    ```
    There are *many* such places. I have a high tolerance for tedious
    refactorings, but even I gave up after a long time trying to convert
    them all.
    
    Instead, this commit has it both ways: the existing `&mut self -> Self`
    chaining methods are kept, and new `self -> Self` chaining methods are
    added, all of which have a `_mv` suffix (short for "move"). Changes to
    the existing `forward!` macro lets this happen with very little
    additional boilerplate code. I chose to add the suffix to the new
    chaining methods rather than the existing ones, because the number of
    changes required is much smaller that way.
    
    This doubled chainging is a bit clumsy, but I think it is worthwhile
    because it allows a *lot* of good things to subsequently happen. In this
    commit, there are many `mut` qualifiers removed in places where
    diagnostics are emitted without being modified. In subsequent commits:
    - chaining can be used more, making the code more concise;
    - more use of chaining also permits the removal of redundant diagnostic
      APIs like `struct_err_with_code`, which can be replaced easily with
      `struct_err` + `code_mv`;
    - `emit_without_diagnostic` can be removed, which simplifies a lot of
      machinery, removing the need for `DiagnosticBuilderState`.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    b1b9278 View commit details
    Browse the repository at this point in the history
  3. Use chaining in DiagnosticBuilder construction.

    To avoid the use of a mutable local variable, and because it reads more
    nicely.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    589591e View commit details
    Browse the repository at this point in the history
  4. Use chaining for DiagnosticBuilder construction and emit.

    To avoid the use of a mutable local variable, and because it reads more
    nicely.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    bd4e623 View commit details
    Browse the repository at this point in the history
  5. Remove all eight DiagnosticBuilder::*_with_code methods.

    These all have relatively low use, and can be perfectly emulated with
    a simpler construction method combined with `code` or `code_mv`.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    6682f24 View commit details
    Browse the repository at this point in the history
  6. Remove a DiagnosticBuilder::emit_without_consuming call.

    In this parsing recovery function, we only need to emit the previously
    obtained error message and mark `expr` as erroneous in the case where we
    actually recover.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    1881055 View commit details
    Browse the repository at this point in the history
  7. Remove a second DiagnosticBuilder::emit_without_consuming call.

    Instead of taking `seq` as a mutable reference,
    `maybe_recover_struct_lit_bad_delims` now consumes `seq` on the recovery
    path, and returns `seq` unchanged on the non-recovery path. The commit
    also combines an `if` and a `match` to merge two identical paths.
    
    Also change `recover_seq_parse_error` so it receives a `PErr` instead of
    a `PResult`, because all the call sites now handle the `Ok`/`Err`
    distinction themselves.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    3ce34f4 View commit details
    Browse the repository at this point in the history
  8. Remove a third DiagnosticBuilder::emit_without_consuming call.

    It's not clear why this was here, because the created error is returned
    as a normal error anyway.
    
    Nor is it clear why removing the call works. The change doesn't affect
    any tests; `tests/ui/parser/issues/issue-102182-impl-trait-recover.rs`
    looks like the only test that could have been affected.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    1b6c8e7 View commit details
    Browse the repository at this point in the history
  9. Remove a fourth DiagnosticBuilder::emit_without_consuming call.

    The old code was very hard to understand, involving an
    `emit_without_consuming` call *and* a `delay_as_bug_without_consuming`
    call.
    
    With slight changes both calls can be avoided. Not creating the error
    until later is crucial, as is the early return in the `if recovered`
    block.
    
    It took me some time to come up with this reworking -- it went through
    intermediate states much further from the original code than this final
    version -- and it's isn't obvious at a glance that it is equivalent. But
    I think it is, and the unchanged test behaviour is good supporting
    evidence.
    
    The commit also changes `check_trailing_angle_brackets` to return
    `Option<ErrorGuaranteed>`. This provides a stricter proof that it
    emitted an error message than asserting `dcx.has_errors().is_some()`,
    which would succeed if any error had previously been emitted anywhere.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    c733a02 View commit details
    Browse the repository at this point in the history
  10. Remove DiagnosticBuilder::emit_without_consuming.

    A nice cleanup: it's now impossible to directly emit a
    `DiagnosticBuilder` without consuming it.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    d406278 View commit details
    Browse the repository at this point in the history
  11. Remove DiagnosticBuilder::delay_as_bug_without_consuming.

    The existing uses are replaced in one of three ways.
    - In a function that also has calls to `emit`, just rearrange the code
      so that exactly one of `delay_as_bug` or `emit` is called on every
      path.
    - In a function returning a `DiagnosticBuilder`, use
      `downgrade_to_delayed_bug`. That's good enough because it will get
      emitted later anyway.
    - In `unclosed_delim_err`, one set of errors is being replaced with
      another set, so just cancel the original errors.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    4752a92 View commit details
    Browse the repository at this point in the history
  12. Make emit_producing_{guarantee,nothing} consuming.

    This is now possible, thanks to changes in previous commits.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    0cb486b View commit details
    Browse the repository at this point in the history
  13. Remove DiagnosticBuilderState.

    Currently it's used for two dynamic checks:
    - When a diagnostic is emitted, has it been emitted before?
    - When a diagnostic is dropped, has it been emitted/cancelled?
    
    The first check is no longer need, because `emit` is consuming, so it's
    impossible to emit a `DiagnosticBuilder` twice. The second check is
    still needed.
    
    This commit replaces `DiagnosticBuilderState` with a simpler
    `Option<Box<Diagnostic>>`, which is enough for the second check:
    functions like `emit` and `cancel` can take the `Diagnostic` and then
    `drop` can check that the `Diagnostic` was taken.
    
    The `DiagCtxt` reference from `DiagnosticBuilderState` is now stored as
    its own field, removing the need for the `dcx` method.
    
    As well as making the code shorter and simpler, the commit removes:
    - One (deprecated) `ErrorGuaranteed::unchecked_claim_error_was_emitted`
      call.
    - Two `FIXME(eddyb)` comments that are no longer relevant.
    - The use of a dummy `Diagnostic` in `into_diagnostic`.
    
    Nice!
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    2d91c6d View commit details
    Browse the repository at this point in the history
  14. Remove {DiagCtxt,DiagCtxtInner}::emit_diagnostic_without_consuming.

    They are no longer used, because
    `{DiagCtxt,DiagCtxtInner}::emit_diagnostic` are used everywhere instead.
    
    This also means `track_diagnostic` can become consuming.
    nnethercote committed Jan 8, 2024
    Configuration menu
    Copy the full SHA
    db09eb2 View commit details
    Browse the repository at this point in the history