Skip to content

Commit cf148a7

Browse files
committed
Auto merge of #65288 - estebank:point-at-assoc-type, r=nikomatsakis
Point at associated type for some obligations Partially address #57663.
2 parents fcf516d + 3a4cacd commit cf148a7

17 files changed

+304
-61
lines changed

src/librustc/traits/error_reporting.rs

+37-15
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
195195
obligation: &PredicateObligation<'tcx>,
196196
error: &MismatchedProjectionTypes<'tcx>,
197197
) {
198-
let predicate =
199-
self.resolve_vars_if_possible(&obligation.predicate);
198+
let predicate = self.resolve_vars_if_possible(&obligation.predicate);
200199

201200
if predicate.references_error() {
202201
return
@@ -228,7 +227,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
228227
&mut obligations
229228
);
230229
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
231-
.eq(normalized_ty, data.ty) {
230+
.eq(normalized_ty, data.ty)
231+
{
232232
values = Some(infer::ValuePairs::Types(ExpectedFound {
233233
expected: normalized_ty,
234234
found: data.ty,
@@ -239,13 +239,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
239239
}
240240

241241
let msg = format!("type mismatch resolving `{}`", predicate);
242-
let error_id = (DiagnosticMessageId::ErrorId(271),
243-
Some(obligation.cause.span), msg);
242+
let error_id = (
243+
DiagnosticMessageId::ErrorId(271),
244+
Some(obligation.cause.span),
245+
msg,
246+
);
244247
let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
245248
if fresh {
246249
let mut diag = struct_span_err!(
247-
self.tcx.sess, obligation.cause.span, E0271,
248-
"type mismatch resolving `{}`", predicate
250+
self.tcx.sess,
251+
obligation.cause.span,
252+
E0271,
253+
"type mismatch resolving `{}`",
254+
predicate
249255
);
250256
self.note_type_err(&mut diag, &obligation.cause, None, values, err);
251257
self.note_obligation_cause(&mut diag, obligation);
@@ -532,23 +538,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
532538
/// whose result could not be truly determined and thus we can't say
533539
/// if the program type checks or not -- and they are unusual
534540
/// occurrences in any case.
535-
pub fn report_overflow_error<T>(&self,
536-
obligation: &Obligation<'tcx, T>,
537-
suggest_increasing_limit: bool) -> !
541+
pub fn report_overflow_error<T>(
542+
&self,
543+
obligation: &Obligation<'tcx, T>,
544+
suggest_increasing_limit: bool,
545+
) -> !
538546
where T: fmt::Display + TypeFoldable<'tcx>
539547
{
540548
let predicate =
541549
self.resolve_vars_if_possible(&obligation.predicate);
542-
let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275,
543-
"overflow evaluating the requirement `{}`",
544-
predicate);
550+
let mut err = struct_span_err!(
551+
self.tcx.sess,
552+
obligation.cause.span,
553+
E0275,
554+
"overflow evaluating the requirement `{}`",
555+
predicate
556+
);
545557

546558
if suggest_increasing_limit {
547559
self.suggest_new_overflow_limit(&mut err);
548560
}
549561

550-
self.note_obligation_cause_code(&mut err, &obligation.predicate, &obligation.cause.code,
551-
&mut vec![]);
562+
self.note_obligation_cause_code(
563+
&mut err,
564+
&obligation.predicate,
565+
&obligation.cause.code,
566+
&mut vec![],
567+
);
552568

553569
err.emit();
554570
self.tcx.sess.abort_if_errors();
@@ -2197,6 +2213,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
21972213
);
21982214
}
21992215
}
2216+
ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
2217+
err.span_label(orig, "associated type defined here");
2218+
if let Some(sp) = impl_span {
2219+
err.span_label(sp, "in this `impl` item");
2220+
}
2221+
}
22002222
}
22012223
}
22022224

src/librustc/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ pub enum ObligationCauseCode<'tcx> {
271271

272272
/// #[feature(trivial_bounds)] is not enabled
273273
TrivialBound,
274+
275+
AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
274276
}
275277

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

src/librustc/traits/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
548548
super::MethodReceiver => Some(super::MethodReceiver),
549549
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
550550
super::TrivialBound => Some(super::TrivialBound),
551+
super::AssocTypeBound(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
551552
}
552553
}
553554
}

src/librustc/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3141,6 +3141,7 @@ impl<'tcx> TyCtxt<'tcx> {
31413141
}
31423142
}
31433143

3144+
#[derive(Clone)]
31443145
pub struct AssocItemsIterator<'tcx> {
31453146
tcx: TyCtxt<'tcx>,
31463147
def_ids: &'tcx [DefId],

src/librustc/ty/wf.rs

