@@ -166,74 +166,77 @@ fn insert_required_predicates_to_be_wf<'tcx>(
166166 debug ! ( "Adt" ) ;
167167 if let Some ( unsubstituted_predicates) = global_inferred_outlives. get ( & adt. did ( ) ) {
168168 for ( unsubstituted_predicate, stack) in & unsubstituted_predicates. 0 {
169- // `unsubstituted_predicate` is `U: 'b` in the
170- // example above. So apply the substitution to
171- // get `T: 'a` (or `predicate`):
172- let predicate = unsubstituted_predicates
173- . rebind ( * unsubstituted_predicate)
174- . subst ( tcx, substs) ;
175-
176169 // We must detect cycles in the inference. If we don't, rustc can hang.
177170 // Cycles can be formed by associated types on traits when they are used like so:
178171 //
179172 // ```
180- // trait Trait<'a> { type Assoc: 'a; }
181- // struct Node<'node, T: Trait<'node>>(Var<'node, T::Assoc>, Option<T::Assoc>);
173+ // trait Trait<'a> {
174+ // type Assoc: 'a;
175+ // }
176+ // struct Node<'node, T: Trait<'node>> {
177+ // var: Var<'node, T::Assoc>,
178+ // }
179+ // struct Var<'var, R: 'var> {
180+ // node: Box<Node<'var, RGen<R>>>,
181+ // }
182182 // struct RGen<R>(std::marker::PhantomData<R>);
183- // impl<'a, R: 'a> Trait<'a> for RGen<R> { type Assoc = R; }
184- // struct Var<'var, R: 'var>(Box<Node<'var, RGen<R>>>);
183+ // impl<'a, R: 'a> Trait<'a> for RGen<R> {
184+ // type Assoc = R; // works with () too
185+ // }
185186 // ```
186187 //
187188 // Visiting Node, we walk the fields and find a Var. Var has an explicit
188189 // R : 'var.
189- // Node finds this on its Var field, substitutes through, and gets an inferred
190+ // Node finds this in check_explicit_predicates.
191+ // Node substitutes its type parameters for Var through, and gets an inferred
190192 // <T as Trait<'node>>::Assoc: 'node.
191- // Visiting Var, we walk the fields and find a Node. So Var then picks up
192- // Node's new inferred predicate (in global_inferred_outlives) and substitutes
193- // the types it passed to Node ('var for 'node, RGen<R> for T).
194- // So Var gets
193+ // Visiting Var, we walk the fields and find Node, for which there us an
194+ // unsubstituted predicate in the global map. So Var gets
195195 // <RGen<R> as Trait<'var>>::Assoc: 'var
196196 // But Node contains a Var. So Node gets
197197 // <RGen<<T as Trait<'node>>::Assoc> as Trait<'node>>::Assoc 'node
198198 // Var gets
199199 // <RGen<<RGen<R> as Trait<'var>>::Assoc> as Trait<'var>>::Assoc: 'var
200- // Etc. This goes on forever.
201200 //
202- // We cut off the cycle formation by tracking in a stack the defs that
203- // have picked up a substituted predicate each time we produce an edge,
204- // and don't insert a predicate that is simply a substituted version of
205- // one we've already seen and added.
201+ // Etc. This goes on forever. The fact that RGen<R>::Assoc *is* R is
202+ // irrelevant. It is simply that both types find a way to add a bigger
203+ // predicate each time.
204+ //
205+ // The outlives requirements propagate through the crate's types like a
206+ // graph walk, so to detect this cycle we can just track visited nodes in
207+ // our branch by pushing them on a stack when we move through the graph.
208+ // An edge move is when a type picks up a predicate from one of its fields
209+ // that it hasn't seen before. We store the stacks alongside the predicates,
210+ // so they carry their provenance with them through the current and
211+ // subsequent rounds of crate-wide inference.
206212 //
207213 // Try: RUSTC_LOG=rustc_hir_analysis::outlives=debug \
208- // rustc +stage1 src/test/ui/typeck /issue-102966.rs 2>&1 \
214+ // rustc +stage1 src/test/ui/rfc-2093-infer-outlives /issue-102966.rs 2>&1 \
209215 // | rg '(grew|cycle)'
210216 //
211- // We do not currently treat a type with an explicit bound as the first
212- // in the visit stack. So Var here does not appear first in the stack,
213- // Node does, and each of Node and Var will get a version of
214- // `<RGen<R> as Trait<'node>>::Assoc: 'node` before the cycle is cut at
215- // Node. This avoids having a second equivalent bound on Node, and also
216- // having RGen involved in Node's predicates (which would be silly).
217- //
218- // It is not clear whether cyclically-substituted versions of bounds we
219- // already have are always redundant/unnecessary to add to Self.
220- // This solution avoids digging into `impl Trait for RGen` to find that it
221- // unifies with an existing bound but it is really a guess that this
222- // cyclic substitution cannot add valuable information. There may be
223- // situations when an error is appropriate.
217+ // We do not treat a type with an explicit bound as the first in the visit
218+ // stack. So in the example, Node appears first in the stack, and each of
219+ // Node and Var will get a new bound constraining an ::Assoc projection
220+ // before the cycle is cut at Node. If Var were already in the visit stack,
221+ // it would not receive the projection bound, which is something it needs.
222+
224223 if stack. iter ( ) . any ( |& ( did, _span) | did == self_did) {
225224 debug ! (
226225 "detected cycle in inferred_outlives_predicates,\
227226 for unsubstituted predicate {unsubstituted_predicate:?}:\
228227 {self_did:?} found in {stack:?}"
229228 ) ;
230229 } else {
230+ // `unsubstituted_predicate` is `U: 'b` in Example 1 above.
231+ // So apply the substitution to get `T: 'a` (or `predicate`):
232+ let predicate = unsubstituted_predicates
233+ . rebind ( * unsubstituted_predicate)
234+ . subst ( tcx, substs) ;
235+
231236 insert_outlives_predicate (
232237 tcx,
233238 predicate. 0 ,
234239 predicate. 1 ,
235- // Treat the top-level definition we are currently walking the fields of as the
236- // type visited in the DefStack. Not the field type.
237240 self_did,
238241 field_span,
239242 required_predicates,
0 commit comments