Skip to content

Commit d1dc2af

Browse files
committed
wf: handle "livelock" checking before reaching WfPredicates::compute.
1 parent eece58a commit d1dc2af

File tree

1 file changed

+38
-42
lines changed
  • src/librustc_trait_selection/traits

1 file changed

+38
-42
lines changed

src/librustc_trait_selection/traits/wf.rs

+38-42
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,27 @@ pub fn obligations<'a, 'tcx>(
2222
ty: Ty<'tcx>,
2323
span: Span,
2424
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
25+
// Handle the "livelock" case (see comment above) by bailing out if necessary.
26+
let ty = match ty.kind {
27+
ty::Infer(_) => {
28+
let resolved_ty = infcx.shallow_resolve(ty);
29+
if resolved_ty == ty {
30+
// No progress, bail out to prevent "livelock".
31+
return None;
32+
}
33+
34+
resolved_ty
35+
}
36+
_ => ty,
37+
};
38+
2539
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
26-
if wf.compute(ty) {
27-
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
28-
29-
let result = wf.normalize();
30-
debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
31-
Some(result)
32-
} else {
33-
None // no progress made, return None
34-
}
40+
wf.compute(ty);
41+
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
42+
43+
let result = wf.normalize();
44+
debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
45+
Some(result)
3546
}
3647

3748
/// Returns the obligations that make this trait reference
@@ -311,12 +322,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
311322
}
312323
}
313324

314-
/// Pushes new obligations into `out`. Returns `true` if it was able
315-
/// to generate all the predicates needed to validate that `ty0`
316-
/// is WF. Returns false if `ty0` is an unresolved type variable,
317-
/// in which case we are not able to simplify at all.
318-
fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
319-
let mut walker = ty0.walk();
325+
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
326+
fn compute(&mut self, ty: Ty<'tcx>) {
327+
let mut walker = ty.walk();
320328
let param_env = self.param_env;
321329
while let Some(arg) = walker.next() {
322330
let ty = match arg.unpack() {
@@ -442,8 +450,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
442450
// are not directly inspecting closure types
443451
// anyway, except via auto trait matching (which
444452
// only inspects the upvar types).
445-
walker.skip_current_subtree(); // subtree handled by compute_projection
453+
walker.skip_current_subtree(); // subtree handled below
446454
for upvar_ty in substs.as_closure().upvar_tys() {
455+
// FIXME(eddyb) add the type to `walker` instead of recursing.
447456
self.compute(upvar_ty);
448457
}
449458
}
@@ -496,44 +505,31 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
496505
//
497506
// 1. Check if they have been resolved, and if so proceed with
498507
// THAT type.
499-
// 2. If not, check whether this is the type that we
500-
// started with (ty0). In that case, we've made no
501-
// progress at all, so return false. Otherwise,
502-
// we've at least simplified things (i.e., we went
503-
// from `Vec<$0>: WF` to `$0: WF`, so we can
508+
// 2. If not, we've at least simplified things (e.g., we went
509+
// from `Vec<$0>: WF` to `$0: WF`), so we can
504510
// register a pending obligation and keep
505511
// moving. (Goal is that an "inductive hypothesis"
506512
// is satisfied to ensure termination.)
513+
// See also the comment on `fn obligations`, describing "livelock"
514+
// prevention, which happens before this can be reached.
507515
ty::Infer(_) => {
508516
let ty = self.infcx.shallow_resolve(ty);
509517
if let ty::Infer(_) = ty.kind {
510-
// not yet resolved...
511-
if ty == ty0 {
512-
// ...this is the type we started from! no progress.
513-
return false;
514-
}
515-
518+
// Not yet resolved, but we've made progress.
516519
let cause = self.cause(traits::MiscObligation);
517-
self.out.push(
518-
// ...not the type we started from, so we made progress.
519-
traits::Obligation::new(
520-
cause,
521-
self.param_env,
522-
ty::Predicate::WellFormed(ty),
523-
),
524-
);
520+
self.out.push(traits::Obligation::new(
521+
cause,
522+
param_env,
523+
ty::Predicate::WellFormed(ty),
524+
));
525525
} else {
526-
// Yes, resolved, proceed with the
527-
// result. Should never return false because
528-
// `ty` is not a Infer.
529-
assert!(self.compute(ty));
526+
// Yes, resolved, proceed with the result.
527+
// FIXME(eddyb) add the type to `walker` instead of recursing.
528+
self.compute(ty);
530529
}
531530
}
532531
}
533532
}
534-
535-
// if we made it through that loop above, we made progress!
536-
true
537533
}
538534

539535
fn nominal_obligations(

0 commit comments

Comments
 (0)