Skip to content

Commit 1fe86f4

Browse files
authored
Rollup merge of rust-lang#69745 - estebank:predicate-obligations-3, r=nikomatsakis,eddyb
Use `PredicateObligation`s instead of `Predicate`s Keep more information about trait binding failures. Use more specific spans by pointing at bindings that introduce obligations. Subset of rust-lang#69709. r? @eddyb
2 parents dbc3cfd + d605a9d commit 1fe86f4

File tree

207 files changed

+547
-403
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+547
-403
lines changed

src/librustc_infer/infer/outlives/verify.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
296296
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
297297
self.collect_outlives_from_predicate_list(
298298
move |ty| ty == identity_proj,
299-
traits::elaborate_predicates(tcx, trait_predicates),
299+
traits::elaborate_predicates(tcx, trait_predicates)
300+
.into_iter()
301+
.map(|o| o.predicate)
302+
.collect::<Vec<_>>(),
300303
)
301304
.map(|b| b.1)
302305
}

src/librustc_infer/traits/util.rs

+48-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use smallvec::smallvec;
22

3+
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
34
use rustc_data_structures::fx::FxHashSet;
45
use rustc_middle::ty::outlives::Component;
56
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, TyCtxt, WithConstness};
7+
use rustc_span::Span;
68

79
pub fn anonymize_predicate<'tcx>(
810
tcx: TyCtxt<'tcx>,
@@ -87,7 +89,7 @@ impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> {
8789
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
8890
/// `T: Foo`, then we know that `T: 'static`.
8991
pub struct Elaborator<'tcx> {
90-
stack: Vec<ty::Predicate<'tcx>>,
92+
stack: Vec<PredicateObligation<'tcx>>,
9193
visited: PredicateSet<'tcx>,
9294
}
9395

@@ -112,35 +114,60 @@ pub fn elaborate_predicates<'tcx>(
112114
) -> Elaborator<'tcx> {
113115
let mut visited = PredicateSet::new(tcx);
114116
predicates.retain(|pred| visited.insert(pred));
115-
Elaborator { stack: predicates, visited }
117+
let obligations: Vec<_> =
118+
predicates.into_iter().map(|predicate| predicate_obligation(predicate, None)).collect();
119+
elaborate_obligations(tcx, obligations)
120+
}
121+
122+
pub fn elaborate_obligations<'tcx>(
123+
tcx: TyCtxt<'tcx>,
124+
mut obligations: Vec<PredicateObligation<'tcx>>,
125+
) -> Elaborator<'tcx> {
126+
let mut visited = PredicateSet::new(tcx);
127+
obligations.retain(|obligation| visited.insert(&obligation.predicate));
128+
Elaborator { stack: obligations, visited }
129+
}
130+
131+
fn predicate_obligation<'tcx>(
132+
predicate: ty::Predicate<'tcx>,
133+
span: Option<Span>,
134+
) -> PredicateObligation<'tcx> {
135+
let mut cause = ObligationCause::dummy();
136+
if let Some(span) = span {
137+
cause.span = span;
138+
}
139+
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
116140
}
117141

118142
impl Elaborator<'tcx> {
119143
pub fn filter_to_traits(self) -> FilterToTraits<Self> {
120144
FilterToTraits::new(self)
121145
}
122146

123-
fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
147+
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
124148
let tcx = self.visited.tcx;
125-
match *predicate {
149+
match obligation.predicate {
126150
ty::Predicate::Trait(ref data, _) => {
127151
// Get predicates declared on the trait.
128152
let predicates = tcx.super_predicates_of(data.def_id());
129153

130-
let predicates = predicates
131-
.predicates
132-
.iter()
133-
.map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref()));
134-
debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone());
154+
let obligations = predicates.predicates.iter().map(|(pred, span)| {
155+
predicate_obligation(
156+
pred.subst_supertrait(tcx, &data.to_poly_trait_ref()),
157+
Some(*span),
158+
)
159+
});
160+
debug!("super_predicates: data={:?} predicates={:?}", data, &obligations);
135161

