Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e4d8f0e

Browse files
authoredJul 24, 2021
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

Lines changed: 45 additions & 20 deletions
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
Lines changed: 99 additions & 0 deletions
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+
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
error[E0271]: type mismatch resolving `<A as Trait>::Associated == ()`
2+
--> $DIR/issue-87261.rs:56:5
3+
|
4+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
5+
| --------------- required by this bound in `accepts_trait`
6+
...
7+
LL | accepts_trait(a);
8+
| ^^^^^^^^^^^^^ expected `()`, found associated type
9+
|
10+
= note: expected unit type `()`
11+
found associated type `<A as Trait>::Associated`
12+
help: consider constraining the associated type `<A as Trait>::Associated` to `()`
13+
|
14+
LL | A: Trait<Associated = ()> + 'static,
15+
| ^^^^^^^^^^^^^^^^^
16+
17+
error[E0271]: type mismatch resolving `<B as Trait>::Associated == ()`
18+
--> $DIR/issue-87261.rs:59:5
19+
|
20+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
21+
| --------------- required by this bound in `accepts_trait`
22+
...
23+
LL | accepts_trait(b);
24+
| ^^^^^^^^^^^^^ expected `()`, found associated type
25+
|
26+
= note: expected unit type `()`
27+
found associated type `<B as Trait>::Associated`
28+
= help: consider constraining the associated type `<B as Trait>::Associated` to `()`
29+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
30+
31+
error[E0271]: type mismatch resolving `<C as Trait>::Associated == ()`
32+
--> $DIR/issue-87261.rs:62:5
33+
|
34+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
35+
| --------------- required by this bound in `accepts_trait`
36+
...
37+
LL | accepts_trait(c);
38+
| ^^^^^^^^^^^^^ expected `()`, found associated type
39+
|
40+
= note: expected unit type `()`
41+
found associated type `<C as Trait>::Associated`
42+
help: consider constraining the associated type `<C as Trait>::Associated` to `()`
43+
|
44+
LL | C: Trait<Associated = ()> + Foo,
45+
| ^^^^^^^^^^^^^^^^^
46+
47+
error[E0271]: type mismatch resolving `<D as Trait>::Associated == ()`
48+
--> $DIR/issue-87261.rs:65:5
49+
|
50+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
51+
| --------------- required by this bound in `accepts_trait`
52+
...
53+
LL | accepts_trait(d);
54+
| ^^^^^^^^^^^^^ expected `()`, found associated type
55+
|
56+
= note: expected unit type `()`
57+
found associated type `<D as Trait>::Associated`
58+
= help: consider constraining the associated type `<D as Trait>::Associated` to `()`
59+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
60+
61+
error[E0271]: type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
62+
--> $DIR/issue-87261.rs:68:5
63+
|
64+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
65+
| --------------- required by this bound in `accepts_generic_trait`
66+
...
67+
LL | accepts_generic_trait(e);
68+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
69+
|
70+
= note: expected unit type `()`
71+
found associated type `<E as GenericTrait<()>>::Associated`
72+
help: consider constraining the associated type `<E as GenericTrait<()>>::Associated` to `()`
73+
|
74+
LL | E: GenericTrait<(), Associated = ()> + 'static,
75+
| ^^^^^^^^^^^^^^^^^
76+
77+
error[E0271]: type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
78+
--> $DIR/issue-87261.rs:71:5
79+
|
80+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
81+
| --------------- required by this bound in `accepts_generic_trait`
82+
...
83+
LL | accepts_generic_trait(f);
84+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
85+
|
86+
= note: expected unit type `()`
87+
found associated type `<F as GenericTrait<()>>::Associated`
88+
help: consider constraining the associated type `<F as GenericTrait<()>>::Associated` to `()`
89+
|
90+
LL | F: GenericTrait<(), Associated = ()> + Foo,
91+
| ^^^^^^^^^^^^^^^^^
92+
93+
error[E0271]: type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
94+
--> $DIR/issue-87261.rs:74:5
95+
|
96+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
97+
| --------------- required by this bound in `accepts_generic_trait`
98+
...
99+
LL | accepts_generic_trait(g);
100+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
101+
|
102+
= note: expected unit type `()`
103+
found associated type `<G as GenericTrait<()>>::Associated`
104+
= help: consider constraining the associated type `<G as GenericTrait<()>>::Associated` to `()`
105+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
106+
107+
error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
108+
--> $DIR/issue-87261.rs:79:5
109+
|
110+
LL | fn returns_opaque() -> impl Trait + 'static {
111+
| -------------------- the found opaque type
112+
...
113+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
114+
| --------------- required by this bound in `accepts_trait`
115+
...
116+
LL | accepts_trait(returns_opaque());
117+
| ^^^^^^^^^^^^^ expected `()`, found associated type
118+
|
119+
= note: expected unit type `()`
120+
found associated type `<impl Trait as Trait>::Associated`
121+
help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
122+
|
123+
LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
124+
| ^^^^^^^^^^^^^^^^^
125+
126+
error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
127+
--> $DIR/issue-87261.rs:82:5
128+
|
129+
LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
130+
| --------------------------- the found opaque type
131+
...
132+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
133+
| --------------- required by this bound in `accepts_trait`
134+
...
135+
LL | accepts_trait(returns_opaque_derived());
136+
| ^^^^^^^^^^^^^ expected `()`, found associated type
137+
|
138+
= note: expected unit type `()`
139+
found associated type `<impl DerivedTrait as Trait>::Associated`
140+
help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
141+
|
142+
LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
143+
| ^^^^^^^^^^^^^^^^^
144+
145+
error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
146+
--> $DIR/issue-87261.rs:85:5
147+
|
148+
LL | fn returns_opaque_foo() -> impl Trait + Foo {
149+
| ---------------- the found opaque type
150+
...
151+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
152+
| --------------- required by this bound in `accepts_trait`
153+
...
154+
LL | accepts_trait(returns_opaque_foo());
155+
| ^^^^^^^^^^^^^ expected `()`, found associated type
156+
|
157+
= note: expected unit type `()`
158+
found associated type `<impl Trait+Foo as Trait>::Associated`
159+
help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
160+
|
161+
LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
162+
| ^^^^^^^^^^^^^^^^^
163+
164+
error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
165+
--> $DIR/issue-87261.rs:88:5
166+
|
167+
LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
168+
| ----------------------- the found opaque type
169+
...
170+
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
171+
| --------------- required by this bound in `accepts_trait`
172+
...
173+
LL | accepts_trait(returns_opaque_derived_foo());
174+
| ^^^^^^^^^^^^^ expected `()`, found associated type
175+
|
176+
= note: expected unit type `()`
177+
found associated type `<impl DerivedTrait+Foo as Trait>::Associated`
178+
= help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
179+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
180+
181+
error[E0271]: type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
182+
--> $DIR/issue-87261.rs:91:5
183+
|
184+
LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
185+
| ------------------------------- the found opaque type
186+
...
187+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
188+
| --------------- required by this bound in `accepts_generic_trait`
189+
...
190+
LL | accepts_generic_trait(returns_opaque_generic());
191+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
192+
|
193+
= note: expected unit type `()`
194+
found associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
195+
help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
196+
|
197+
LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
198+
| ^^^^^^^^^^^^^^^^^
199+
200+
error[E0271]: type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
201+
--> $DIR/issue-87261.rs:94:5
202+
|
203+
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
204+
| --------------------------- the found opaque type
205+
...
206+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
207+
| --------------- required by this bound in `accepts_generic_trait`
208+
...
209+
LL | accepts_generic_trait(returns_opaque_generic_foo());
210+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
211+
|
212+
= note: expected unit type `()`
213+
found associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
214+
help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
215+
|
216+
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
217+
| ^^^^^^^^^^^^^^^^^
218+
219+
error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
220+
--> $DIR/issue-87261.rs:97:5
221+
|
222+
LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
223+
| ---------------------------------------- the found opaque type
224+
...
225+
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
226+
| --------------- required by this bound in `accepts_generic_trait`
227+
...
228+
LL | accepts_generic_trait(returns_opaque_generic_duplicate());
229+
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
230+
|
231+
= note: expected unit type `()`
232+
found associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
233+
= help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
234+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
235+
236+
error: aborting due to 14 previous errors
237+
238+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)
Please sign in to comment.