Skip to content

recurse into refs when comparing tys for diagnostics #118730

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

Merged
merged 1 commit into from
Dec 9, 2023
Merged
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
94 changes: 52 additions & 42 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1181,37 +1181,54 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());

// helper functions
fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match (a.kind(), b.kind()) {
(a, b) if *a == *b => true,
(&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
| (
&ty::Infer(ty::InferTy::IntVar(_)),
&ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)),
)
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
| (
&ty::Infer(ty::InferTy::FloatVar(_)),
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
) => true,
_ => false,
let recurse = |t1, t2, values: &mut (DiagnosticStyledString, DiagnosticStyledString)| {
let (x1, x2) = self.cmp(t1, t2);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
};

fn fmt_region<'tcx>(region: ty::Region<'tcx>) -> String {
let mut r = region.to_string();
if r == "'_" {
r.clear();
} else {
r.push(' ');
}
format!("&{r}")
}

fn push_ty_ref<'tcx>(
fn push_ref<'tcx>(
region: ty::Region<'tcx>,
ty: Ty<'tcx>,
mutbl: hir::Mutability,
s: &mut DiagnosticStyledString,
) {
let mut r = region.to_string();
if r == "'_" {
r.clear();
s.push_highlighted(fmt_region(region));
s.push_highlighted(mutbl.prefix_str());
}

fn cmp_ty_refs<'tcx>(
r1: ty::Region<'tcx>,
mut1: hir::Mutability,
r2: ty::Region<'tcx>,
mut2: hir::Mutability,
ss: &mut (DiagnosticStyledString, DiagnosticStyledString),
) {
let (r1, r2) = (fmt_region(r1), fmt_region(r2));
if r1 != r2 {
ss.0.push_highlighted(r1);
ss.1.push_highlighted(r2);
} else {
r.push(' ');
ss.0.push_normal(r1);
ss.1.push_normal(r2);
}

if mut1 != mut2 {
ss.0.push_highlighted(mut1.prefix_str());
ss.1.push_highlighted(mut2.prefix_str());
} else {
ss.0.push_normal(mut1.prefix_str());
ss.1.push_normal(mut2.prefix_str());
}
s.push_highlighted(format!("&{}{}", r, mutbl.prefix_str()));
s.push_normal(ty.to_string());
}

// process starts here
Expand Down Expand Up @@ -1310,9 +1327,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
values.0.push_normal("_");
values.1.push_normal("_");
} else {
let (x1, x2) = self.cmp(ta1, ta2);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
recurse(ta1, ta2, &mut values);
}
self.push_comma(&mut values.0, &mut values.1, len, i);
}
Expand Down Expand Up @@ -1418,27 +1433,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}

