Rollup merge of #87348 - SkiFire13:fix-87261, r=oli-obk

Fix span when suggesting to add an associated type bound

Fixes #87261

Note that this fix is not perfect, it ~~will still give incorrect~~ won't give suggestions in some situations:
- If the associated type is defined on a supertrait of those contained in the opaque type, it will fallback to the previous behaviour, e.g. if `AssocTy` is defined on the trait `Foo`, `Bar` has `Foo` as supertrait and the opaque type is a `impl Bar + Baz`.
- If the the associated type is defined on a generic trait and the opaque type includes two versions of that generic trait, e.g. the opaque type is `impl Foo<A> + Foo<B>`
This commit is contained in:
Manish Goregaokar 2021-07-24 09:51:56 -07:00 committed by GitHub
commit e4d8f0e349
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 382 additions and 20 deletions

View File

@ -628,6 +628,7 @@ impl<T> Trait<T> for X {
assoc_substs,
ty,
msg,
false,
) {
return true;
}
@ -646,6 +647,7 @@ impl<T> Trait<T> 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 `<A as T>::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::<Vec<_>>();
let span = match &matching_trait_bounds[..] {
&[ptr] => ptr.span,
&[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
&[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

View File

@ -0,0 +1,99 @@
trait Foo {}
trait Trait {
type Associated;
}
trait DerivedTrait: Trait {}
trait GenericTrait<A> {
type Associated;
}
struct Impl;
impl Foo for Impl {}
impl Trait for Impl {
type Associated = ();
}
impl DerivedTrait for Impl {}
impl<A> GenericTrait<A> 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<u8> {
Impl
}
fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
fn check_generics<A, B, C, D, E, F, G>(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<u8>,
{
accepts_trait(a);
//~^ ERROR type mismatch resolving `<A as Trait>::Associated == ()`
accepts_trait(b);
//~^ ERROR type mismatch resolving `<B as Trait>::Associated == ()`
accepts_trait(c);
//~^ ERROR type mismatch resolving `<C as Trait>::Associated == ()`
accepts_trait(d);
//~^ ERROR type mismatch resolving `<D as Trait>::Associated == ()`
accepts_generic_trait(e);
//~^ ERROR type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(f);
//~^ ERROR type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(g);
//~^ ERROR type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
}
fn main() {
accepts_trait(returns_opaque());
//~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
accepts_trait(returns_opaque_derived());
//~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
accepts_trait(returns_opaque_foo());
//~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
accepts_trait(returns_opaque_derived_foo());
//~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
accepts_generic_trait(returns_opaque_generic());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_foo());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_duplicate());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
}

View File

@ -0,0 +1,238 @@
error[E0271]: type mismatch resolving `<A as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:56:5
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| --------------- required by this bound in `accepts_trait`
...
LL | accepts_trait(a);
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<A as Trait>::Associated`
help: consider constraining the associated type `<A as Trait>::Associated` to `()`
|
LL | A: Trait<Associated = ()> + 'static,
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<B as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:59:5
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| --------------- required by this bound in `accepts_trait`
...
LL | accepts_trait(b);
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<B as Trait>::Associated`
= help: consider constraining the associated type `<B as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `<C as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:62:5
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| --------------- required by this bound in `accepts_trait`
...
LL | accepts_trait(c);
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<C as Trait>::Associated`
help: consider constraining the associated type `<C as Trait>::Associated` to `()`
|
LL | C: Trait<Associated = ()> + Foo,
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<D as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:65:5
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| --------------- required by this bound in `accepts_trait`
...
LL | accepts_trait(d);
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<D as Trait>::Associated`
= help: consider constraining the associated type `<D as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:68:5
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: 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 `<E as GenericTrait<()>>::Associated`
help: consider constraining the associated type `<E as GenericTrait<()>>::Associated` to `()`
|
LL | E: GenericTrait<(), Associated = ()> + 'static,
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:71:5
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: 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 `<F as GenericTrait<()>>::Associated`
help: consider constraining the associated type `<F as GenericTrait<()>>::Associated` to `()`
|
LL | F: GenericTrait<(), Associated = ()> + Foo,
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:74:5
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: 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 `<G as GenericTrait<()>>::Associated`
= help: consider constraining the associated type `<G as GenericTrait<()>>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:79:5
|
LL | fn returns_opaque() -> impl Trait + 'static {
| -------------------- the found opaque type
...
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| --------------- required by this bound in `accepts_trait`
...
LL | accepts_trait(returns_opaque());
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl Trait as Trait>::Associated`
help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
|
LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:82:5
|
LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
| --------------------------- the found opaque type
...
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: 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 `<impl DerivedTrait as Trait>::Associated`
help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
|
LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:85:5
|
LL | fn returns_opaque_foo() -> impl Trait + Foo {
| ---------------- the found opaque type
...
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: 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 `<impl Trait+Foo as Trait>::Associated`
help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
|
LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::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: Trait<Associated = ()>>(_: 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 `<impl DerivedTrait+Foo as Trait>::Associated`
= help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `<impl GenericTrait<()> 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: GenericTrait<(), Associated = ()>>(_: 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 `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
|
LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<impl GenericTrait<()>+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: GenericTrait<(), Associated = ()>>(_: 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 `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
| ^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:97:5
|
LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
| ---------------------------------------- the found opaque type
...
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: 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 `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
= help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> 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`.