Skip to content

On type mismatch involving associated type, suggest constraint #71108

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 11 commits into from
May 4, 2020
5 changes: 3 additions & 2 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
terr: &TypeError<'tcx>,
) {
let span = cause.span(self.tcx);
debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);

// For some types of errors, expected-found does not make
// sense, so just ignore the values we were given.
Expand Down Expand Up @@ -1599,11 +1600,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id })
});
self.check_and_note_conflicting_crates(diag, terr);
self.tcx.note_and_explain_type_err(diag, terr, span, body_owner_def_id.to_def_id());
self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());

// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, &cause, exp_found);
self.note_error_origin(diag, cause, exp_found);
}

/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ pub enum ObligationCauseCode<'tcx> {

DerivedObligation(DerivedObligationCause<'tcx>),

/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplConstObligation,

/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplMethodObligation {
item_name: ast::Name,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_middle/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
tcx.lift(cause).map(super::ImplDerivedObligation)
}
super::DerivedObligation(ref cause) => tcx.lift(cause).map(super::DerivedObligation),
super::CompareImplConstObligation => Some(super::CompareImplConstObligation),
super::CompareImplMethodObligation {
item_name,
impl_item_def_id,
Expand Down
414 changes: 377 additions & 37 deletions src/librustc_middle/ty/error.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
predicate
));
}
ObligationCauseCode::CompareImplConstObligation => {
err.note(&format!(
"the requirement `{}` appears on the associated impl constant \
but not on the corresponding associated trait constant",
predicate
));
}
ObligationCauseCode::ReturnType
| ObligationCauseCode::ReturnValue(_)
| ObligationCauseCode::BlockTailExpression(_) => (),
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ crate fn compare_const_impl<'tcx>(
let impl_ty = tcx.type_of(impl_c.def_id);
let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id);
cause.code = ObligationCauseCode::CompareImplConstObligation;

// There is no "body" here, so just pass dummy id.
let impl_ty =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ LL | const FROM: &'static str = "foo";
|
= note: expected associated type `<T as Foo>::Out`
found reference `&'static str`
= note: consider constraining the associated type `<T as Foo>::Out` to `&'static str` or calling a method that returns `<T as Foo>::Out`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error: aborting due to previous error

Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/associated-types/associated-types-eq-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ LL | let _: Bar = x.boo();
|
= note: expected struct `Bar`
found associated type `<I as Foo>::A`
= note: consider constraining the associated type `<I as Foo>::A` to `Bar`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<I as Foo>::A` to `Bar`
|
LL | fn foo2<I: Foo<A = Bar>>(x: I) {
| ^^^^^^^^^

error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar`
--> $DIR/associated-types-eq-3.rs:38:5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ LL | is_iterator_of::<Option<T>, _>(&adapter);
|
= note: expected enum `std::option::Option<T>`
found type `T`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ LL | fn want_y<T:Foo<Y=i32>>(t: &T) { }
|
= note: expected type `i32`
found associated type `<T as Foo>::Y`
= note: consider constraining the associated type `<T as Foo>::Y` to `i32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<T as Foo>::Y` to `i32`
|
LL | fn have_x_want_y<T:Foo<X=u32, Y = i32>>(t: &T)
| ^^^^^^^^^

error[E0271]: type mismatch resolving `<T as Foo>::X == u32`
--> $DIR/associated-types-multiple-types-one-trait.rs:18:5
Expand All @@ -23,8 +25,10 @@ LL | fn want_x<T:Foo<X=u32>>(t: &T) { }
|
= note: expected type `u32`
found associated type `<T as Foo>::X`
= note: consider constraining the associated type `<T as Foo>::X` to `u32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<T as Foo>::X` to `u32`
|
LL | fn have_y_want_x<T:Foo<Y=i32, X = u32>>(t: &T)
| ^^^^^^^^^

error: aborting due to 2 previous errors

Expand Down
8 changes: 2 additions & 6 deletions src/test/ui/associated-types/defaults-in-other-trait-items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
// Associated type defaults may not be assumed inside the trait defining them.
// ie. they only resolve to `<Self as Tr>::A`, not the actual type `()`
trait Tr {
type A = ();
type A = (); //~ NOTE associated type defaults can't be assumed inside the trait defining them

fn f(p: Self::A) {
let () = p;
//~^ ERROR mismatched types
//~| NOTE expected associated type, found `()`
//~| NOTE expected associated type `<Self as Tr>::A`
//~| NOTE consider constraining the associated type
//~| NOTE for more information, visit
}
}

Expand All @@ -31,15 +29,13 @@ impl Tr for u8 {
}

trait AssocConst {
type Ty = u8;
type Ty = u8; //~ NOTE associated type defaults can't be assumed inside the trait defining them

// Assoc. consts also cannot assume that default types hold
const C: Self::Ty = 0u8;
//~^ ERROR mismatched types
//~| NOTE expected associated type, found `u8`
//~| NOTE expected associated type `<Self as AssocConst>::Ty`
//~| NOTE consider constraining the associated type
//~| NOTE for more information, visit
}

