Skip to content

Commit 523a7d5

Browse files
authored
Rollup merge of rust-lang#65994 - estebank:where-bound, r=nikomatsakis
Point at where clauses where the associated item was restricted CC rust-lang#57663. r? @nikomatsakis
2 parents b9351ef + 9534b58 commit 523a7d5

6 files changed

+147
-18
lines changed

src/librustc/traits/error_reporting.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -2287,11 +2287,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
22872287
);
22882288
}
22892289
}
2290-
ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
2291-
err.span_label(orig, "associated type defined here");
2292-
if let Some(sp) = impl_span {
2290+
ObligationCauseCode::AssocTypeBound(ref data) => {
2291+
err.span_label(data.original, "associated type defined here");
2292+
if let Some(sp) = data.impl_span {
22932293
err.span_label(sp, "in this `impl` item");
22942294
}
2295+
for sp in &data.bounds {
2296+
err.span_label(*sp, "restricted in this bound");
2297+
}
22952298
}
22962299
}
22972300
}

src/librustc/traits/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,14 @@ pub enum ObligationCauseCode<'tcx> {
276276
/// #[feature(trivial_bounds)] is not enabled
277277
TrivialBound,
278278

279-
AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
279+
AssocTypeBound(Box<AssocTypeBoundData>),
280+
}
281+
282+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
283+
pub struct AssocTypeBoundData {
284+
pub impl_span: Option<Span>,
285+
pub original: Span,
286+
pub bounds: Vec<Span>,
280287
}
281288

282289
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.

src/librustc/traits/structural_impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
549549
super::MethodReceiver => Some(super::MethodReceiver),
550550
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
551551
super::TrivialBound => Some(super::TrivialBound),
552-
super::AssocTypeBound(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
552+
super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
553553
}
554554
}
555555
}

src/librustc/ty/wf.rs

+89-12
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use crate::hir;
22
use crate::hir::def_id::DefId;
33
use crate::infer::InferCtxt;
44
use crate::ty::subst::SubstsRef;
5-
use crate::traits;
5+
use crate::traits::{self, AssocTypeBoundData};
66
use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
77
use std::iter::once;
8+
use syntax::symbol::{kw, Ident};
89
use syntax_pos::Span;
910
use crate::middle::lang_items;
1011
use crate::mir::interpret::ConstValue;
@@ -176,6 +177,23 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
176177
pred: &ty::Predicate<'_>,
177178
trait_assoc_items: ty::AssocItemsIterator<'_>,
178179
| {
180+
let trait_item = tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| {
181+
tcx.hir().find(trait_id)
182+
});
183+
let (trait_name, trait_generics) = match trait_item {
184+
Some(hir::Node::Item(hir::Item {
185+
ident,
186+
kind: hir::ItemKind::Trait(.., generics, _, _),
187+
..
188+
})) |
189+
Some(hir::Node::Item(hir::Item {
190+
ident,
191+
kind: hir::ItemKind::TraitAlias(generics, _),
192+
..
193+
})) => (Some(ident), Some(generics)),
194+
_ => (None, None),
195+
};
196+
179197
let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span));
180198
match pred {
181199
ty::Predicate::Projection(proj) => {
@@ -226,10 +244,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
226244
item.ident == trait_assoc_item.ident
227245
}).next() {
228246
cause.span = impl_item.span;
229-
cause.code = traits::AssocTypeBound(
230-
item_span,
231-
trait_assoc_item.ident.span,
232-
);
247+
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
248+
impl_span: item_span,
249+
original: trait_assoc_item.ident.span,
250+
bounds: vec![],
251+
}));
233252
}
234253
}
235254
}
@@ -251,14 +270,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
251270
// LL | type Assoc = bool;
252271
// | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
253272
//
254-
// FIXME: if the obligation comes from the where clause in the `trait`, we
255-
// should point at it:
273+
// If the obligation comes from the where clause in the `trait`, we point at it:
256274
//
257275
// error[E0277]: the trait bound `bool: Bar` is not satisfied
258276
// --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
259277
// |
260278
// | trait Foo where <Self as Foo>>::Assoc: Bar {
261-
// | -------------------------- obligation set here
279+
// | -------------------------- restricted in this bound
262280
// LL | type Assoc;
263281
// | ----- associated type defined here
264282
// ...
@@ -278,11 +296,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
278296
.next()
279297
.map(|impl_item| (impl_item, trait_assoc_item)))
280298
{
299+
let bounds = trait_generics.map(|generics| get_generic_bound_spans(
300+
&generics,
301+
trait_name,
302+
trait_assoc_item.ident,
303+
)).unwrap_or_else(Vec::new);
281304
cause.span = impl_item.span;
282-
cause.code = traits::AssocTypeBound(
283-
item_span,
284-
trait_assoc_item.ident.span,
285-
);
305+
cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
306+
impl_span: item_span,
307+
original: trait_assoc_item.ident.span,
308+
bounds,
309+
}));
286310
}
287311
}
288312
}
@@ -666,3 +690,56 @@ pub fn object_region_bounds<'tcx>(
666690

