Skip to content

Commit e4d8f0e

Browse files
authored
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>`
2 parents 18840b0 + d1bc941 commit e4d8f0e

File tree

3 files changed

+382
-20
lines changed

3 files changed

+382
-20
lines changed

compiler/rustc_middle/src/ty/error.rs

+45-20
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ impl<T> Trait<T> for X {
628628
assoc_substs,
629629
ty,
630630
msg,
631+
false,
631632
) {
632633
return true;
633634
}
@@ -646,6 +647,7 @@ impl<T> Trait<T> for X {
646647
assoc_substs,
647648
ty,
648649
msg,
650+
false,
649651
);
650652
}
651653
}
@@ -771,13 +773,24 @@ fn foo(&self) -> Self::T { String::new() }
771773
) -> bool {
772774
let assoc = self.associated_item(proj_ty.item_def_id);
773775
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
774-
self.constrain_associated_type_structured_suggestion(
776+
let opaque_local_def_id = def_id.expect_local();
777+
let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
778+
let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
779+
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
780+
_ => bug!("The HirId comes from a `ty::Opaque`"),
781+
};
782+
783+
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
784+
785+
self.constrain_generic_bound_associated_type_structured_suggestion(
775786
db,
776-
self.def_span(def_id),
777-
&assoc,
778-
proj_ty.trait_ref_and_own_substs(self).1,
787+
&trait_ref,
788+
opaque_hir_ty.bounds,
789+
assoc,
790+
assoc_substs,
779791
ty,
780-
&msg,
792+
msg,
793+
true,
781794
)
782795
} else {
783796
false
@@ -899,6 +912,11 @@ fn foo(&self) -> Self::T { String::new() }
899912

900913
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
901914
/// requirement, provide a structured suggestion to constrain it to a given type `ty`.
915+
///
916+
/// `is_bound_surely_present` indicates whether we know the bound we're looking for is
917+
/// inside `bounds`. If that's the case then we can consider `bounds` containing only one
918+
/// trait bound as the one we're looking for. This can help in cases where the associated
919+
/// type is defined on a supertrait of the one present in the bounds.
902920
fn constrain_generic_bound_associated_type_structured_suggestion(
903921
self,
904922
db: &mut DiagnosticBuilder<'_>,
@@ -908,23 +926,30 @@ fn foo(&self) -> Self::T { String::new() }
908926
assoc_substs: &[ty::GenericArg<'tcx>],
909927
ty: Ty<'tcx>,
910928
msg: &str,
929+
is_bound_surely_present: bool,
911930
) -> bool {
912931
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
913-
bounds.iter().any(|bound| match bound {
914-
hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
915-
// Relate the type param against `T` in `<A as T>::Foo`.
916-
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
917-
&& self.constrain_associated_type_structured_suggestion(
918-
db,
919-
ptr.span,
920-
assoc,
921-
assoc_substs,
922-
ty,
923-
msg,
924-
)
925-
}
926-
_ => false,
927-
})
932+
933+
let trait_bounds = bounds.iter().filter_map(|bound| match bound {
934+
hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
935+
_ => None,
936+
});
937+
938+
let matching_trait_bounds = trait_bounds
939+
.clone()
940+
.filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
941+
.collect::<Vec<_>>();
942+
943+
let span = match &matching_trait_bounds[..] {
944+
&[ptr] => ptr.span,
945+
&[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
946+
&[ptr] => ptr.span,
947+
_ => return false,
948+
},
949+
_ => return false,
950+
};
951+
952+
self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
928953
}
929954

930955
/// Given a span corresponding to a bound, provide a structured suggestion to set an
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
trait Foo {}
2+
3+
trait Trait {
4+
type Associated;
5+
}
6+
trait DerivedTrait: Trait {}
7+
trait GenericTrait<A> {
8+
type Associated;
9+
}
10+
11+
struct Impl;
12+
impl Foo for Impl {}
13+
impl Trait for Impl {
14+
type Associated = ();
15+
}
16+
impl DerivedTrait for Impl {}
17+
impl<A> GenericTrait<A> for Impl {
18+
type Associated = ();
19+
}
20+
21+
fn returns_opaque() -> impl Trait + 'static {
22+
Impl
23+
}
24+
fn returns_opaque_derived() -> impl DerivedTrait + 'static {
25+
Impl
26+
}
27+
fn returns_opaque_foo() -> impl Trait + Foo {
28+
Impl
29+
}
30+
fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
31+
Impl
32+
}
33+
fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
34+
Impl
35+
}
36+
fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
37+
Impl
38+
}
39+
fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
40+
Impl
41+
}
42+
43+
fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
44+
fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
45+
46+
fn check_generics<A, B, C, D, E, F, G>(a: A, b: B, c: C, d: D, e: E, f: F, g: G)
47+
where
48+
A: Trait + 'static,
49+
B: DerivedTrait + 'static,
50+
C: Trait + Foo,
51+
D: DerivedTrait + Foo,
52+
E: GenericTrait<()> + 'static,
53+
F: GenericTrait<()> + Foo,
54+
G: GenericTrait<()> + GenericTrait<u8>,
55+
{
56+
accepts_trait(a);
57+
//~^ ERROR type mismatch resolving `<A as Trait>::Associated == ()`
58+
59+
accepts_trait(b);
60+
//~^ ERROR type mismatch resolving `<B as Trait>::Associated == ()`
61+
62+
accepts_trait(c);
63+
//~^ ERROR type mismatch resolving `<C as Trait>::Associated == ()`
64+
65+
accepts_trait(d);
66+
//~^ ERROR type mismatch resolving `<D as Trait>::Associated == ()`
67+
68+
accepts_generic_trait(e);
69+
//~^ ERROR type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
70+
71+
accepts_generic_trait(f);
72+
//~^ ERROR type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
73+
74+
accepts_generic_trait(g);
75+
//~^ ERROR type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
76+
}
77+
78+
fn main() {
79+
accepts_trait(returns_opaque());
80+
//~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
81+
82+
accepts_trait(returns_opaque_derived());
83+
//~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
84+
85+
accepts_trait(returns_opaque_foo());
86+
//~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
87+
88+
accepts_trait(returns_opaque_derived_foo());
89+
//~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
90+
91+
accepts_generic_trait(returns_opaque_generic());
92+
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
93+
94+
accepts_generic_trait(returns_opaque_generic_foo());
95+
//~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
96+
97+
accepts_generic_trait(returns_opaque_generic_duplicate());
98+
//~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
99+
}

0 commit comments

Comments
 (0)