Change:
returns if it can't make progress on an inference variable, and the original obligation should be retried later. However, doesn't check that return type and may (incorrectly) return no obligations. On I suggested this: I'm pretty sure now that it would've prevented this bug. <hr/Looking at the users, only uses this function, and only for the user-specified bounds, so it's possible inference variables are impossible to find (unless normalization introduces them, I guess?). It might be fine to just create obligation for the instead of bailing out (see below, this is the same as moving out of ) It's true that can't be found as the first type in the recursive call, but is a , and it uses . (EDIT: Read the code more carefully and the check is , so while it's not an early like I would prefer, it does seem to only trigger on the root type) However, a few other things call and it would be fine for them to create an obligation rather than erroring out, so maybe itself should do that check? cc
changes the return type of to a and discards it using . Might cause us to be slightly more cautious in the future.
I'm working on a fix that makes itself never bail out, so the check is done in , hopefully that will also work nicely for consts. EDIT: opened .

Discussion:
ty: Ty<'tcx>, span: Span, ) -> Option<Vec<traits::PredicateObligation<'tcx>>> { <ins> // Handle the "livelock" case (see comment above) by bailing out if necessary. let ty = match ty.kind { ty::Infer(ty::TyVar(_)) => { let resolved_ty = infcx.shallow_resolve(ty); if resolved_ty == ty { // No progress, bail out to prevent "livelock". return None; } resolved_ty } _ => ty, }; </ins> let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; <del> if wf.compute(ty) { debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); let result = wf.normalize(); debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); Some(result) } else { None // no progress made, return None } </del> <ins> wf.compute(ty); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); let result = wf.normalize(); debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); Some(result) </ins> } /// Returns the obligations that make this trait reference

} } <del> /// Pushes new obligations into `out`. Returns `true` if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { let mut walker = ty0.walk(); </del> <ins> /// Pushes all the predicates needed to validate that `ty` is WF into `out`. fn compute(&mut self, ty: Ty<'tcx>) { let mut walker = ty.walk(); </ins> let param_env = self.param_env; while let Some(arg) = walker.next() { let ty = match arg.unpack() {

// WfScalar, WfParameter, etc } <ins> // Can only infer to `ty::Int(_) | ty::Uint(_)`. ty::Infer(ty::IntVar(_)) => {} // Can only infer to `ty::Float(_)`. ty::Infer(ty::FloatVar(_)) => {} </ins> ty::Slice(subty) => { self.require_sized(subty, traits::SliceOrArrayElem); }

// are not directly inspecting closure types // anyway, except via auto trait matching (which // only inspects the upvar types). <del> walker.skip_current_subtree(); // subtree handled by compute_projection </del> <ins> walker.skip_current_subtree(); // subtree handled below </ins> for upvar_ty in substs.as_closure().upvar_tys() { <ins> // FIXME(eddyb) add the type to `walker` instead of recursing. </ins> self.compute(upvar_ty); } }

// // 1. Check if they have been resolved, and if so proceed with //    THAT type. <del> // 2. If not, check whether this is the type that we //    started with (ty0). In that case, we've made no //    progress at all, so return false. Otherwise, //    we've at least simplified things (i.e., we went //    from `Vec<$0>: WF` to `$0: WF`, so we can </del> <ins> // 2. If not, we've at least simplified things (e.g., we went //    from `Vec<$0>: WF` to `$0: WF`), so we can </ins> //    register a pending obligation and keep //    moving. (Goal is that an "inductive hypothesis" //    is satisfied to ensure termination.) <ins> // See also the comment on `fn obligations`, describing "livelock" // prevention, which happens before this can be reached. </ins> ty::Infer(_) => { let ty = self.infcx.shallow_resolve(ty); <del> if let ty::Infer(_) = ty.kind { // not yet resolved... if ty == ty0 { // ...this is the type we started from! no progress. return false; } </del> <ins> if let ty::Infer(ty::TyVar(_)) = ty.kind { // Not yet resolved, but we've made progress. </ins> let cause = self.cause(traits::MiscObligation); <del> self.out.push( // ...not the type we started from, so we made progress. traits::Obligation::new( cause, self.param_env, ty::Predicate::WellFormed(ty), ), ); </del> <ins> self.out.push(traits::Obligation::new( cause, param_env, ty::Predicate::WellFormed(ty), )); </ins> } else { <del> // Yes, resolved, proceed with the // result. Should never return false because // `ty` is not a Infer. assert!(self.compute(ty)); </del> <ins> // Yes, resolved, proceed with the result. // FIXME(eddyb) add the type to `walker` instead of recursing. self.compute(ty); </ins> } } } } <del> // if we made it through that loop above, we made progress! true </del> } fn nominal_obligations(