rust-lang / rust-lang/rust

Some code suggestions failed to be shown due to span tweaking

Open
#134,061 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics A-parser A-suggestion-diagnostics C-bug D-invalid-suggestion I-ICE requires-debug-assertions S-bug-has-test T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code
const x: () = |&'a
Current output
error: unexpected lifetime `'a` in pattern
 --> fuzz_input.rs:1:19
  |
1 | const x: () = |&'a
  |                 ^^
  |

error: expected parameter name, found `<eof>`
 --> fuzz_input.rs:1:19
  |
1 | const x: () = |&'a
  |                 ^^ expected parameter name

error: aborting due to 2 previous errors
Desired output
error: unexpected lifetime `'a` in pattern
 --> fuzz_input.rs:1:19
  |
1 | const x: () = |&'a
  |                 ^^
  |
help: remove the lifetime
  |
1 - const x: () = |&'a
1 + const x: () = |&
  |

error: expected parameter name, found `<eof>`
 --> fuzz_input.rs:1:21
  |
1 | const x: () = |&'a
  |                   ^ expected parameter name

error: aborting due to 2 previous errors
Rationale and extra context

This originates from this line in the bump function:

if next.0.span.is_dummy() {
    // Tweak the location for better diagnostics, but keep syntactic context intact.
    let fallback_span = self.token.span; // <------ This line
    next.0.span = fallback_span.with_ctxt(next.0.span.ctxt());
}

In the example input, the lifetime token is followed by an <eof> token, which has the dummy span as specified in inlined_next function. Thus the bump function sets the span of the latter to that of the former, leading to an overlap. Then, in the construction site of the UnexpectedLifetimeInPattern diagnostic in the parse_pat_deref function, the suggestion span constructed from untiling these spans becomes an empty span. Coincidentally, the suggestion code of this diagnostic is empty (removing the lifetime), causing the suggestion to be suppressed.

self.dcx().emit_err(UnexpectedLifetimeInPattern {
    span: self.prev_token.span,
    symbol: lifetime.name,
    suggestion: self.prev_token.span.until(self.token.span), // <------ This line
});

In fact, the current behavior also causes a debug_assert! to fail in the span_suggestion_with_style function:

debug_assert!(
    !(sp.is_empty() && suggestion.to_string().is_empty()),
    "Span must not be empty and have no suggestion"
);

I have 2 possible suggestions for fixing the problem:

  1. Change the assignment of the span to be self.token.span.shrink_to_hi(), or;
  2. Change the span of the returned <eof> token to be at the end position instead of the dummy span.

I have implemented and tested the first suggestion, and it works as expected. However, due to my lack of knowledge of the code base, I cannot figure out the other possible effects on the rest of the code, so I didn't open a pull request to fix this directly.

Other cases

Rust Version
rustc 1.85.0-nightly (9c707a8b7 2024-12-07)
binary: rustc
commit-hash: 9c707a8b769523bb6768bf58e74fa2c39cc24844
commit-date: 2024-12-07
host: x86_64-unknown-linux-gnu
release: 1.85.0-nightly
LLVM version: 19.1.5
Anything else?

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in compiler/rustc_parse/src/parser/mod.rs at Parser::bump and compare the dummy-span handling with the EOF token from inlined_next. Then inspect compiler/rustc_parse/src/parser/pat.rs at parse_pat_deref and the debug assertion in compiler/rustc_errors/src/diagnostic.rs. Reproduce the Rust snippet and verify that the lifetime suggestion is shown, spans no longer overlap, and the assertion does not fail.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.