Skip to content

Suggest only Span without source changes when source code is unavailable #144585

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2014,12 +2014,52 @@ impl HumanEmitter {
debug!(?suggestions);

if suggestions.is_empty() {
// Here we check if there are suggestions that have actual code changes. We sometimes
// suggest the same code that is already there, instead of changing how we produce the
// suggestions and filtering there, we just don't emit the suggestion.
// Suggestions coming from macros can also have malformed spans. This is a heavy handed
// approach to avoid ICEs by ignoring the suggestion outright.
return Ok(());
// Check if this is because source file is unavailable
let has_unavailable_source =
suggestion.substitutions.iter().flat_map(|sub| &sub.parts).any(|part| {
if let Ok(lines) = sm.span_to_lines(part.span) {
!sm.ensure_source_file_source_present(&lines.file)
} else {
false
}
});
// Only when source unavailable, use the original suggestion spans for proper location display
if has_unavailable_source {
// When source is unavailable, use the original suggestion spans for proper location display
let suggestion_span = if !suggestion.substitutions.is_empty() {
// Use the span from the first substitution part
let parts: Vec<_> = suggestion
.substitutions
.iter()
.flat_map(|sub| &sub.parts)
.map(|part| part.span)
.collect();
if !parts.is_empty() { MultiSpan::from_spans(parts) } else { span.clone() }
} else {
span.clone()
};

return self.emit_messages_default_inner(
&suggestion_span,
&[(suggestion.msg.to_owned(), Style::HeaderMsg)],
args,
&None,
level,
max_line_num_len,
true,
false,
);
} else {
// If source is available but suggestions are empty
// this is because of some reason in `splice_lines`, skip
//
// Here we check if there are suggestions that have actual code changes.
// We sometimes suggest the same code that is already there, instead of changing how we produce the
// suggestions and filtering there, we just don't emit the suggestion.
// Suggestions coming from macros can also have malformed spans. This is a heavy handed
// approach to avoid ICEs by ignoring the suggestion outright.
return Ok(());
}
}

let mut buffer = StyledBuffer::new();
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/compiletest-self-test/help-show-std-source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
enum Foo<T> {
Bar {
v23: T,
y: isize
}
}

fn f(x: &Foo) { //~ ERROR missing generics for enum `Foo` [E0107]
match *x {
Foo::Bar { y: y, v23: x } => {
assert_eq!(x, 1);
assert_eq!(y, 2); //~ ERROR can't compare `&isize` with `{integer}` [E0277]
}
}
}

pub fn main() {
let x = Foo::Bar { x: 1, y: 2 }; //~ ERROR variant `Foo<_>::Bar` has no field named `x` [E0559]
f(&x);
}
39 changes: 39 additions & 0 deletions tests/ui/compiletest-self-test/help-show-std-source.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0107]: missing generics for enum `Foo`
--> $DIR/help-show-std-source.rs:8:10
|
LL | fn f(x: &Foo) {
| ^^^ expected 1 generic argument
|
note: enum defined here, with 1 generic parameter: `T`
--> $DIR/help-show-std-source.rs:1:6
|
LL | enum Foo<T> {
| ^^^ -
help: add missing generic argument
|
LL | fn f(x: &Foo<T>) {
| +++

error[E0277]: can't compare `&isize` with `{integer}`
--> $DIR/help-show-std-source.rs:12:13
|
LL | assert_eq!(y, 2);
| ^^^^^^^^^^^^^^^^ no implementation for `&isize == {integer}`
|
= help: the trait `PartialEq<{integer}>` is not implemented for `&isize`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider dereferencing here
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL

Comment on lines +25 to +27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've written up this change in the PR description above, and it should have a similar mechanism to span_note for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be suggesting changes to code the user doesn't own, specially for stdlib. For a suggestion here it should be pointing at the parameters instead (which might be difficult to accomplish).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is exactly the problem we need to solve.

This pr is to solve the problem that UI test can't be reproduced to make suggestions in std. Being able to reproduce compiler bugs will make review easier.

This comment was marked as duplicate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pr is to solve the problem that UI test can't be reproduced to make suggestions in std.

I'm not 100% convinced this is the right problem to solve -- do we actually need the standard library sources, or can we just s/std/external crate/?

Copy link
Contributor Author

@xizheyin xizheyin Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way is to use two files to represent two crate in ui test to simulate this situation. (If full reproduction is not required)

That is what this comment points out.
#144266 (comment)

But I think it is reasonable to be able to reproduce any bug in the test.

@compiler-errors What do you think?

error[E0559]: variant `Foo<_>::Bar` has no field named `x`
--> $DIR/help-show-std-source.rs:18:24
|
LL | let x = Foo::Bar { x: 1, y: 2 };
| ^ `Foo<_>::Bar` does not have this field
|
= note: available fields are: `v23`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0107, E0277, E0559.
For more information about an error, try `rustc --explain E0107`.
Loading