Skip to content

Commit

Permalink
Highlight clarifying information in "expected/found" error
Browse files Browse the repository at this point in the history
When the expected and found types have the same textual representation, we add clarifying in parentheses. We now visually highlight it in the output.

Detect a corner case where the clarifying information would be the same for both types and skip it, as it doesn't add anything useful.
  • Loading branch information
estebank committed Feb 2, 2025
1 parent 7f36543 commit c75e601
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 27 deletions.
20 changes: 15 additions & 5 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
found_label: &dyn fmt::Display,
found: DiagStyledString,
) -> &mut Self {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
self.note_expected_found_extra(
expected_label,
expected,
found_label,
found,
DiagStyledString::normal(""),
DiagStyledString::normal(""),
)
}

#[rustc_lint_diagnostics]
Expand All @@ -651,8 +658,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
expected: DiagStyledString,
found_label: &dyn fmt::Display,
found: DiagStyledString,
expected_extra: &dyn fmt::Display,
found_extra: &dyn fmt::Display,
expected_extra: DiagStyledString,
found_extra: DiagStyledString,
) -> &mut Self {
let expected_label = expected_label.to_string();
let expected_label = if expected_label.is_empty() {
Expand All @@ -677,10 +684,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
expected_label
))];
msg.extend(expected.0);
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
msg.push(StringPart::normal(format!("`")));
msg.extend(expected_extra.0);
msg.push(StringPart::normal(format!("\n")));
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
msg.extend(found.0);
msg.push(StringPart::normal(format!("`{found_extra}")));
msg.push(StringPart::normal(format!("`")));
msg.extend(found_extra.0);

// For now, just attach these as notes.
self.highlighted_note(msg);
Expand Down
46 changes: 28 additions & 18 deletions compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1725,32 +1725,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
TypeError::Sorts(values) => {
let extra = expected == found;
let extra = expected == found
// Ensure that we don't ever say something like
// expected `impl Trait` (opaque type `impl Trait`)
// found `impl Trait` (opaque type `impl Trait`)
&& values.expected.sort_string(self.tcx)
!= values.found.sort_string(self.tcx);
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
DiagStyledString::normal(format!(
" (opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
))
}
(true, ty::Alias(ty::Projection, proj))
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
format!(
DiagStyledString::normal(format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
))
}
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
(true, _) => {
let mut s = DiagStyledString::normal(" (");
s.push_highlighted(ty.sort_string(self.tcx));
s.push_normal(")");
s
}
(false, _) => DiagStyledString::normal(""),
};
if !(values.expected.is_simple_text() && values.found.is_simple_text())
|| (exp_found.is_some_and(|ef| {
Expand All @@ -1767,23 +1777,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}))
{
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
&& !self.tcx.ty_is_opaque_future(found_ty)
{
// `Future` is a special opaque type that the compiler
// will try to hide in some case such as `async fn`, so
// to make an error more use friendly we will
// avoid to suggest a mismatch type with a
// type that the user usually are not using
// directly such as `impl Future<Output = u8>`.
if !self.tcx.ty_is_opaque_future(found_ty) {
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
&sort_string(values.expected),
&sort_string(values.found),
);
}
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
sort_string(values.expected),
sort_string(values.found),
);
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/error-emitter/E0308-clarification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always
//@ only-linux
// Ensure that when we have a type error where both types have the same textual representation, the
// diagnostic machinery highlights the clarifying comment that comes after in parentheses.
trait Foo: Copy + ToString {}

impl<T: Copy + ToString> Foo for T {}

fn hide<T: Foo>(x: T) -> impl Foo {
x
}

fn main() {
let mut x = (hide(0_u32), hide(0_i32));
x = (x.1, x.0);
}
97 changes: 97 additions & 0 deletions tests/ui/error-emitter/E0308-clarification.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/impl-trait-in-macro.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ LL | let mut a = x;
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
found type parameter `impl Debug` (type parameter `impl Debug`)
= note: expected type parameter `impl Debug`
found type parameter `impl Debug`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/universal-two-impl-traits.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ LL | let mut a = x;
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
found type parameter `impl Debug` (type parameter `impl Debug`)
= note: expected type parameter `impl Debug`
found type parameter `impl Debug`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

Expand Down

0 comments on commit c75e601

Please sign in to comment.