136162
// Only keep those bounds that we haven't already seen.
137163
// This is necessary to prevent infinite recursion in some
138164
// cases. One common case is when people define
139165
// `trait Sized: Sized { }` rather than `trait Sized { }`.
140166
let visited = &mut self.visited;
141-
let predicates = predicates.filter(|pred| visited.insert(pred));
167+
let obligations =
168+
obligations.filter(|obligation| visited.insert(&obligation.predicate));
142169

143-
self.stack.extend(predicates);
170+
self.stack.extend(obligations);
144171
}
145172
ty::Predicate::WellFormed(..) => {
146173
// Currently, we do not elaborate WF predicates,
@@ -221,25 +248,26 @@ impl Elaborator<'tcx> {
221248
None
222249
}
223250
})
224-
.filter(|p| visited.insert(p)),
251+
.filter(|p| visited.insert(p))
252+
.map(|p| predicate_obligation(p, None)),
225253
);
226254
}
227255
}
228256
}
229257
}
230258

231259
impl Iterator for Elaborator<'tcx> {
232-
type Item = ty::Predicate<'tcx>;
260+
type Item = PredicateObligation<'tcx>;
233261

234262
fn size_hint(&self) -> (usize, Option<usize>) {
235263
(self.stack.len(), None)
236264
}
237265

