Skip to content

Commit bd7ea54

Browse files
committed
Use PredicateObligations instead of Predicates
Keep more information about trait binding failures.
1 parent 485c5fb commit bd7ea54

File tree

90 files changed

+280
-141
lines changed

Some content is hidden

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

90 files changed

+280
-141
lines changed

src/librustc_infer/infer/outlives/verify.rs

Lines changed: 4 additions & 1 deletion
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

Lines changed: 48 additions & 20 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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,7 @@ 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() && !snippet.ends_with('>') {
13911391
// FIXME: To avoid spurious suggestions in functions where type arguments
13921392
// where already supplied, we check the snippet to make sure it doesn't
13931393
// end with a turbofish. Ideally we would have access to a `PathSegment`

src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs

Lines changed: 3 additions & 1 deletion
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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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,9 @@ 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+
if !ident.span.overlaps(span) {
1360+
err.span_label(ident.span, "");
1361+
}
13611362
}
13621363
if span != DUMMY_SP {
13631364
err.span_label(span, &msg);

src/librustc_trait_selection/traits/mod.rs

Lines changed: 3 additions & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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
}

0 commit comments

Comments
 (0)