Skip to content

Commit 0b0563c

Browse files
committed
Handle projection obligation errors
1 parent 718626d commit 0b0563c

5 files changed

+98
-10
lines changed

src/librustc/ty/wf.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -164,37 +164,60 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
164164

165165
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
166166
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
167+
let tcx = self.infcx.tcx;
167168
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
168-
let assoc_items = self.infcx.tcx.associated_items(trait_ref.def_id);
169+
169170
let cause = self.cause(traits::MiscObligation);
170171
let param_env = self.param_env;
171172

172173
if let Elaborate::All = elaborate {
174+
let trait_assoc_items = tcx.associated_items(trait_ref.def_id);
175+
173176
let predicates = obligations.iter()
174177
.map(|obligation| obligation.predicate.clone())
175178
.collect();
176-
let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates);
179+
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
177180
let item_span: Option<Span> = self.item.map(|i| i.span);
178181
let item = &self.item;
179182
let implied_obligations = implied_obligations.map(|pred| {
180183
let mut cause = cause.clone();
181-
if let ty::Predicate::Trait(proj) = &pred {
184+
match &pred {
185+
ty::Predicate::Projection(proj) => {
186+
if let Some(hir::ItemKind::Impl(.., impl_items)) = item.map(|i| &i.kind) {
187+
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
188+
if let Some(impl_item) = impl_items.iter().filter(|item| {
189+
item.ident == trait_assoc_item.ident
190+
}).next() {
191+
cause.span = impl_item.span;
192+
cause.code = traits::AssocTypeBound(
193+
item_span,
194+
trait_assoc_item.ident.span,
195+
);
196+
}
197+
}
198+
}
199+
ty::Predicate::Trait(proj) => {
182200
if let (
183201
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
184-
Some(hir::ItemKind::Impl(.., bounds)),
202+
Some(hir::ItemKind::Impl(.., impl_items)),
185203
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) {
186-
if let Some((bound, assoc_item)) = assoc_items.clone()
204+
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items.clone()
187205
.filter(|i| i.def_id == *item_def_id)
188206
.next()
189-
.and_then(|assoc_item| bounds.iter()
190-
.filter(|b| b.ident == assoc_item.ident)
207+
.and_then(|trait_assoc_item| impl_items.iter()
208+
.filter(|i| i.ident == trait_assoc_item.ident)
191209
.next()
192-
.map(|bound| (bound, assoc_item)))
210+
.map(|impl_item| (impl_item, trait_assoc_item)))
193211
{
194-
cause.span = bound.span;
195-
cause.code = traits::AssocTypeBound(item_span, assoc_item.ident.span);
212+
cause.span = impl_item.span;
213+
cause.code = traits::AssocTypeBound(
214+
item_span,
215+
trait_assoc_item.ident.span,
216+
);
217+
}
196218
}
197219
}
220+
_ => {}
198221
}
199222
traits::Obligation::new(cause, param_env, pred)
200223
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait Bar {}
2+
3+
trait Foo {
4+
type Assoc: Bar;
5+
}
6+
7+
impl Foo for () {
8+
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `bool: Bar` is not satisfied
2+
--> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
3+
|
4+
LL | type Assoc: Bar;
5+
| ----- associated type defined here
6+
...
7+
LL | / impl Foo for () {
8+
LL | | type Assoc = bool;
9+
| | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
10+
LL | | }
11+
| |_- in this `impl` item
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
trait Bar {
2+
type Ok;
3+
type Sibling: Bar2<Ok=Self::Ok>;
4+
}
5+
trait Bar2 {
6+
type Ok;
7+
}
8+
9+
struct Foo;
10+
struct Foo2;
11+
12+
impl Bar for Foo {
13+
type Ok = (); //~ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
14+
type Sibling = Foo2;
15+
}
16+
impl Bar2 for Foo2 {
17+
type Ok = u32;
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
2+
--> $DIR/point-at-type-on-obligation-failure.rs:13:5
3+
|
4+
LL | type Ok;
5+
| -- associated type defined here
6+
...
7+
LL | / impl Bar for Foo {
8+
LL | | type Ok = ();
9+
| | ^^^^^^^^^^^^^ expected u32, found ()
10+
LL | | type Sibling = Foo2;
11+
LL | | }
12+
| |_- in this `impl` item
13+
|
14+
= note: expected type `u32`
15+
found type `()`
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)