Skip to content

Commit

Permalink
Remove AssocTypeBound and propagate bound Spans
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Apr 18, 2020
1 parent ad1c23c commit 6bc55c7
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 287 deletions.
9 changes: 0 additions & 9 deletions src/librustc_middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ pub enum ObligationCauseCode<'tcx> {

/// #[feature(trivial_bounds)] is not enabled
TrivialBound,

AssocTypeBound(Box<AssocTypeBoundData>),
}

impl ObligationCauseCode<'_> {
Expand All @@ -272,13 +270,6 @@ impl ObligationCauseCode<'_> {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AssocTypeBoundData {
pub impl_span: Option<Span>,
pub original: Span,
pub bounds: Vec<Span>,
}

// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(ObligationCauseCode<'_>, 32);
Expand Down
1 change: 0 additions & 1 deletion src/librustc_middle/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1684,15 +1684,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
}
}
ObligationCauseCode::AssocTypeBound(ref data) => {
err.span_label(data.original, "associated type defined here");
if let Some(sp) = data.impl_span {
err.span_label(sp, "in this `impl` item");
}
for sp in &data.bounds {
err.span_label(*sp, "restricted in this bound");
}
}
}
}

Expand Down
229 changes: 50 additions & 179 deletions src/librustc_trait_selection/traits/wf.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use crate::infer::InferCtxt;
use crate::opaque_types::required_region_bounds;
use crate::traits::{self, AssocTypeBoundData};
use crate::traits;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
use std::rc::Rc;

Expand Down Expand Up @@ -143,137 +142,57 @@ fn extend_cause_with_original_assoc_item_obligation<'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),
debug!(
"extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
trait_ref, item, cause, pred
);
let items = match item {
Some(hir::Item { kind: hir::ItemKind::Impl { items, .. }, .. }) => items,
_ => return,
};

let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span));
let fix_span =
|impl_item_ref: &hir::ImplItemRef<'_>| match tcx.hir().impl_item(impl_item_ref.id).kind {
hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span,
_ => impl_item_ref.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![],
}));
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`.
let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
if let Some(impl_item_span) =
items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
{
cause.span = impl_item_span;
} else {
let kind = &proj.ty().skip_binder().kind;
if let ty::Projection(projection_ty) = kind {
// This happens when an associated type has a projection coming from another
// associated type. See `traits-assoc-type-in-supertrait-bad.rs`.
let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id);
if let Some(impl_item_span) =
items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
{
cause.span = impl_item_span;
}
}
}
}
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))
ty::Predicate::Trait(pred, _) => {
// An associated item obligation born out of the `trait` failed to be met. An example
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) =
&pred.skip_binder().self_ty().kind
{
if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
if let Some(impl_item_span) = 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))
items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
})
{
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,
}));
cause.span = impl_item_span;
}
}
}
Expand Down Expand Up @@ -307,6 +226,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let tcx = self.infcx.tcx;
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);

debug!("compute_trait_ref obligations {:?}", obligations);
let cause = self.cause(traits::MiscObligation);
let param_env = self.param_env;

Expand All @@ -315,16 +235,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
if let Elaborate::All = elaborate {
let implied_obligations = traits::util::elaborate_obligations(tcx, obligations.clone());
let implied_obligations = implied_obligations.map(|obligation| {
debug!("compute_trait_ref implied_obligation {:?}", obligation);
debug!("compute_trait_ref implied_obligation cause {:?}", obligation.cause);
let mut cause = cause.clone();
let parent_trait_ref = obligation
.predicate
.to_opt_poly_trait_ref()
.unwrap_or_else(|| ty::Binder::dummy(*trait_ref));
let derived_cause = traits::DerivedObligationCause {
parent_trait_ref,
parent_code: Rc::new(obligation.cause.code.clone()),
};
cause.code = traits::ObligationCauseCode::ImplDerivedObligation(derived_cause);
if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
let derived_cause = traits::DerivedObligationCause {
parent_trait_ref,
parent_code: Rc::new(obligation.cause.code.clone()),
};
cause.code = traits::ObligationCauseCode::ImplDerivedObligation(derived_cause);
}
extend_cause_with_original_assoc_item_obligation(
tcx,
trait_ref,
Expand All @@ -333,6 +253,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
&obligation.predicate,
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
);
debug!("compute_trait_ref new cause {:?}", cause);
traits::Obligation::new(cause, param_env, obligation.predicate)
});
self.out.extend(implied_obligations);
Expand Down Expand Up @@ -719,53 +640,3 @@ pub fn object_region_bounds<'tcx>(

required_region_bounds(tcx, open_ty, predicates)
}

/// Find the span of a generic bound affecting an associated type.
fn get_generic_bound_spans(
generics: &hir::Generics<'_>,
trait_name: Option<&Ident>,
assoc_item_name: Ident,
) -> Vec<Span> {
let mut bounds = vec![];
for clause in generics.where_clause.predicates.iter() {
if let hir::WherePredicate::BoundPredicate(pred) = clause {
match &pred.bounded_ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => {
let mut s = path.segments.iter();
if let (a, Some(b), None) = (s.next(), s.next(), s.next()) {
if a.map(|s| &s.ident) == trait_name
&& b.ident == assoc_item_name
&& is_self_path(&ty.kind)
{
// `<Self as Foo>::Bar`
bounds.push(pred.span);
}
}
}
hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
if segment.ident == assoc_item_name {
if is_self_path(&ty.kind) {
// `Self::Bar`
bounds.push(pred.span);
}
}
}
_ => {}
}
}
}
bounds
}

fn is_self_path(kind: &hir::TyKind<'_>) -> bool {
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = kind {
let mut s = path.segments.iter();
if let (Some(segment), None) = (s.next(), s.next()) {
if segment.ident.name == kw::SelfUpper {
// `type(Self)`
return true;
}
}
}
false
}
2 changes: 1 addition & 1 deletion src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
bounds,
speculative,
&mut dup_bindings,
span,
binding.span,
);
// Okay to ignore `Err` because of `ErrorReported` (see above).
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LL | fn dent<C:BoxCar>(c: C, color: <C as Vehicle>::Color) {
| ^^^^^^^^^^^^^^^^^^^^^

error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar`
--> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30
--> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37
|
LL | type Color;
| ----------- ambiguous `Color` from `Vehicle`
Expand All @@ -37,7 +37,7 @@ LL | type Color;
| ----------- ambiguous `Color` from `Box`
...
LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {
| ^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Color`
| ^^^^^^^^^^^ ambiguous associated type `Color`
|
= help: consider introducing a new type parameter `T` and adding `where` constraints:
where
Expand Down
Loading

0 comments on commit 6bc55c7

Please sign in to comment.