diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 96aae3bd70cd2..f1c7c1ea852a2 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -628,6 +628,7 @@ impl Trait for X { assoc_substs, ty, msg, + false, ) { return true; } @@ -646,6 +647,7 @@ impl Trait for X { assoc_substs, ty, msg, + false, ); } } @@ -771,13 +773,24 @@ fn foo(&self) -> Self::T { String::new() } ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { - self.constrain_associated_type_structured_suggestion( + let opaque_local_def_id = def_id.expect_local(); + let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id); + let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind { + hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, + _ => bug!("The HirId comes from a `ty::Opaque`"), + }; + + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); + + self.constrain_generic_bound_associated_type_structured_suggestion( db, - self.def_span(def_id), - &assoc, - proj_ty.trait_ref_and_own_substs(self).1, + &trait_ref, + opaque_hir_ty.bounds, + assoc, + assoc_substs, ty, - &msg, + msg, + true, ) } else { false @@ -899,6 +912,11 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a structured suggestion to constrain it to a given type `ty`. + /// + /// `is_bound_surely_present` indicates whether we know the bound we're looking for is + /// inside `bounds`. If that's the case then we can consider `bounds` containing only one + /// trait bound as the one we're looking for. This can help in cases where the associated + /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( self, db: &mut DiagnosticBuilder<'_>, @@ -908,23 +926,30 @@ fn foo(&self) -> Self::T { String::new() } assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, + is_bound_surely_present: bool, ) -> bool { // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. - bounds.iter().any(|bound| match bound { - hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => { - // Relate the type param against `T` in `::Foo`. - ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id) - && self.constrain_associated_type_structured_suggestion( - db, - ptr.span, - assoc, - assoc_substs, - ty, - msg, - ) - } - _ => false, - }) + + let trait_bounds = bounds.iter().filter_map(|bound| match bound { + hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), + _ => None, + }); + + let matching_trait_bounds = trait_bounds + .clone() + .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)) + .collect::>(); + + let span = match &matching_trait_bounds[..] { + &[ptr] => ptr.span, + &[] if is_bound_surely_present => match &trait_bounds.collect::>()[..] { + &[ptr] => ptr.span, + _ => return false, + }, + _ => return false, + }; + + self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg) } /// Given a span corresponding to a bound, provide a structured suggestion to set an diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs new file mode 100644 index 0000000000000..a70f771e4826f --- /dev/null +++ b/src/test/ui/associated-types/issue-87261.rs @@ -0,0 +1,99 @@ +trait Foo {} + +trait Trait { + type Associated; +} +trait DerivedTrait: Trait {} +trait GenericTrait { + type Associated; +} + +struct Impl; +impl Foo for Impl {} +impl Trait for Impl { + type Associated = (); +} +impl DerivedTrait for Impl {} +impl GenericTrait for Impl { + type Associated = (); +} + +fn returns_opaque() -> impl Trait + 'static { + Impl +} +fn returns_opaque_derived() -> impl DerivedTrait + 'static { + Impl +} +fn returns_opaque_foo() -> impl Trait + Foo { + Impl +} +fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo { + Impl +} +fn returns_opaque_generic() -> impl GenericTrait<()> + 'static { + Impl +} +fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo { + Impl +} +fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait { + Impl +} + +fn accepts_trait>(_: T) {} +fn accepts_generic_trait>(_: T) {} + +fn check_generics(a: A, b: B, c: C, d: D, e: E, f: F, g: G) +where + A: Trait + 'static, + B: DerivedTrait + 'static, + C: Trait + Foo, + D: DerivedTrait + Foo, + E: GenericTrait<()> + 'static, + F: GenericTrait<()> + Foo, + G: GenericTrait<()> + GenericTrait, +{ + accepts_trait(a); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(b); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(c); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(d); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_generic_trait(e); + //~^ ERROR type mismatch resolving `>::Associated == ()` + + accepts_generic_trait(f); + //~^ ERROR type mismatch resolving `>::Associated == ()` + + accepts_generic_trait(g); + //~^ ERROR type mismatch resolving `>::Associated == ()` +} + +fn main() { + accepts_trait(returns_opaque()); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(returns_opaque_derived()); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(returns_opaque_foo()); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_trait(returns_opaque_derived_foo()); + //~^ ERROR type mismatch resolving `::Associated == ()` + + accepts_generic_trait(returns_opaque_generic()); + //~^ ERROR type mismatch resolving ` as GenericTrait<()>>::Associated == ()` + + accepts_generic_trait(returns_opaque_generic_foo()); + //~^ ERROR type mismatch resolving `+Foo as GenericTrait<()>>::Associated == ()` + + accepts_generic_trait(returns_opaque_generic_duplicate()); + //~^ ERROR type mismatch resolving `+GenericTrait as GenericTrait<()>>::Associated == ()` +} diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr new file mode 100644 index 0000000000000..0725acfe537db --- /dev/null +++ b/src/test/ui/associated-types/issue-87261.stderr @@ -0,0 +1,238 @@ +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:56:5 + | +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(a); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` +help: consider constraining the associated type `::Associated` to `()` + | +LL | A: Trait + 'static, + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:59:5 + | +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(b); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` + = help: consider constraining the associated type `::Associated` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:62:5 + | +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(c); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` +help: consider constraining the associated type `::Associated` to `()` + | +LL | C: Trait + Foo, + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:65:5 + | +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(d); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` + = help: consider constraining the associated type `::Associated` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0271]: type mismatch resolving `>::Associated == ()` + --> $DIR/issue-87261.rs:68:5 + | +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(e); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `>::Associated` +help: consider constraining the associated type `>::Associated` to `()` + | +LL | E: GenericTrait<(), Associated = ()> + 'static, + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `>::Associated == ()` + --> $DIR/issue-87261.rs:71:5 + | +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(f); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `>::Associated` +help: consider constraining the associated type `>::Associated` to `()` + | +LL | F: GenericTrait<(), Associated = ()> + Foo, + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `>::Associated == ()` + --> $DIR/issue-87261.rs:74:5 + | +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(g); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `>::Associated` + = help: consider constraining the associated type `>::Associated` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:79:5 + | +LL | fn returns_opaque() -> impl Trait + 'static { + | -------------------- the found opaque type +... +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(returns_opaque()); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` +help: consider constraining the associated type `::Associated` to `()` + | +LL | fn returns_opaque() -> impl Trait + 'static { + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:82:5 + | +LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static { + | --------------------------- the found opaque type +... +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(returns_opaque_derived()); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` +help: consider constraining the associated type `::Associated` to `()` + | +LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static { + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:85:5 + | +LL | fn returns_opaque_foo() -> impl Trait + Foo { + | ---------------- the found opaque type +... +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(returns_opaque_foo()); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` +help: consider constraining the associated type `::Associated` to `()` + | +LL | fn returns_opaque_foo() -> impl Trait + Foo { + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `::Associated == ()` + --> $DIR/issue-87261.rs:88:5 + | +LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo { + | ----------------------- the found opaque type +... +LL | fn accepts_trait>(_: T) {} + | --------------- required by this bound in `accepts_trait` +... +LL | accepts_trait(returns_opaque_derived_foo()); + | ^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Associated` + = help: consider constraining the associated type `::Associated` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0271]: type mismatch resolving ` as GenericTrait<()>>::Associated == ()` + --> $DIR/issue-87261.rs:91:5 + | +LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static { + | ------------------------------- the found opaque type +... +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(returns_opaque_generic()); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type ` as GenericTrait<()>>::Associated` +help: consider constraining the associated type ` as GenericTrait<()>>::Associated` to `()` + | +LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static { + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `+Foo as GenericTrait<()>>::Associated == ()` + --> $DIR/issue-87261.rs:94:5 + | +LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo { + | --------------------------- the found opaque type +... +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(returns_opaque_generic_foo()); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `+Foo as GenericTrait<()>>::Associated` +help: consider constraining the associated type `+Foo as GenericTrait<()>>::Associated` to `()` + | +LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo { + | ^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `+GenericTrait as GenericTrait<()>>::Associated == ()` + --> $DIR/issue-87261.rs:97:5 + | +LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait { + | ---------------------------------------- the found opaque type +... +LL | fn accepts_generic_trait>(_: T) {} + | --------------- required by this bound in `accepts_generic_trait` +... +LL | accepts_generic_trait(returns_opaque_generic_duplicate()); + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `+GenericTrait as GenericTrait<()>>::Associated` + = help: consider constraining the associated type `+GenericTrait as GenericTrait<()>>::Associated` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0271`.