Some code suggestions failed to be shown due to span tweaking
Nobody has claimed this yet.
- 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:
- Change the assignment of the span to be
self.token.span.shrink_to_hi(), or; - 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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