Skip to content

Commit c75e601

Browse files
committed
Highlight clarifying information in "expected/found" error
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.
1 parent 7f36543 commit c75e601

File tree

6 files changed

+160
-27
lines changed

6 files changed

+160
-27
lines changed

compiler/rustc_errors/src/diagnostic.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
641641
found_label: &dyn fmt::Display,
642642
found: DiagStyledString,
643643
) -> &mut Self {
644-
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
644+
self.note_expected_found_extra(
645+
expected_label,
646+
expected,
647+
found_label,
648+
found,
649+
DiagStyledString::normal(""),
650+
DiagStyledString::normal(""),
651+
)
645652
}
646653

647654
#[rustc_lint_diagnostics]
@@ -651,8 +658,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
651658
expected: DiagStyledString,
652659
found_label: &dyn fmt::Display,
653660
found: DiagStyledString,
654-
expected_extra: &dyn fmt::Display,
655-
found_extra: &dyn fmt::Display,
661+
expected_extra: DiagStyledString,
662+
found_extra: DiagStyledString,
656663
) -> &mut Self {
657664
let expected_label = expected_label.to_string();
658665
let expected_label = if expected_label.is_empty() {
@@ -677,10 +684,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
677684
expected_label
678685
))];
679686
msg.extend(expected.0);
680-
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
687+
msg.push(StringPart::normal(format!("`")));
688+
msg.extend(expected_extra.0);
689+
msg.push(StringPart::normal(format!("\n")));
681690
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
682691
msg.extend(found.0);
683-
msg.push(StringPart::normal(format!("`{found_extra}")));
692+
msg.push(StringPart::normal(format!("`")));
693+
msg.extend(found_extra.0);
684694

685695
// For now, just attach these as notes.
686696
self.highlighted_note(msg);

compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

+28-18
Original file line numberDiff line numberDiff line change
@@ -1725,32 +1725,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
17251725
}
17261726
}
17271727
TypeError::Sorts(values) => {
1728-
let extra = expected == found;
1728+
let extra = expected == found
1729+
// Ensure that we don't ever say something like
1730+
// expected `impl Trait` (opaque type `impl Trait`)
1731+
// found `impl Trait` (opaque type `impl Trait`)
1732+
&& values.expected.sort_string(self.tcx)
1733+
!= values.found.sort_string(self.tcx);
17291734
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
17301735
(true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
17311736
let sm = self.tcx.sess.source_map();
17321737
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1733-
format!(
1738+
DiagStyledString::normal(format!(
17341739
" (opaque type at <{}:{}:{}>)",
17351740
sm.filename_for_diagnostics(&pos.file.name),
17361741
pos.line,
17371742
pos.col.to_usize() + 1,
1738-
)
1743+
))
17391744
}
17401745
(true, ty::Alias(ty::Projection, proj))
17411746
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
17421747
{
17431748
let sm = self.tcx.sess.source_map();
17441749
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
1745-
format!(
1750+
DiagStyledString::normal(format!(
17461751
" (trait associated opaque type at <{}:{}:{}>)",
17471752
sm.filename_for_diagnostics(&pos.file.name),
17481753
pos.line,
17491754
pos.col.to_usize() + 1,
1750-
)
1755+
))
17511756
}
1752-
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1753-
(false, _) => "".to_string(),
1757+
(true, _) => {
1758+
let mut s = DiagStyledString::normal(" (");
1759+
s.push_highlighted(ty.sort_string(self.tcx));
1760+
s.push_normal(")");
1761+
s
1762+
}
1763+
(false, _) => DiagStyledString::normal(""),
17541764
};
17551765
if !(values.expected.is_simple_text() && values.found.is_simple_text())
17561766
|| (exp_found.is_some_and(|ef| {
@@ -1767,23 +1777,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
17671777
}
17681778
}))
17691779
{
1770-
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
1780+
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
1781+
&& !self.tcx.ty_is_opaque_future(found_ty)
1782+
{
17711783
// `Future` is a special opaque type that the compiler
17721784
// will try to hide in some case such as `async fn`, so
17731785
// to make an error more use friendly we will
17741786
// avoid to suggest a mismatch type with a
17751787
// type that the user usually are not using
17761788
// directly such as `impl Future<Output = u8>`.
1777-
if !self.tcx.ty_is_opaque_future(found_ty) {
1778-
diag.note_expected_found_extra(
1779-
&expected_label,
1780-
expected,
1781-
&found_label,
1782-
found,
1783-
&sort_string(values.expected),
1784-
&sort_string(values.found),
1785-
);
1786-
}
1789+
diag.note_expected_found_extra(
1790+
&expected_label,
1791+
expected,
1792+
&found_label,
1793+
found,
1794+
sort_string(values.expected),
1795+
sort_string(values.found),
1796+
);
17871797
}
17881798
}
17891799
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always
2+
//@ only-linux
3+
// Ensure that when we have a type error where both types have the same textual representation, the
4+
// diagnostic machinery highlights the clarifying comment that comes after in parentheses.
5+
trait Foo: Copy + ToString {}
6+
7+
impl<T: Copy + ToString> Foo for T {}
8+
9+
fn hide<T: Foo>(x: T) -> impl Foo {
10+
x
11+
}
12+
13+
fn main() {
14+
let mut x = (hide(0_u32), hide(0_i32));
15+
x = (x.1, x.0);
16+
}
Loading

tests/ui/impl-trait/impl-trait-in-macro.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ LL | let mut a = x;
1212
LL | a = y;
1313
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
1414
|
15-
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
16-
found type parameter `impl Debug` (type parameter `impl Debug`)
15+
= note: expected type parameter `impl Debug`
16+
found type parameter `impl Debug`
1717
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
1818
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
1919

tests/ui/impl-trait/universal-two-impl-traits.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ LL | let mut a = x;
1010
LL | a = y;
1111
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
1212
|
13-
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
14-
found type parameter `impl Debug` (type parameter `impl Debug`)
13+
= note: expected type parameter `impl Debug`
14+
found type parameter `impl Debug`
1515
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
1616
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
1717

0 commit comments

Comments
 (0)