// When finding T != &T, highlight only the borrow
(&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(ref_ty1, t2) => {
// When finding `&T != &T`, compare the references, then recurse into pointee type
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) => {
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
values.1.push_normal(t2.to_string());
cmp_ty_refs(r1, mutbl1, r2, mutbl2, &mut values);
recurse(ref_ty1, ref_ty2, &mut values);
values
}
(_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(t1, ref_ty2) => {
// When finding T != &T, highlight the borrow
(&ty::Ref(r1, ref_ty1, mutbl1), _) => {
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
values.0.push_normal(t1.to_string());
push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
push_ref(r1, mutbl1, &mut values.0);
recurse(ref_ty1, t2, &mut values);
values
}

// When encountering &T != &mut T, highlight only the borrow
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
if equals(ref_ty1, ref_ty2) =>
{
(_, &ty::Ref(r2, ref_ty2, mutbl2)) => {
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
push_ref(r2, mutbl2, &mut values.1);
recurse(t1, ref_ty2, &mut values);
values
}

Expand All @@ -1448,9 +1460,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(DiagnosticStyledString::normal("("), DiagnosticStyledString::normal("("));
let len = args1.len();
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
let (x1, x2) = self.cmp(left, right);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
recurse(left, right, &mut values);
self.push_comma(&mut values.0, &mut values.1, len, i);
}
if len == 1 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0308]: const not compatible with trait
LL | const NAME: &'a str = "unit";
| ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected reference `&'static str`
found reference `&'a str`
= note: expected reference `&'static _`
found reference `&'a _`
note: the lifetime `'a` as defined here...
--> $DIR/associated-const-impl-wrong-lifetime.rs:6:6
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | debug_assert_eq!(iter.next(), Some(value));
| ^^^^^^^^^^^ expected `Option<<I as Iterator>::Item>`, found `Option<&<I as Iterator>::Item>`
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like maybe we should use the expected/found ones now instead for the label, as they end up being significantly shorter.

|
= note: expected enum `Option<<I as Iterator>::Item>`
found enum `Option<&<I as Iterator>::Item>`
= note: expected enum `Option<_>`
found enum `Option<&_>`

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ note: type in trait
|
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
found signature `fn(&i32) -> impl Future<Output = i32>`
= note: expected signature `fn(&_) -> Pin<Box<dyn Future<Output = i32>>>`
found signature `fn(&_) -> impl Future<Output = i32>`

error: aborting due to 1 previous error

Expand Down
8 changes: 4 additions & 4 deletions tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ error[E0308]: method not compatible with trait
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
= note: expected signature `fn(&'a _, Inv<'c>, Inv<'c>, Inv<'_>)`
found signature `fn(&'a _, Inv<'_>, Inv<'c>, Inv<'_>)`
note: the lifetime `'c` as defined here...
--> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
|
Expand All @@ -41,8 +41,8 @@ error[E0308]: method not compatible with trait
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
= note: expected signature `fn(&'a _, Inv<'c>, Inv<'c>, Inv<'_>)`
found signature `fn(&'a _, Inv<'_>, Inv<'c>, Inv<'_>)`
note: the lifetime `'c` as defined here...
--> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/box/issue-82446.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | val
| ^^^ expected `Box<dyn MyTrait>`, found `&Box<dyn MyTrait>`
|
= note: expected struct `Box<(dyn MyTrait + 'static)>`
found reference `&Box<(dyn MyTrait + 'static)>`
= note: expected struct `Box<_>`
found reference `&Box<_>`

error: aborting due to 1 previous error

Expand Down
12 changes: 6 additions & 6 deletions tests/ui/closure-expected-type/expect-fn-supply-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,26 @@ error[E0308]: mismatched types
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
| ^ one type is more general than the other
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `for<'a> fn(&'a u32)`
= note: expected fn pointer `fn(&_)`
found fn pointer `for<'a> fn(&'a _)`

error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:39:50
|
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
| ^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a u32)`
found fn pointer `fn(&u32)`
= note: expected fn pointer `for<'a> fn(&'a _)`
found fn pointer `fn(&_)`

error[E0308]: mismatched types
--> $DIR/expect-fn-supply-fn.rs:48:50
|
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
| ^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a u32)`
found fn pointer `fn(&u32)`
= note: expected fn pointer `for<'a> fn(&'a _)`
found fn pointer `fn(&_)`