238-
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
266+
fn next(&mut self) -> Option<Self::Item> {
239267
// Extract next item from top-most stack frame, if any.
240-
if let Some(pred) = self.stack.pop() {
241-
self.elaborate(&pred);
242-
Some(pred)
268+
if let Some(obligation) = self.stack.pop() {
269+
self.elaborate(&obligation);
270+
Some(obligation)
243271
} else {
244272
None
245273
}
@@ -282,12 +310,12 @@ impl<I> FilterToTraits<I> {
282310
}
283311
}
284312

285-
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
313+
impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
286314
type Item = ty::PolyTraitRef<'tcx>;
287315

288316
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
289-
while let Some(pred) = self.base_iterator.next() {
290-
if let ty::Predicate::Trait(data, _) = pred {
317+
while let Some(obligation) = self.base_iterator.next() {
318+
if let ty::Predicate::Trait(data, _) = obligation.predicate {
291319
return Some(data.to_poly_trait_ref());
292320
}
293321
}

src/librustc_mir/transform/const_prop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
126126
.collect();
127127
if !traits::normalize_and_test_predicates(
128128
tcx,
129-
traits::elaborate_predicates(tcx, predicates).collect(),
129+
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
130130
) {
131131
trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", source.def_id());
132132
return;

src/librustc_trait_selection/opaque_types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1255,8 +1255,8 @@ crate fn required_region_bounds(
12551255
assert!(!erased_self_ty.has_escaping_bound_vars());
12561256

12571257
traits::elaborate_predicates(tcx, predicates)
1258-
.filter_map(|predicate| {
1259-
match predicate {
1258+
.filter_map(|obligation| {
1259+
match obligation.predicate {
12601260
ty::Predicate::Projection(..)
12611261
| ty::Predicate::Trait(..)
12621262
| ty::Predicate::Subtype(..)

src/librustc_trait_selection/traits/auto_trait.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,8 @@ impl AutoTraitFinder<'tcx> {
366366

367367
computed_preds.extend(user_computed_preds.iter().cloned());
368368
let normalized_preds =
369-
elaborate_predicates(tcx, computed_preds.iter().cloned().collect());
369+
elaborate_predicates(tcx, computed_preds.iter().cloned().collect())
370+
.map(|o| o.predicate);
370371
new_env =
371372
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None);
372373
}

src/librustc_trait_selection/traits/error_reporting/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -976,8 +976,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
976976
}
977977
};
978978

979-
for implication in super::elaborate_predicates(self.tcx, vec![*cond]) {
980-
if let ty::Predicate::Trait(implication, _) = implication {
979+
for obligation in super::elaborate_predicates(self.tcx, vec![*cond]) {
980+
if let ty::Predicate::Trait(implication, _) = obligation.predicate {
981981
let error = error.to_poly_trait_ref();
982982
let implication = implication.to_poly_trait_ref();
983983
// FIXME: I'm just not taking associated types at all here.
@@ -1387,7 +1387,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
13871387
(self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
13881388
{
13891389
let generics = self.tcx.generics_of(*def_id);
1390-
if !generics.params.is_empty() && !snippet.ends_with('>') {
1390+
if generics.params.iter().filter(|p| p.name.as_str() != "Self").next().is_some()
1391+
&& !snippet.ends_with('>')
1392+
{
13911393
// FIXME: To avoid spurious suggestions in functions where type arguments
13921394
// where already supplied, we check the snippet to make sure it doesn't
13931395
// end with a turbofish. Ideally we would have access to a `PathSegment`
@@ -1405,7 +1407,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
14051407
// | `Tt::const_val::<[i8; 123]>::<T>`
14061408
// ...
14071409
// LL | const fn const_val<T: Sized>() -> usize {
1408-
// | --------- - required by this bound in `Tt::const_val`
1410+
// | - required by this bound in `Tt::const_val`
14091411
// |
14101412
// = note: cannot satisfy `_: Tt`
14111413

src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
142142
}
143143
}
144144

145-
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
145+
if let ObligationCauseCode::ItemObligation(item)
146+
| ObligationCauseCode::BindingObligation(item, _) = obligation.cause.code
147+
{
146148
// FIXME: maybe also have some way of handling methods
147149
// from other traits? That would require name resolution,
148150
// which we might want to be some sort of hygienic.

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
948948
/// --> $DIR/issue-64130-2-send.rs:21:5
949949
/// |
950950
/// LL | fn is_send<T: Send>(t: T) { }
951-
/// | ------- ---- required by this bound in `is_send`
951+
/// | ---- required by this bound in `is_send`
952952
/// ...
953953
/// LL | is_send(bar());
954954
/// | ^^^^^^^ future returned by `bar` is not send
@@ -1345,7 +1345,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13451345
ObligationCauseCode::ItemObligation(item_def_id) => {
13461346
let item_name = tcx.def_path_str(item_def_id);
13471347
let msg = format!("required by `{}`", item_name);
1348-
13491348
if let Some(sp) = tcx.hir().span_if_local(item_def_id) {
13501349
let sp = tcx.sess.source_map().guess_head_span(sp);
13511350
err.span_label(sp, &msg);
@@ -1357,7 +1356,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13571356
let item_name = tcx.def_path_str(item_def_id);
13581357
let msg = format!("required by this bound in `{}`", item_name);
13591358
if let Some(ident) = tcx.opt_item_name(item_def_id) {
1360-
err.span_label(ident.span, "");
1359+
let sm = self.tcx.sess.source_map();
1360+
let same_line =
1361+
match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) {
1362+
(Ok(l), Ok(r)) => l.line == r.line,
1363+
_ => true,
1364+
};
1365+
if !ident.span.overlaps(span) && !same_line {
1366+
err.span_label(ident.span, "");
1367+
}
13611368
}
13621369
if span != DUMMY_SP {
13631370
err.span_label(span, &msg);

src/librustc_trait_selection/traits/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,9 @@ pub fn normalize_param_env_or_error<'tcx>(
297297
);
298298

299299
let mut predicates: Vec<_> =
300-
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect();
300+
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
301+
.map(|obligation| obligation.predicate)
302+
.collect();
301303

302304
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
303305

src/librustc_trait_selection/traits/object_safety.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
298298
// Search for a predicate like `Self : Sized` amongst the trait bounds.
299299
let predicates = tcx.predicates_of(def_id);
300300
let predicates = predicates.instantiate_identity(tcx).predicates;
301-
elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
301+
elaborate_predicates(tcx, predicates).any(|obligation| match obligation.predicate {
302302
ty::Predicate::Trait(ref trait_pred, _) => {
303303
trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
304304
}

src/librustc_trait_selection/traits/project.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
900900
// If so, extract what we know from the trait and try to come up with a good answer.
901901
let trait_predicates = tcx.predicates_of(def_id);
902902
let bounds = trait_predicates.instantiate(tcx, substs);
903-
let bounds = elaborate_predicates(tcx, bounds.predicates);
903+
let bounds = elaborate_predicates(tcx, bounds.predicates).map(|o| o.predicate);
904904
assemble_candidates_from_predicates(
905905
selcx,
906906
obligation,
@@ -1162,7 +1162,7 @@ fn confirm_object_candidate<'cx, 'tcx>(
11621162

11631163
// select only those projections that are actually projecting an
11641164
// item with the correct name
1165-
let env_predicates = env_predicates.filter_map(|p| match p {
1165+
let env_predicates = env_predicates.filter_map(|o| match o.predicate {
11661166
ty::Predicate::Projection(data) => {
11671167
if data.projection_def_id() == obligation.predicate.item_def_id {
11681168
Some(data)

src/librustc_trait_selection/traits/wf.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -312,19 +312,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
312312
let item = self.item;
313313

314314
if let Elaborate::All = elaborate {
315-
let predicates = obligations.iter().map(|obligation| obligation.predicate).collect();
316-
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
317-
let implied_obligations = implied_obligations.map(|pred| {
315+
let implied_obligations = traits::util::elaborate_obligations(tcx, obligations.clone());
316+
let implied_obligations = implied_obligations.map(|obligation| {
318317
let mut cause = cause.clone();
319318
extend_cause_with_original_assoc_item_obligation(
320319
tcx,
321320
trait_ref,
322321
item,
323322
&mut cause,
324-
&pred,
323+
&obligation.predicate,
325324
tcx.associated_items(trait_ref.def_id).in_definition_order().copied(),
326325
);
327-
traits::Obligation::new(cause, param_env, pred)
326+
traits::Obligation::new(cause, param_env, obligation.predicate)
328327
});
329328
self.out.extend(implied_obligations);
330329
}
@@ -613,11 +612,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
613612
substs: SubstsRef<'tcx>,
614613
) -> Vec<traits::PredicateObligation<'tcx>> {
615614
let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs);
616-
let cause = self.cause(traits::ItemObligation(def_id));
617615
predicates
618616
.predicates
619617
.into_iter()
620-
.map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred))
618+
.zip(predicates.spans.into_iter())
619+
.map(|(pred, span)| {
620+
let cause = self.cause(traits::BindingObligation(def_id, span));
621+
traits::Obligation::new(cause, self.param_env, pred)
622+
})
621623
.filter(|pred| !pred.has_escaping_bound_vars())
622624
.collect()
623625
}

src/librustc_typeck/astconv.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1601,12 +1601,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16011601
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
16021602
assert_eq!(constness, Constness::NotConst);
16031603

1604-
for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
1604+
for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
16051605
debug!(
16061606
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
1607-
trait_ref
1607+
obligation.predicate
16081608
);
1609-
match trait_ref {
1609+
match obligation.predicate {
16101610
ty::Predicate::Trait(pred, _) => {
16111611
associated_types.entry(span).or_default().extend(
16121612
tcx.associated_items(pred.def_id())

src/librustc_typeck/check/method/confirm.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -573,13 +573,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
573573
};
574574

575575
traits::elaborate_predicates(self.tcx, predicates.predicates.clone())
576-
.filter_map(|predicate| match predicate {
576+
.filter_map(|obligation| match obligation.predicate {
577577
ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
578578
let span = predicates
579579
.predicates
580580
.iter()
581581
.zip(predicates.spans.iter())
582-
.filter_map(|(p, span)| if *p == predicate { Some(*span) } else { None })
582+
.filter_map(
583+
|(p, span)| if *p == obligation.predicate { Some(*span) } else { None },
584+
)
583585
.next()
584586
.unwrap_or(rustc_span::DUMMY_SP);
585587
Some((trait_pred, span))

src/librustc_typeck/check/wfcheck.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,8 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
12291229
// Check elaborated bounds.
12301230
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
12311231

1232-
for pred in implied_obligations {
1232+
for obligation in implied_obligations {
1233+
let pred = obligation.predicate;
12331234
// Match the existing behavior.
12341235
if pred.is_global() && !pred.has_late_bound_regions() {
12351236
let pred = fcx.normalize_associated_types_in(span, &pred);

src/librustc_typeck/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
16501650
// prove that the trait applies to the types that were
16511651
// used, and adding the predicate into this list ensures
16521652
// that this is done.
1653-
let span = tcx.def_span(def_id);
1653+
let span = tcx.sess.source_map().guess_head_span(tcx.def_span(def_id));
16541654
result.predicates =
16551655
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
16561656
ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(),

0 commit comments

Comments
 (0)