@@ -22,9 +22,13 @@ mod search_graph;
2222mod trait_goals;
2323
2424use derive_where:: derive_where;
25+ use rustc_type_ir:: data_structures:: ensure_sufficient_stack;
2526use rustc_type_ir:: inherent:: * ;
2627pub use rustc_type_ir:: solve:: * ;
27- use rustc_type_ir:: { self as ty, Interner , TyVid , TypingMode } ;
28+ use rustc_type_ir:: {
29+ self as ty, FallibleTypeFolder , Interner , TyVid , TypeFoldable , TypeSuperFoldable ,
30+ TypeVisitableExt , TypingMode ,
31+ } ;
2832use tracing:: instrument;
2933
3034pub use self :: eval_ctxt:: {
9195 goal : Goal < I , ty:: OutlivesPredicate < I , I :: Ty > > ,
9296 ) -> QueryResult < I > {
9397 let ty:: OutlivesPredicate ( ty, lt) = goal. predicate ;
98+
99+ // With `-Znext-solver`, `TypeOutlives` goals normalize aliases before registering region
100+ // obligations so that later processing does not have to structurally process aliases.
101+ let ty = self . resolve_vars_if_possible ( ty) ;
102+ let ty = if ty. has_aliases ( ) {
103+ self . deeply_normalize_for_outlives ( goal. param_env , ty)
104+ } else {
105+ ty
106+ } ;
94107 self . register_ty_outlives ( ty, lt) ;
95108 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
96109 }
@@ -306,6 +319,131 @@ where
306319 }
307320 }
308321
322+ /// This is the solver-internal equivalent of the `deeply_normalize` helper in
323+ /// `compiler/rustc_trait_selection/src/solve/normalize.rs`.
324+ fn deeply_normalize_for_outlives ( & mut self , param_env : I :: ParamEnv , ty : I :: Ty ) -> I :: Ty {
325+ debug_assert ! ( ty. has_aliases( ) ) ;
326+
327+ // We only use this for `TypeOutlives` goals,
328+ // so the input should not have escaping bound vars.
329+ debug_assert ! (
330+ !ty. has_escaping_bound_vars( ) ,
331+ "expected `TypeOutlives` ty to not have escaping bound vars: {ty:?}"
332+ ) ;
333+
334+ struct DeepNormalizer < ' ecx , ' a , D , I >
335+ where
336+ D : SolverDelegate < Interner = I > ,
337+ I : Interner ,
338+ {
339+ ecx : & ' ecx mut EvalCtxt < ' a , D , I > ,
340+ param_env : I :: ParamEnv ,
341+ depth : usize ,
342+ }
343+
344+ impl < D , I > DeepNormalizer < ' _ , ' _ , D , I >
345+ where
346+ D : SolverDelegate < Interner = I > ,
347+ I : Interner ,
348+ {
349+ fn normalize_alias_term ( & mut self , alias_term : I :: Term ) -> Result < I :: Term , NoSolution > {
350+ debug_assert ! ( alias_term. to_alias_term( ) . is_some( ) ) ;
351+
352+ if alias_term. has_non_region_infer ( ) || alias_term. has_non_region_placeholders ( ) {
353+ return match alias_term. kind ( ) {
354+ ty:: TermKind :: Ty ( ty) => Ok ( ty. try_super_fold_with ( self ) ?. into ( ) ) ,
355+ ty:: TermKind :: Const ( ct) => Ok ( ct. try_super_fold_with ( self ) ?. into ( ) ) ,
356+ } ;
357+ }
358+
359+ // Avoid getting stuck on self-referential normalization.
360+ if self . depth >= self . ecx . cx ( ) . recursion_limit ( ) {
361+ return match alias_term. kind ( ) {
362+ ty:: TermKind :: Ty ( ty) => Ok ( ty. try_super_fold_with ( self ) ?. into ( ) ) ,
363+ ty:: TermKind :: Const ( ct) => Ok ( ct. try_super_fold_with ( self ) ?. into ( ) ) ,
364+ } ;
365+ }
366+
367+ self . depth += 1 ;
368+
369+ let normalized_term = self . ecx . next_term_infer_of_kind ( alias_term) ;
370+ let goal = Goal :: new (
371+ self . ecx . cx ( ) ,
372+ self . param_env ,
373+ ty:: PredicateKind :: AliasRelate (
374+ alias_term,
375+ normalized_term,
376+ ty:: AliasRelationDirection :: Equate ,
377+ ) ,
378+ ) ;
379+
380+ let result = match self . ecx . try_evaluate_goal ( GoalSource :: TypeRelating , goal) {
381+ Ok ( GoalEvaluation { certainty : Certainty :: Yes , .. } ) => {
382+ // Resolve the fresh term and continue normalization recursively.
383+ let term = self . ecx . resolve_vars_if_possible ( normalized_term) ;
384+ match term. kind ( ) {
385+ ty:: TermKind :: Ty ( ty) => ty. try_super_fold_with ( self ) ?. into ( ) ,
386+ ty:: TermKind :: Const ( ct) => ct. try_super_fold_with ( self ) ?. into ( ) ,
387+ }
388+ }
389+ Ok ( GoalEvaluation { certainty : Certainty :: Maybe { .. } , .. } )
390+ | Err ( NoSolution ) => {
391+ // If normalizing this alias isn't possible right now, keep it and continue
392+ // folding inside of it.
393+ match alias_term. kind ( ) {
394+ ty:: TermKind :: Ty ( ty) => ty. try_super_fold_with ( self ) ?. into ( ) ,
395+ ty:: TermKind :: Const ( ct) => ct. try_super_fold_with ( self ) ?. into ( ) ,
396+ }
397+ }
398+ } ;
399+
400+ self . depth -= 1 ;
401+ Ok ( result)
402+ }
403+ }
404+
405+ impl < D , I > FallibleTypeFolder < I > for DeepNormalizer < ' _ , ' _ , D , I >
406+ where
407+ D : SolverDelegate < Interner = I > ,
408+ I : Interner ,
409+ {
410+ type Error = NoSolution ;
411+
412+ fn cx ( & self ) -> I {
413+ self . ecx . cx ( )
414+ }
415+
416+ #[ instrument( level = "trace" , skip( self ) , ret) ]
417+ fn try_fold_ty ( & mut self , ty : I :: Ty ) -> Result < I :: Ty , Self :: Error > {
418+ let ty = self . ecx . shallow_resolve ( ty) ;
419+ if !ty. has_aliases ( ) {
420+ return Ok ( ty) ;
421+ }
422+
423+ let ty:: Alias ( ..) = ty. kind ( ) else { return ty. try_super_fold_with ( self ) } ;
424+ let term = ensure_sufficient_stack ( || self . normalize_alias_term ( ty. into ( ) ) ) ?;
425+ Ok ( term. expect_ty ( ) )
426+ }
427+
428+ #[ instrument( level = "trace" , skip( self ) , ret) ]
429+ fn try_fold_const ( & mut self , ct : I :: Const ) -> Result < I :: Const , Self :: Error > {
430+ let ct = self . ecx . shallow_resolve_const ( ct) ;
431+ if !ct. has_aliases ( ) {
432+ return Ok ( ct) ;
433+ }
434+
435+ let ty:: ConstKind :: Unevaluated ( ..) = ct. kind ( ) else {
436+ return ct. try_super_fold_with ( self ) ;
437+ } ;
438+
439+ let term = ensure_sufficient_stack ( || self . normalize_alias_term ( ct. into ( ) ) ) ?;
440+ Ok ( term. expect_const ( ) )
441+ }
442+ }
443+
444+ ty. try_fold_with ( & mut DeepNormalizer { ecx : self , param_env, depth : 0 } ) . unwrap ( )
445+ }
446+
309447 /// Normalize a type for when it is structurally matched on.
310448 ///
311449 /// This function is necessary in nearly all cases before matching on a type.
0 commit comments