Skip to content

Commit e3346e5

Browse files
authored
Rollup merge of rust-lang#70892 - lcnr:interators_are_nice, r=nikomatsakis
wf: refactor `compute_trait_ref` moves `extend_cause_with_original_assoc_item_obligation` out of `compute_trait_ref` and changes `trait_assoc_items` to an iterator. This saves us from building an unnecessary `Vec<_>` r? @eddyb i guess
2 parents 6696666 + ab4178b commit e3346e5

File tree

1 file changed

+151
-155
lines changed
  • src/librustc_trait_selection/traits

1 file changed

+151
-155
lines changed

src/librustc_trait_selection/traits/wf.rs

+151-155
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,152 @@ enum Elaborate {
134134
None,
135135
}
136136

137+
fn extend_cause_with_original_assoc_item_obligation<'tcx>(
138+
tcx: TyCtxt<'tcx>,
139+
trait_ref: &ty::TraitRef<'tcx>,
140+
item: Option<&hir::Item<'tcx>>,
141+
cause: &mut traits::ObligationCause<'tcx>,
142+
pred: &ty::Predicate<'_>,
143+
mut trait_assoc_items: impl Iterator<Item = ty::AssocItem>,
144+
) {
145+
let trait_item =
146+
tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| tcx.hir().find(trait_id));
147+
let (trait_name, trait_generics) = match trait_item {
148+
Some(hir::Node::Item(hir::Item {
149+
ident,
150+
kind: hir::ItemKind::Trait(.., generics, _, _),
151+
..
152+
}))
153+
| Some(hir::Node::Item(hir::Item {
154+
ident,
155+
kind: hir::ItemKind::TraitAlias(generics, _),
156+
..
157+
})) => (Some(ident), Some(generics)),
158+
_ => (None, None),
159+
};
160+
161+
let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
162+
match pred {
163+
ty::Predicate::Projection(proj) => {
164+
// The obligation comes not from the current `impl` nor the `trait` being
165+
// implemented, but rather from a "second order" obligation, like in
166+
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
167+
//
168+
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
169+
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
170+
// |
171+
// LL | type Ok;
172+
// | -- associated type defined here
173+
// ...
174+
// LL | impl Bar for Foo {
175+
// | ---------------- in this `impl` item
176+
// LL | type Ok = ();
177+
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
178+
// |
179+
// = note: expected type `u32`
180+
// found type `()`
181+
//
182+
// FIXME: we would want to point a span to all places that contributed to this
183+
// obligation. In the case above, it should be closer to:
184+
//
185+
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
186+
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
187+
// |
188+
// LL | type Ok;
189+
// | -- associated type defined here
190+
// LL | type Sibling: Bar2<Ok=Self::Ok>;
191+
// | -------------------------------- obligation set here
192+
// ...
193+
// LL | impl Bar for Foo {
194+
// | ---------------- in this `impl` item
195+
// LL | type Ok = ();
196+
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
197+
// ...
198+
// LL | impl Bar2 for Foo2 {
199+
// | ---------------- in this `impl` item
200+
// LL | type Ok = u32;
201+
// | -------------- obligation set here
202+
// |
203+
// = note: expected type `u32`
204+
// found type `()`
205+
if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
206+
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
207+
if let Some(impl_item) =
208+
items.iter().find(|item| item.ident == trait_assoc_item.ident)
209+
{
210+
cause.span = impl_item.span;
211+
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
212+
impl_span: item_span,
213+
original: trait_assoc_item.ident.span,
214+
bounds: vec![],
215+
}));
216+
}
217+
}
218+
}
219+
ty::Predicate::Trait(proj, _) => {
220+
// An associated item obligation born out of the `trait` failed to be met.
221+
// Point at the `impl` that failed the obligation, the associated item that
222+
// needed to meet the obligation, and the definition of that associated item,
223+
// which should hold the obligation in most cases. An example can be seen in
224+
// `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
225+
//
226+
// error[E0277]: the trait bound `bool: Bar` is not satisfied
227+
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
228+
// |
229+
// LL | type Assoc: Bar;
230+
// | ----- associated type defined here
231+
// ...
232+
// LL | impl Foo for () {
233+
// | --------------- in this `impl` item
234+
// LL | type Assoc = bool;
235+
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
236+
//
237+
// If the obligation comes from the where clause in the `trait`, we point at it:
238+
//
239+
// error[E0277]: the trait bound `bool: Bar` is not satisfied
240+
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
241+
// |
242+
// | trait Foo where <Self as Foo>>::Assoc: Bar {
243+
// | -------------------------- restricted in this bound
244+
// LL | type Assoc;
245+
// | ----- associated type defined here
246+
// ...
247+
// LL | impl Foo for () {
248+
// | --------------- in this `impl` item
249+
// LL | type Assoc = bool;
250+
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
251+
if let (
252+
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
253+
Some(hir::ItemKind::Impl { items, .. }),
254+
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
255+
{
256+
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
257+
.find(|i| i.def_id == *item_def_id)
258+
.and_then(|trait_assoc_item| {
259+
items
260+
.iter()
261+
.find(|i| i.ident == trait_assoc_item.ident)
262+
.map(|impl_item| (impl_item, trait_assoc_item))
263+
})
264+
{
265+
let bounds = trait_generics
266+
.map(|generics| {
267+
get_generic_bound_spans(&generics, trait_name, trait_assoc_item.ident)
268+
})
269+
.unwrap_or_else(Vec::new);
270+
cause.span = impl_item.span;
271+
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
272+
impl_span: item_span,
273+
original: trait_assoc_item.ident.span,
274+
bounds,
275+
}));
276+
}
277+
}
278+
}
279+
_ => {}
280+
}
281+
}
282+
137283
impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
138284
fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
139285
traits::ObligationCause::new(self.span, self.body_id, code)
@@ -163,170 +309,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
163309
let cause = self.cause(traits::MiscObligation);
164310
let param_env = self.param_env;
165311

166-
let item = &self.item;
167-
let extend_cause_with_original_assoc_item_obligation =
168-
|cause: &mut traits::ObligationCause<'_>,
169-
pred: &ty::Predicate<'_>,
170-
trait_assoc_items: &[ty::AssocItem]| {
171-
let trait_item = tcx
172-
.hir()
173-
.as_local_hir_id(trait_ref.def_id)
174-
.and_then(|trait_id| tcx.hir().find(trait_id));
175-
let (trait_name, trait_generics) = match trait_item {
176-
Some(hir::Node::Item(hir::Item {
177-
ident,
178-
kind: hir::ItemKind::Trait(.., generics, _, _),
179-
..
180-
}))
181-
| Some(hir::Node::Item(hir::Item {
182-
ident,
183-
kind: hir::ItemKind::TraitAlias(generics, _),
184-
..
185-
})) => (Some(ident), Some(generics)),
186-
_ => (None, None),
187-
};
188-
189-
let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
190-
match pred {
191-
ty::Predicate::Projection(proj) => {
192-
// The obligation comes not from the current `impl` nor the `trait` being
193-
// implemented, but rather from a "second order" obligation, like in
194-
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
195-
//
196-
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
197-
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
198-
// |
199-
// LL | type Ok;
200-
// | -- associated type defined here
201-
// ...
202-
// LL | impl Bar for Foo {
203-
// | ---------------- in this `impl` item
204-
// LL | type Ok = ();
205-
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
206-
// |
207-
// = note: expected type `u32`
208-
// found type `()`
209-
//
210-
// FIXME: we would want to point a span to all places that contributed to this
211-
// obligation. In the case above, it should be closer to:
212-
//
213-
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
214-
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
215-
// |
216-
// LL | type Ok;
217-
// | -- associated type defined here
218-
// LL | type Sibling: Bar2<Ok=Self::Ok>;
219-
// | -------------------------------- obligation set here
220-
// ...
221-
// LL | impl Bar for Foo {
222-
// | ---------------- in this `impl` item
223-
// LL | type Ok = ();
224-
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
225-
// ...
226-
// LL | impl Bar2 for Foo2 {
227-
// | ---------------- in this `impl` item
228-
// LL | type Ok = u32;
229-
// | -------------- obligation set here
230-
// |
231-
// = note: expected type `u32`
232-
// found type `()`
233-
if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
234-
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
235-
if let Some(impl_item) =
236-
items.iter().find(|item| item.ident == trait_assoc_item.ident)
237-
{
238-
cause.span = impl_item.span;
239-
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
240-
impl_span: item_span,
241-
original: trait_assoc_item.ident.span,
242-
bounds: vec![],
243-
}));
244-
}
245-
}
246-
}
247-
ty::Predicate::Trait(proj, _) => {
248-
// An associated item obligation born out of the `trait` failed to be met.
249-
// Point at the `impl` that failed the obligation, the associated item that
250-
// needed to meet the obligation, and the definition of that associated item,
251-
// which should hold the obligation in most cases. An example can be seen in
252-
// `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
253-
//
254-
// error[E0277]: the trait bound `bool: Bar` is not satisfied
255-
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
256-
// |
257-
// LL | type Assoc: Bar;
258-
// | ----- associated type defined here
259-
// ...
260-
// LL | impl Foo for () {
261-
// | --------------- in this `impl` item
262-
// LL | type Assoc = bool;
263-
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
264-
//
265-
// If the obligation comes from the where clause in the `trait`, we point at it:
266-
//
267-
// error[E0277]: the trait bound `bool: Bar` is not satisfied
268-
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
269-
// |
270-
// | trait Foo where <Self as Foo>>::Assoc: Bar {
271-
// | -------------------------- restricted in this bound
272-
// LL | type Assoc;
273-
// | ----- associated type defined here
274-
// ...
275-
// LL | impl Foo for () {
276-
// | --------------- in this `impl` item
277-
// LL | type Assoc = bool;
278-
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
279-
if let (
280-
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
281-
Some(hir::ItemKind::Impl { items, .. }),
282-
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
283-
{
284-
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
285-
.iter()
286-
.find(|i| i.def_id == *item_def_id)
287-
.and_then(|trait_assoc_item| {
288-
items
289-
.iter()
290-
.find(|i| i.ident == trait_assoc_item.ident)
291-
.map(|impl_item| (impl_item, trait_assoc_item))
292-
})
293-
{
294-
let bounds = trait_generics
295-
.map(|generics| {
296-
get_generic_bound_spans(
297-
&generics,
298-
trait_name,
299-
trait_assoc_item.ident,
300-
)
301-
})
302-
.unwrap_or_else(Vec::new);
303-
cause.span = impl_item.span;
304-
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
305-
impl_span: item_span,
306-
original: trait_assoc_item.ident.span,
307-
bounds,
308-
}));
309-
}
310-
}
311-
}
312-
_ => {}
313-
}
314-
};
312+
let item = self.item;
315313

316314
if let Elaborate::All = elaborate {
317-
// FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator
318-
// instead of a slice.
319-
let trait_assoc_items: Vec<_> =
320-
tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect();
321-
322315
let predicates = obligations.iter().map(|obligation| obligation.predicate).collect();
323316
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
324317
let implied_obligations = implied_obligations.map(|pred| {
325318
let mut cause = cause.clone();
326319
extend_cause_with_original_assoc_item_obligation(
320+
tcx,
321+
trait_ref,
322+
item,
327323
&mut cause,
328324
&pred,
329-
&*trait_assoc_items,
325+
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
330326
);
331327
traits::Obligation::new(cause, param_env, pred)
332328
});

0 commit comments

Comments
 (0)