Skip to content

Commit

Permalink
Rollup merge of rust-lang#65994 - estebank:where-bound, r=nikomatsakis
Browse files Browse the repository at this point in the history
Point at where clauses where the associated item was restricted

CC rust-lang#57663.
r? @nikomatsakis
  • Loading branch information
Centril committed Nov 9, 2019
2 parents b9351ef + 9534b58 commit 523a7d5
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 18 deletions.
9 changes: 6 additions & 3 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2287,11 +2287,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
}
ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
err.span_label(orig, "associated type defined here");
if let Some(sp) = impl_span {
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
9 changes: 8 additions & 1 deletion src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,14 @@ pub enum ObligationCauseCode<'tcx> {
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,

AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
AssocTypeBound(Box<AssocTypeBoundData>),
}

#[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.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ 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(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
}
}
}
Expand Down
101 changes: 89 additions & 12 deletions src/librustc/ty/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use crate::hir;
use crate::hir::def_id::DefId;
use crate::infer::InferCtxt;
use crate::ty::subst::SubstsRef;
use crate::traits;
use crate::traits::{self, AssocTypeBoundData};
use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use std::iter::once;
use syntax::symbol::{kw, Ident};
use syntax_pos::Span;
use crate::middle::lang_items;
use crate::mir::interpret::ConstValue;
Expand Down Expand Up @@ -176,6 +177,23 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
pred: &ty::Predicate<'_>,
trait_assoc_items: ty::AssocItemsIterator<'_>,
| {
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().def_span(i.span));
match pred {
ty::Predicate::Projection(proj) => {
Expand Down Expand Up @@ -226,10 +244,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
item.ident == trait_assoc_item.ident
}).next() {
cause.span = impl_item.span;
cause.code = traits::AssocTypeBound(
item_span,
trait_assoc_item.ident.span,
);
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
impl_span: item_span,
original: trait_assoc_item.ident.span,
bounds: vec![],
}));
}
}
}
Expand All @@ -251,14 +270,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// LL | type Assoc = bool;
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
//
// FIXME: if the obligation comes from the where clause in the `trait`, we
// should point at it:
// 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 {
// | -------------------------- obligation set here
// | -------------------------- restricted in this bound
// LL | type Assoc;
// | ----- associated type defined here
// ...
Expand All @@ -278,11 +296,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
.next()
.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(
item_span,
trait_assoc_item.ident.span,
);
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
impl_span: item_span,
original: trait_assoc_item.ident.span,
bounds,
}));
}
}
}
Expand Down Expand Up @@ -666,3 +690,56 @@ pub fn object_region_bounds<'tcx>(

tcx.required_region_bounds(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 {
match kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,20 @@ impl Foo for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}

trait Baz where Self::Assoc: Bar {
type Assoc;
}

impl Baz for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}

trait Bat where <Self as Bat>::Assoc: Bar {
type Assoc;
}

impl Bat for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ LL | impl Foo for () {
LL | type Assoc = bool;
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`

error: aborting due to previous error
error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-2.rs:16:5
|
LL | trait Baz where Self::Assoc: Bar {
| ---------------- restricted in this bound
LL | type Assoc;
| ----- associated type defined here
...
LL | impl Baz for () {
| --------------- in this `impl` item
LL | type Assoc = bool;
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`

error[E0277]: the trait bound `bool: Bar` is not satisfied
--> $DIR/point-at-type-on-obligation-failure-2.rs:24:5
|
LL | trait Bat where <Self as Bat>::Assoc: Bar {
| ------------------------- restricted in this bound
LL | type Assoc;
| ----- associated type defined here
...
LL | impl Bat for () {
| --------------- in this `impl` item
LL | type Assoc = bool;
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 523a7d5

Please sign in to comment.