667691
tcx.required_region_bounds(open_ty, predicates)
668692
}
693+
694+
/// Find the span of a generic bound affecting an associated type.
695+
fn get_generic_bound_spans(
696+
generics: &hir::Generics,
697+
trait_name: Option<&Ident>,
698+
assoc_item_name: Ident,
699+
) -> Vec<Span> {
700+
let mut bounds = vec![];
701+
for clause in generics.where_clause.predicates.iter() {
702+
if let hir::WherePredicate::BoundPredicate(pred) = clause {
703+
match &pred.bounded_ty.kind {
704+
hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => {
705+
let mut s = path.segments.iter();
706+
if let (a, Some(b), None) = (s.next(), s.next(), s.next()) {
707+
if a.map(|s| &s.ident) == trait_name
708+
&& b.ident == assoc_item_name
709+
&& is_self_path(&ty.kind)
710+
{
711+
// `<Self as Foo>::Bar`
712+
bounds.push(pred.span);
713+
}
714+
}
715+
}
716+
hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
717+
if segment.ident == assoc_item_name {
718+
if is_self_path(&ty.kind) {
719+
// `Self::Bar`
720+
bounds.push(pred.span);
721+
}
722+
}
723+
}
724+
_ => {}
725+
}
726+
}
727+
}
728+
bounds
729+
}
730+
731+
fn is_self_path(kind: &hir::TyKind) -> bool {
732+
match kind {
733+
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
734+
let mut s = path.segments.iter();
735+
if let (Some(segment), None) = (s.next(), s.next()) {
736+
if segment.ident.name == kw::SelfUpper {
737+
// `type(Self)`
738+
return true;
739+
}
740+
}
741+
}
742+
_ => {}
743+
}
744+
false
745+
}

src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs

+16
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,20 @@ impl Foo for () {
88
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
99
}
1010

11+
trait Baz where Self::Assoc: Bar {
12+
type Assoc;
13+
}
14+
15+
impl Baz for () {
16+
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
17+
}
18+
19+
trait Bat where <Self as Bat>::Assoc: Bar {
20+
type Assoc;
21+
}
22+
23+
impl Bat for () {
24+
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
25+
}
26+
1127
fn main() {}

src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr

+27-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@ LL | impl Foo for () {
99
LL | type Assoc = bool;
1010
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
1111

12-
error: aborting due to previous error
12+
error[E0277]: the trait bound `bool: Bar` is not satisfied
13+
--> $DIR/point-at-type-on-obligation-failure-2.rs:16:5
14+
|
15+
LL | trait Baz where Self::Assoc: Bar {
16+
| ---------------- restricted in this bound
17+
LL | type Assoc;
18+
| ----- associated type defined here
19+
...
20+
LL | impl Baz for () {
21+
| --------------- in this `impl` item
22+
LL | type Assoc = bool;
23+
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
24+
25+
error[E0277]: the trait bound `bool: Bar` is not satisfied
26+
--> $DIR/point-at-type-on-obligation-failure-2.rs:24:5
27+
|
28+
LL | trait Bat where <Self as Bat>::Assoc: Bar {
29+
| ------------------------- restricted in this bound
30+
LL | type Assoc;
31+
| ----- associated type defined here
32+
...
33+
LL | impl Bat for () {
34+
| --------------- in this `impl` item
35+
LL | type Assoc = bool;
36+
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
37+
38+
error: aborting due to 3 previous errors
1339

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

0 commit comments

Comments
 (0)