// An impl can, however
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
error[E0308]: mismatched types
--> $DIR/defaults-in-other-trait-items.rs:9:13
|
LL | type A = ();
| ------------ associated type defaults can't be assumed inside the trait defining them
...
LL | let () = p;
| ^^ expected associated type, found `()`
|
= note: expected associated type `<Self as Tr>::A`
found unit type `()`
= note: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-in-other-trait-items.rs:37:25
--> $DIR/defaults-in-other-trait-items.rs:35:25
|
LL | type Ty = u8;
| ------------- associated type defaults can't be assumed inside the trait defining them
...
LL | const C: Self::Ty = 0u8;
| ^^^ expected associated type, found `u8`
|
= note: expected associated type `<Self as AssocConst>::Ty`
found type `u8`
= note: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` or calling a method that returns `<Self as AssocConst>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error: aborting due to 2 previous errors

Expand Down
47 changes: 30 additions & 17 deletions src/test/ui/associated-types/defaults-specialization.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@ LL | fn make() -> u8 { 0 }
|
= note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
found fn pointer `fn() -> u8`
= note: consider constraining the associated type `<A<T> as Tr>::Ty` to `u8` or calling a method that returns `<A<T> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:34:18
|
LL | fn make() -> Self::Ty {
| -------- type in trait
...
LL | default type Ty = bool;
| ----------------------- expected this associated type
LL |
LL | fn make() -> bool { true }
| ^^^^ expected associated type, found `bool`
|
= note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
found fn pointer `fn() -> bool`
= note: consider constraining the associated type `<B<T> as Tr>::Ty` to `bool` or calling a method that returns `<B<T> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:9:9
|
LL | type Ty = u8;
| ------------- associated type defaults can't be assumed inside the trait defining them
LL |
LL | fn make() -> Self::Ty {
| -------- expected `<Self as Tr>::Ty` because of return type
LL | 0u8
| ^^^ expected associated type, found `u8`
|
= note: expected associated type `<Self as Tr>::Ty`
found type `u8`
= note: consider constraining the associated type `<Self as Tr>::Ty` to `u8` or calling a method that returns `<Self as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:25:29
Expand All @@ -49,21 +49,22 @@ LL | fn make() -> Self::Ty { 0u8 }
|
= note: expected associated type `<A2<T> as Tr>::Ty`
found type `u8`
= note: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty`
= help: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:43:29
|
LL | default type Ty = bool;
| ----------------------- expected this associated type
LL |
LL | fn make() -> Self::Ty { true }
| -------- ^^^^ expected associated type, found `bool`
| |
| expected `<B2<T> as Tr>::Ty` because of return type
|
= note: expected associated type `<B2<T> as Tr>::Ty`
found type `bool`
= note: consider constraining the associated type `<B2<T> as Tr>::Ty` to `bool` or calling a method that returns `<B2<T> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:86:32
Expand All @@ -75,8 +76,11 @@ LL | let _: <B<()> as Tr>::Ty = 0u8;
|
= note: expected associated type `<B<()> as Tr>::Ty`
found type `u8`
= note: consider constraining the associated type `<B<()> as Tr>::Ty` to `u8` or calling a method that returns `<B<()> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: a method is available that returns `<B<()> as Tr>::Ty`
--> $DIR/defaults-specialization.rs:8:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:87:32
Expand All @@ -88,8 +92,11 @@ LL | let _: <B<()> as Tr>::Ty = true;
|
= note: expected associated type `<B<()> as Tr>::Ty`
found type `bool`
= note: consider constraining the associated type `<B<()> as Tr>::Ty` to `bool` or calling a method that returns `<B<()> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: a method is available that returns `<B<()> as Tr>::Ty`
--> $DIR/defaults-specialization.rs:8:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:88:33
Expand All @@ -101,8 +108,11 @@ LL | let _: <B2<()> as Tr>::Ty = 0u8;
|
= note: expected associated type `<B2<()> as Tr>::Ty`
found type `u8`
= note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `u8` or calling a method that returns `<B2<()> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: a method is available that returns `<B2<()> as Tr>::Ty`
--> $DIR/defaults-specialization.rs:8:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`

error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:89:33
Expand All @@ -114,8 +124,11 @@ LL | let _: <B2<()> as Tr>::Ty = true;
|
= note: expected associated type `<B2<()> as Tr>::Ty`
found type `bool`
= note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `bool` or calling a method that returns `<B2<()> as Tr>::Ty`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: a method is available that returns `<B2<()> as Tr>::Ty`
--> $DIR/defaults-specialization.rs:8:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`

error: aborting due to 9 previous errors

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
trait Foo {
type Item;
}

trait Bar: Foo {}

struct S;

impl Foo for S {
type Item = i32;
}
impl Bar for S {}

struct T;

impl Foo for T {
type Item = u32;
}
impl Bar for T {}

fn bar() -> impl Bar {
T
}

fn baz() -> impl Bar<Item = i32> {
//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
bar()
}

fn main() {
let _ = baz();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
|
LL | fn bar() -> impl Bar {
| -------- the expected opaque type
...
LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
|
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
= note: the return type of a function must have a statically known size
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
LL | fn bar() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0271`.
2 changes: 1 addition & 1 deletion src/test/ui/associated-types/issue-26681.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LL | const C: <Self::Fv as Foo>::Bar = 6665;
|
= note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
found type `{integer}`
= note: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}` or calling a method that returns `<<Self as Baz>::Fv as Foo>::Bar`
= help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error: aborting due to previous error
Expand Down
Loading