+153-19
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ pub fn obligations<'a, 'tcx>(
2222
ty: Ty<'tcx>,
2323
span: Span,
2424
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
25-
let mut wf = WfPredicates { infcx,
26-
param_env,
27-
body_id,
28-
span,
29-
out: vec![] };
25+
let mut wf = WfPredicates {
26+
infcx,
27+
param_env,
28+
body_id,
29+
span,
30+
out: vec![],
31+
item: None,
32+
};
3033
if wf.compute(ty) {
3134
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
3235
let result = wf.normalize();
@@ -47,8 +50,9 @@ pub fn trait_obligations<'a, 'tcx>(
4750
body_id: hir::HirId,
4851
trait_ref: &ty::TraitRef<'tcx>,
4952
span: Span,
53+
item: Option<&'tcx hir::Item>,
5054
) -> Vec<traits::PredicateObligation<'tcx>> {
51-
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
55+
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
5256
wf.compute_trait_ref(trait_ref, Elaborate::All);
5357
wf.normalize()
5458
}
@@ -60,7 +64,7 @@ pub fn predicate_obligations<'a, 'tcx>(
6064
predicate: &ty::Predicate<'tcx>,
6165
span: Span,
6266
) -> Vec<traits::PredicateObligation<'tcx>> {
63-
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
67+
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
6468

6569
// (*) ok to skip binders, because wf code is prepared for it
6670
match *predicate {
@@ -107,6 +111,7 @@ struct WfPredicates<'a, 'tcx> {
107111
body_id: hir::HirId,
108112
span: Span,
109113
out: Vec<traits::PredicateObligation<'tcx>>,
114+
item: Option<&'tcx hir::Item>,
110115
}
111116

112117
/// Controls whether we "elaborate" supertraits and so forth on the WF
@@ -157,33 +162,162 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
157162
.collect()
158163
}
159164

160-
/// Pushes the obligations required for `trait_ref` to be WF into
161-
/// `self.out`.
165+
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
162166
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
167+
let tcx = self.infcx.tcx;
163168
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
164169

165170
let cause = self.cause(traits::MiscObligation);
166171
let param_env = self.param_env;
167172

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

179312
self.out.extend(obligations);
180313

181-
self.out.extend(
182-
trait_ref.substs.types()
183-
.filter(|ty| !ty.has_escaping_bound_vars())
184-
.map(|ty| traits::Obligation::new(cause.clone(),
185-
param_env,
186-
ty::Predicate::WellFormed(ty))));
314+
self.out.extend(trait_ref.substs.types()
315+
.filter(|ty| !ty.has_escaping_bound_vars())
316+
.map(|ty| traits::Obligation::new(
317+
cause.clone(),
318+
param_env,
319+
ty::Predicate::WellFormed(ty),
320+
)));
187321
}
188322

189323
/// Pushes the obligations required for `trait_ref::Item` to be WF

src/librustc_typeck/check/wfcheck.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ fn check_item_type(
430430

431431
fn check_impl<'tcx>(
432432
tcx: TyCtxt<'tcx>,
433-
item: &hir::Item,
433+
item: &'tcx hir::Item,
434434
ast_self_ty: &hir::Ty,
435435
ast_trait_ref: &Option<hir::TraitRef>,
436436
) {
@@ -445,15 +445,18 @@ fn check_impl<'tcx>(
445445
// therefore don't need to be WF (the trait's `Self: Trait` predicate
446446
// won't hold).
447447
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
448-
let trait_ref =
449-
fcx.normalize_associated_types_in(
450-
ast_trait_ref.path.span, &trait_ref);
451-
let obligations =
452-
ty::wf::trait_obligations(fcx,
453-
fcx.param_env,
454-
fcx.body_id,
455-
&trait_ref,
456-
ast_trait_ref.path.span);
448+
let trait_ref = fcx.normalize_associated_types_in(
449+
ast_trait_ref.path.span,
450+
&trait_ref,
451+
);
452+
let obligations = ty::wf::trait_obligations(
453+
fcx,
454+
fcx.param_env,
455+
fcx.body_id,
456+
&trait_ref,
457+
ast_trait_ref.path.span,
458+
Some(item),
459+
);
457460
for obligation in obligations {
458461
fcx.register_predicate(obligation);
459462
}

src/test/compile-fail/chalkify/impl_wf.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl<T> Bar for Option<T> {
2525
impl Bar for f32 {
2626
//~^ ERROR the trait bound `f32: Foo` is not satisfied
2727
type Item = f32;
28+
//~^ ERROR the trait bound `f32: Foo` is not satisfied
2829
}
2930

3031
trait Baz<U: ?Sized> where U: Foo { }

0 commit comments

Comments
 (0)