error: aborting due to 5 previous errors

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/closures/multiple-fn-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ LL | foo(move |x| v);
| |
| expected due to this
|
= note: expected closure signature `fn(char) -> _`
found closure signature `for<'a> fn(&'a char) -> _`
= note: expected closure signature `fn(_) -> _`
found closure signature `for<'a> fn(&'a _) -> _`
note: closure inferred to have a different signature due to this bound
--> $DIR/multiple-fn-bounds.rs:1:11
|
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/fn/fn-pointer-mismatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ fn main() {
// suggest removing reference
let c: fn(u32) -> u32 = &foo;
//~^ ERROR mismatched types
//~| expected fn pointer `fn(u32) -> u32`
//~| found reference `&fn(u32) -> u32 {foo}`
//~| expected fn pointer `fn(_) -> _`
//~| found reference `&fn(_) -> _ {foo}`

// suggest using reference
let d: &fn(u32) -> u32 = foo;
//~^ ERROR mismatched types
//~| expected reference `&fn(u32) -> u32`
//~| found fn item `fn(u32) -> u32 {foo}`
//~| expected reference `&fn(_) -> _`
//~| found fn item `fn(_) -> _ {foo}`

// suggest casting with reference
let e: &fn(u32) -> u32 = &foo;
//~^ ERROR mismatched types
//~| expected reference `&fn(u32) -> u32`
//~| found reference `&fn(u32) -> u32 {foo}`
//~| expected reference `&fn(_) -> _`
//~| found reference `&fn(_) -> _ {foo}`

// OK
let mut z: fn(u32) -> u32 = foo as fn(u32) -> u32;
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/fn/fn-pointer-mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ LL | let g = if n % 2 == 0 { &foo } else { &bar };
| |
| expected because of this
|
= note: expected reference `&fn(u32) -> u32 {foo}`
found reference `&fn(u32) -> u32 {bar}`
= note: expected reference `&fn(_) -> _ {foo}`
found reference `&fn(_) -> _ {bar}`
= note: different fn items have unique types, even if their signatures are the same
= help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`

Expand Down Expand Up @@ -47,8 +47,8 @@ LL | let c: fn(u32) -> u32 = &foo;
| |
| expected due to this
|
= note: expected fn pointer `fn(u32) -> u32`
found reference `&fn(u32) -> u32 {foo}`
= note: expected fn pointer `fn(_) -> _`
found reference `&fn(_) -> _ {foo}`
help: consider removing the reference
|
LL | let c: fn(u32) -> u32 = foo;
Expand All @@ -62,8 +62,8 @@ LL | let d: &fn(u32) -> u32 = foo;
| |
| expected due to this
|
= note: expected reference `&fn(u32) -> u32`
found fn item `fn(u32) -> u32 {foo}`
= note: expected reference `&fn(_) -> _`
found fn item `fn(_) -> _ {foo}`
help: consider using a reference
|
LL | let d: &fn(u32) -> u32 = &foo;
Expand All @@ -77,8 +77,8 @@ LL | let e: &fn(u32) -> u32 = &foo;
| |
| expected due to this
|
= note: expected reference `&fn(u32) -> u32`
found reference `&fn(u32) -> u32 {foo}`
= note: expected reference `&fn(_) -> _`
found reference `&fn(_) -> _ {foo}`
= note: fn items are distinct from fn pointers
help: consider casting to a fn pointer
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/generic-associated-types/issue-88360.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ LL | fn copy(&self) -> Self::Gat<'_> where T: Copy {
LL | *self.test()
| ^^^^^^^^^^^^ expected `&T`, found type parameter `T`
|
= note: expected reference `&T`
found type parameter `T`
= note: expected reference `&_`
found type parameter `_`
Comment on lines +12 to +13
Copy link
Member

Choose a reason for hiding this comment

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

I wish we didn't use _ as a placeholder here, but whatever. This is still pretty helpful.

Copy link
Member Author

@jyn514 jyn514 Dec 8, 2023

Choose a reason for hiding this comment

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

help: consider removing deref here
|
LL - *self.test()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u3
LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
| |_____________________________________________- in this macro invocation
|
= note: expected enum `Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
found enum `Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
= note: expected enum `Option<for<'a, 'b> fn(&'a _, &'b _) -> &'a _>`
found enum `Option<for<'a> fn(&'a _, &'a _) -> &'a _>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
LL | | fn(&'x u32)) }
| |______________- in this macro invocation
|
= note: expected enum `Option<for<'a> fn(&'a u32)>`
found enum `Option<fn(&u32)>`
= note: expected enum `Option<for<'a> fn(&'a _)>`
found enum `Option<fn(&_)>`
= note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ LL | let _: for<'b> fn(&'b u32) = foo();
| |
| expected due to this
|
= note: expected fn pointer `for<'b> fn(&'b u32)`
found fn pointer `fn(&u32)`
= note: expected fn pointer `for<'b> fn(&'b _)`
found fn pointer `fn(&_)`

error: aborting due to 1 previous error

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/in-trait/specialization-broken.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ note: type in trait
|
LL | fn bar(&self) -> impl Sized;
| ^^^^^^^^^^
= note: expected signature `fn(&U) -> impl Sized`
found signature `fn(&U) -> U`
= note: expected signature `fn(&_) -> impl Sized`
found signature `fn(&_) -> U`

error: method with return-position `impl Trait` in trait cannot be specialized
--> $DIR/specialization-broken.rs:15:5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ LL | fn eq(&self, _other: &(Foo, i32)) -> bool {
| expected `a::Bar`, found opaque type
| help: change the parameter type to match the trait: `&(a::Bar, i32)`
|
= note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _`
found signature `fn(&a::Bar, &(a::Foo, i32)) -> _`
= note: expected signature `fn(&a::Bar, &(a::Bar, _)) -> _`
found signature `fn(&a::Bar, &(a::Foo, _)) -> _`

error: unconstrained opaque type
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16
Expand All @@ -41,8 +41,8 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool {
| expected opaque type, found `b::Bar`
| help: change the parameter type to match the trait: `&(b::Foo, i32)`
|
= note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _`
found signature `fn(&b::Bar, &(b::Bar, i32)) -> _`
= note: expected signature `fn(&b::Bar, &(b::Foo, _)) -> _`
found signature `fn(&b::Bar, &(b::Bar, _)) -> _`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:12
|
Expand Down
Loading