Rollup merge of #136415 - estebank:highlight-clarification, r=compiler-errors
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. 
This commit is contained in:
commit
7e3d872bc0
6 changed files with 160 additions and 27 deletions
|
@ -644,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
||||||
found_label: &dyn fmt::Display,
|
found_label: &dyn fmt::Display,
|
||||||
found: DiagStyledString,
|
found: DiagStyledString,
|
||||||
) -> &mut Self {
|
) -> &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]
|
#[rustc_lint_diagnostics]
|
||||||
|
@ -654,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
||||||
expected: DiagStyledString,
|
expected: DiagStyledString,
|
||||||
found_label: &dyn fmt::Display,
|
found_label: &dyn fmt::Display,
|
||||||
found: DiagStyledString,
|
found: DiagStyledString,
|
||||||
expected_extra: &dyn fmt::Display,
|
expected_extra: DiagStyledString,
|
||||||
found_extra: &dyn fmt::Display,
|
found_extra: DiagStyledString,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
let expected_label = expected_label.to_string();
|
let expected_label = expected_label.to_string();
|
||||||
let expected_label = if expected_label.is_empty() {
|
let expected_label = if expected_label.is_empty() {
|
||||||
|
@ -680,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
||||||
expected_label
|
expected_label
|
||||||
))];
|
))];
|
||||||
msg.extend(expected.0);
|
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.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
|
||||||
msg.extend(found.0);
|
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.
|
// For now, just attach these as notes.
|
||||||
self.highlighted_note(msg);
|
self.highlighted_note(msg);
|
||||||
|
|
|
@ -1722,32 +1722,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeError::Sorts(values) => {
|
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()) {
|
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
|
||||||
(true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
|
(true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
|
||||||
let sm = self.tcx.sess.source_map();
|
let sm = self.tcx.sess.source_map();
|
||||||
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
|
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
|
||||||
format!(
|
DiagStyledString::normal(format!(
|
||||||
" (opaque type at <{}:{}:{}>)",
|
" (opaque type at <{}:{}:{}>)",
|
||||||
sm.filename_for_diagnostics(&pos.file.name),
|
sm.filename_for_diagnostics(&pos.file.name),
|
||||||
pos.line,
|
pos.line,
|
||||||
pos.col.to_usize() + 1,
|
pos.col.to_usize() + 1,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
(true, ty::Alias(ty::Projection, proj))
|
(true, ty::Alias(ty::Projection, proj))
|
||||||
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
|
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||||
{
|
{
|
||||||
let sm = self.tcx.sess.source_map();
|
let sm = self.tcx.sess.source_map();
|
||||||
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
|
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
|
||||||
format!(
|
DiagStyledString::normal(format!(
|
||||||
" (trait associated opaque type at <{}:{}:{}>)",
|
" (trait associated opaque type at <{}:{}:{}>)",
|
||||||
sm.filename_for_diagnostics(&pos.file.name),
|
sm.filename_for_diagnostics(&pos.file.name),
|
||||||
pos.line,
|
pos.line,
|
||||||
pos.col.to_usize() + 1,
|
pos.col.to_usize() + 1,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
|
(true, _) => {
|
||||||
(false, _) => "".to_string(),
|
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())
|
if !(values.expected.is_simple_text() && values.found.is_simple_text())
|
||||||
|| (exp_found.is_some_and(|ef| {
|
|| (exp_found.is_some_and(|ef| {
|
||||||
|
@ -1764,23 +1774,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
|
// `Future` is a special opaque type that the compiler
|
||||||
// will try to hide in some case such as `async fn`, so
|
// will try to hide in some case such as `async fn`, so
|
||||||
// to make an error more use friendly we will
|
// to make an error more use friendly we will
|
||||||
// avoid to suggest a mismatch type with a
|
// avoid to suggest a mismatch type with a
|
||||||
// type that the user usually are not using
|
// type that the user usually are not using
|
||||||
// directly such as `impl Future<Output = u8>`.
|
// directly such as `impl Future<Output = u8>`.
|
||||||
if !self.tcx.ty_is_opaque_future(found_ty) {
|
diag.note_expected_found_extra(
|
||||||
diag.note_expected_found_extra(
|
&expected_label,
|
||||||
&expected_label,
|
expected,
|
||||||
expected,
|
&found_label,
|
||||||
&found_label,
|
found,
|
||||||
found,
|
sort_string(values.expected),
|
||||||
&sort_string(values.expected),
|
sort_string(values.found),
|
||||||
&sort_string(values.found),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
tests/ui/error-emitter/E0308-clarification.rs
Normal file
16
tests/ui/error-emitter/E0308-clarification.rs
Normal file
|
@ -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
tests/ui/error-emitter/E0308-clarification.svg
Normal file
97
tests/ui/error-emitter/E0308-clarification.svg
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<svg width="740px" height="668px" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<style>
|
||||||
|
.fg { fill: #AAAAAA }
|
||||||
|
.bg { background: #000000 }
|
||||||
|
.fg-ansi256-009 { fill: #FF5555 }
|
||||||
|
.fg-ansi256-012 { fill: #5555FF }
|
||||||
|
.fg-magenta { fill: #AA00AA }
|
||||||
|
.container {
|
||||||
|
padding: 0 10px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
.bold { font-weight: bold; }
|
||||||
|
tspan {
|
||||||
|
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||||
|
white-space: pre;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||||
|
|
||||||
|
<text xml:space="preserve" class="container fg">
|
||||||
|
<tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:10</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide<T: Foo>(x: T) -> impl Foo {</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">‡</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="190px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> x = (x.1, x.0);</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `u32`, found `i32`</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="280px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="298px">
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="316px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="334px"><tspan> </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:15</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="352px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="370px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide<T: Foo>(x: T) -> impl Foo {</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="388px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="406px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="424px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="442px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="460px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">‡</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="478px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> x = (x.1, x.0);</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="496px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `i32`, found `u32`</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="514px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="532px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="586px">
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="604px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 2 previous errors</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="622px">
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="640px"><tspan class="bold">For more information about this error, try `rustc --explain E0308`.</tspan>
|
||||||
|
</tspan>
|
||||||
|
<tspan x="10px" y="658px">
|
||||||
|
</tspan>
|
||||||
|
</text>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -12,8 +12,8 @@ LL | let mut a = x;
|
||||||
LL | a = y;
|
LL | a = y;
|
||||||
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
||||||
|
|
|
|
||||||
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
|
= note: expected type parameter `impl Debug`
|
||||||
found type parameter `impl Debug` (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: 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
|
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ LL | let mut a = x;
|
||||||
LL | a = y;
|
LL | a = y;
|
||||||
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
||||||
|
|
|
|
||||||
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
|
= note: expected type parameter `impl Debug`
|
||||||
found type parameter `impl Debug` (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: 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
|
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue