wf: refactor compute_trait_ref
This commit is contained in:
parent
39b62533c7
commit
ab4178bd7d
@ -134,6 +134,152 @@ enum Elaborate {
|
||||
None,
|
||||
}
|
||||
|
||||
fn extend_cause_with_original_assoc_item_obligation<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
item: Option<&hir::Item<'tcx>>,
|
||||
cause: &mut traits::ObligationCause<'tcx>,
|
||||
pred: &ty::Predicate<'_>,
|
||||
mut trait_assoc_items: impl Iterator<Item = ty::AssocItem>,
|
||||
) {
|
||||
let trait_item =
|
||||
tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| tcx.hir().find(trait_id));
|
||||
let (trait_name, trait_generics) = match trait_item {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(.., generics, _, _),
|
||||
..
|
||||
}))
|
||||
| Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::TraitAlias(generics, _),
|
||||
..
|
||||
})) => (Some(ident), Some(generics)),
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
|
||||
match pred {
|
||||
ty::Predicate::Projection(proj) => {
|
||||
// The obligation comes not from the current `impl` nor the `trait` being
|
||||
// implemented, but rather from a "second order" obligation, like in
|
||||
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
|
||||
//
|
||||
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// ...
|
||||
// LL | impl Bar for Foo {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = ();
|
||||
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
|
||||
// |
|
||||
// = note: expected type `u32`
|
||||
// found type `()`
|
||||
//
|
||||
// FIXME: we would want to point a span to all places that contributed to this
|
||||
// obligation. In the case above, it should be closer to:
|
||||
//
|
||||
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// LL | type Sibling: Bar2<Ok=Self::Ok>;
|
||||
// | -------------------------------- obligation set here
|
||||
// ...
|
||||
// LL | impl Bar for Foo {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = ();
|
||||
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
|
||||
// ...
|
||||
// LL | impl Bar2 for Foo2 {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = u32;
|
||||
// | -------------- obligation set here
|
||||
// |
|
||||
// = note: expected type `u32`
|
||||
// found type `()`
|
||||
if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
|
||||
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
|
||||
if let Some(impl_item) =
|
||||
items.iter().find(|item| item.ident == trait_assoc_item.ident)
|
||||
{
|
||||
cause.span = impl_item.span;
|
||||
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
|
||||
impl_span: item_span,
|
||||
original: trait_assoc_item.ident.span,
|
||||
bounds: vec![],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Predicate::Trait(proj, _) => {
|
||||
// An associated item obligation born out of the `trait` failed to be met.
|
||||
// Point at the `impl` that failed the obligation, the associated item that
|
||||
// needed to meet the obligation, and the definition of that associated item,
|
||||
// which should hold the obligation in most cases. An example can be seen in
|
||||
// `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
|
||||
//
|
||||
// error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
||||
// |
|
||||
// LL | type Assoc: Bar;
|
||||
// | ----- associated type defined here
|
||||
// ...
|
||||
// LL | impl Foo for () {
|
||||
// | --------------- in this `impl` item
|
||||
// LL | type Assoc = bool;
|
||||
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
//
|
||||
// If the obligation comes from the where clause in the `trait`, we point at it:
|
||||
//
|
||||
// error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
||||
// |
|
||||
// | trait Foo where <Self as Foo>>::Assoc: Bar {
|
||||
// | -------------------------- restricted in this bound
|
||||
// LL | type Assoc;
|
||||
// | ----- associated type defined here
|
||||
// ...
|
||||
// LL | impl Foo for () {
|
||||
// | --------------- in this `impl` item
|
||||
// LL | type Assoc = bool;
|
||||
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
if let (
|
||||
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
|
||||
Some(hir::ItemKind::Impl { items, .. }),
|
||||
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
|
||||
{
|
||||
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
|
||||
.find(|i| i.def_id == *item_def_id)
|
||||
.and_then(|trait_assoc_item| {
|
||||
items
|
||||
.iter()
|
||||
.find(|i| i.ident == trait_assoc_item.ident)
|
||||
.map(|impl_item| (impl_item, trait_assoc_item))
|
||||
})
|
||||
{
|
||||
let bounds = trait_generics
|
||||
.map(|generics| {
|
||||
get_generic_bound_spans(&generics, trait_name, trait_assoc_item.ident)
|
||||
})
|
||||
.unwrap_or_else(Vec::new);
|
||||
cause.span = impl_item.span;
|
||||
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
|
||||
impl_span: item_span,
|
||||
original: trait_assoc_item.ident.span,
|
||||
bounds,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
||||
traits::ObligationCause::new(self.span, self.body_id, code)
|
||||
@ -163,170 +309,20 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let param_env = self.param_env;
|
||||
|
||||
let item = &self.item;
|
||||
let extend_cause_with_original_assoc_item_obligation =
|
||||
|cause: &mut traits::ObligationCause<'_>,
|
||||
pred: &ty::Predicate<'_>,
|
||||
trait_assoc_items: &[ty::AssocItem]| {
|
||||
let trait_item = tcx
|
||||
.hir()
|
||||
.as_local_hir_id(trait_ref.def_id)
|
||||
.and_then(|trait_id| tcx.hir().find(trait_id));
|
||||
let (trait_name, trait_generics) = match trait_item {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(.., generics, _, _),
|
||||
..
|
||||
}))
|
||||
| Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::TraitAlias(generics, _),
|
||||
..
|
||||
})) => (Some(ident), Some(generics)),
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
|
||||
match pred {
|
||||
ty::Predicate::Projection(proj) => {
|
||||
// The obligation comes not from the current `impl` nor the `trait` being
|
||||
// implemented, but rather from a "second order" obligation, like in
|
||||
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
|
||||
//
|
||||
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// ...
|
||||
// LL | impl Bar for Foo {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = ();
|
||||
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
|
||||
// |
|
||||
// = note: expected type `u32`
|
||||
// found type `()`
|
||||
//
|
||||
// FIXME: we would want to point a span to all places that contributed to this
|
||||
// obligation. In the case above, it should be closer to:
|
||||
//
|
||||
// error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// LL | type Sibling: Bar2<Ok=Self::Ok>;
|
||||
// | -------------------------------- obligation set here
|
||||
// ...
|
||||
// LL | impl Bar for Foo {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = ();
|
||||
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
|
||||
// ...
|
||||
// LL | impl Bar2 for Foo2 {
|
||||
// | ---------------- in this `impl` item
|
||||
// LL | type Ok = u32;
|
||||
// | -------------- obligation set here
|
||||
// |
|
||||
// = note: expected type `u32`
|
||||
// found type `()`
|
||||
if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
|
||||
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
|
||||
if let Some(impl_item) =
|
||||
items.iter().find(|item| item.ident == trait_assoc_item.ident)
|
||||
{
|
||||
cause.span = impl_item.span;
|
||||
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
|
||||
impl_span: item_span,
|
||||
original: trait_assoc_item.ident.span,
|
||||
bounds: vec![],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Predicate::Trait(proj, _) => {
|
||||
// An associated item obligation born out of the `trait` failed to be met.
|
||||
// Point at the `impl` that failed the obligation, the associated item that
|
||||
// needed to meet the obligation, and the definition of that associated item,
|
||||
// which should hold the obligation in most cases. An example can be seen in
|
||||
// `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
|
||||
//
|
||||
// error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
||||
// |
|
||||
// LL | type Assoc: Bar;
|
||||
// | ----- associated type defined here
|
||||
// ...
|
||||
// LL | impl Foo for () {
|
||||
// | --------------- in this `impl` item
|
||||
// LL | type Assoc = bool;
|
||||
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
//
|
||||
// If the obligation comes from the where clause in the `trait`, we point at it:
|
||||
//
|
||||
// error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
||||
// |
|
||||
// | trait Foo where <Self as Foo>>::Assoc: Bar {
|
||||
// | -------------------------- restricted in this bound
|
||||
// LL | type Assoc;
|
||||
// | ----- associated type defined here
|
||||
// ...
|
||||
// LL | impl Foo for () {
|
||||
// | --------------- in this `impl` item
|
||||
// LL | type Assoc = bool;
|
||||
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
if let (
|
||||
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
|
||||
Some(hir::ItemKind::Impl { items, .. }),
|
||||
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
|
||||
{
|
||||
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
|
||||
.iter()
|
||||
.find(|i| i.def_id == *item_def_id)
|
||||
.and_then(|trait_assoc_item| {
|
||||
items
|
||||
.iter()
|
||||
.find(|i| i.ident == trait_assoc_item.ident)
|
||||
.map(|impl_item| (impl_item, trait_assoc_item))
|
||||
})
|
||||
{
|
||||
let bounds = trait_generics
|
||||
.map(|generics| {
|
||||
get_generic_bound_spans(
|
||||
&generics,
|
||||
trait_name,
|
||||
trait_assoc_item.ident,
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(Vec::new);
|
||||
cause.span = impl_item.span;
|
||||
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
|
||||
impl_span: item_span,
|
||||
original: trait_assoc_item.ident.span,
|
||||
bounds,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
let item = self.item;
|
||||
|
||||
if let Elaborate::All = elaborate {
|
||||
// FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator
|
||||
// instead of a slice.
|
||||
let trait_assoc_items: Vec<_> =
|
||||
tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect();
|
||||
|
||||
let predicates = obligations.iter().map(|obligation| obligation.predicate).collect();
|
||||
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
|
||||
let implied_obligations = implied_obligations.map(|pred| {
|
||||
let mut cause = cause.clone();
|
||||
extend_cause_with_original_assoc_item_obligation(
|
||||
tcx,
|
||||
trait_ref,
|
||||
item,
|
||||
&mut cause,
|
||||
&pred,
|
||||
&*trait_assoc_items,
|
||||
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
|
||||
);
|
||||
traits::Obligation::new(cause, param_env, pred)
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user