33//! of our more general approach to "lazy normalization".
44//!
55//! This is done by first normalizing both sides of the goal, ending up in
6- //! either a concrete type, rigid projection, opaque , or an infer variable.
6+ //! either a concrete type, rigid alias , or an infer variable.
77//! These are related further according to the rules below:
88//!
9- //! (1.) If we end up with a rigid projection and a rigid projection, then we
10- //! relate those projections structurally.
9+ //! (1.) If we end up with two rigid aliases, then we relate them structurally.
1110//!
12- //! (2.) If we end up with a rigid projection and an alias, then the opaque will
13- //! have its hidden type defined to be that rigid projection.
14- //!
15- //! (3.) If we end up with an opaque and an opaque, then we assemble two
16- //! candidates, one defining the LHS to be the hidden type of the RHS, and vice
17- //! versa.
18- //!
19- //! (4.) If we end up with an infer var and an opaque or rigid projection, then
11+ //! (2.) If we end up with an infer var and a rigid alias, then
2012//! we assign the alias to the infer var.
2113//!
22- //! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
23- //! define the hidden type of the opaque to be the rigid type.
24- //!
25- //! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
14+ //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
2615//! relate them structurally.
16+ //!
17+ //! Subtle: when relating an opaque to another type, we emit a
18+ //! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
19+ //! This nested goal starts out as ambiguous and does not actually define the opaque.
20+ //! However, if `?fresh_var` ends up geteting equated to another type, we retry the
21+ //! `NormalizesTo` goal, at which point the opaque is actually defined.
2722
2823use super :: { EvalCtxt , GoalSource } ;
29- use rustc_infer:: infer:: DefineOpaqueTypes ;
3024use rustc_infer:: traits:: query:: NoSolution ;
3125use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
32- use rustc_middle:: ty;
26+ use rustc_middle:: ty:: { self , Ty } ;
3327
3428impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
3529 #[ instrument( level = "debug" , skip( self ) , ret) ]
@@ -59,37 +53,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5953 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
6054 }
6155
62- ( Some ( alias ) , None ) => {
56+ ( Some ( _ ) , None ) => {
6357 if rhs. is_infer ( ) {
6458 self . relate ( param_env, lhs, variance, rhs) ?;
6559 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
66- } else if alias. is_opaque ( tcx) {
67- // FIXME: This doesn't account for variance.
68- self . define_opaque ( param_env, alias, rhs)
6960 } else {
7061 Err ( NoSolution )
7162 }
7263 }
73- ( None , Some ( alias ) ) => {
64+ ( None , Some ( _ ) ) => {
7465 if lhs. is_infer ( ) {
7566 self . relate ( param_env, lhs, variance, rhs) ?;
7667 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
77- } else if alias. is_opaque ( tcx) {
78- // FIXME: This doesn't account for variance.
79- self . define_opaque ( param_env, alias, lhs)
8068 } else {
8169 Err ( NoSolution )
8270 }
8371 }
8472
8573 ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
86- self . relate_rigid_alias_or_opaque ( param_env, alias_lhs, variance, alias_rhs)
74+ self . relate ( param_env, alias_lhs, variance, alias_rhs) ?;
75+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
8776 }
8877 }
8978 }
9079
9180 // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
92- /// Normalize the `term` to equate it later. This does not define opaque types.
81+ /// Normalize the `term` to equate it later.
9382 #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
9483 fn try_normalize_term (
9584 & mut self ,
@@ -98,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
9887 ) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
9988 match term. unpack ( ) {
10089 ty:: TermKind :: Ty ( ty) => {
101- // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
102- Ok ( self
103- . try_normalize_ty_recur ( param_env, DefineOpaqueTypes :: No , 0 , ty)
104- . map ( Into :: into) )
90+ Ok ( self . try_normalize_ty_recur ( param_env, 0 , ty) . map ( Into :: into) )
10591 }
10692 ty:: TermKind :: Const ( _) => {
10793 if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
@@ -119,51 +105,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
119105 }
120106 }
121107
122- fn define_opaque (
108+ fn try_normalize_ty_recur (
123109 & mut self ,
124110 param_env : ty:: ParamEnv < ' tcx > ,
125- opaque : ty:: AliasTy < ' tcx > ,
126- term : ty:: Term < ' tcx > ,
127- ) -> QueryResult < ' tcx > {
128- self . add_goal (
129- GoalSource :: Misc ,
130- Goal :: new ( self . tcx ( ) , param_env, ty:: NormalizesTo { alias : opaque, term } ) ,
131- ) ;
132- self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
133- }
134-
135- fn relate_rigid_alias_or_opaque (
136- & mut self ,
137- param_env : ty:: ParamEnv < ' tcx > ,
138- lhs : ty:: AliasTy < ' tcx > ,
139- variance : ty:: Variance ,
140- rhs : ty:: AliasTy < ' tcx > ,
141- ) -> QueryResult < ' tcx > {
142- let tcx = self . tcx ( ) ;
143- let mut candidates = vec ! [ ] ;
144- if lhs. is_opaque ( tcx) {
145- candidates. extend (
146- self . probe_misc_candidate ( "define-lhs-opaque" )
147- . enter ( |ecx| ecx. define_opaque ( param_env, lhs, rhs. to_ty ( tcx) . into ( ) ) ) ,
148- ) ;
111+ depth : usize ,
112+ ty : Ty < ' tcx > ,
113+ ) -> Option < Ty < ' tcx > > {
114+ if !self . tcx ( ) . recursion_limit ( ) . value_within_limit ( depth) {
115+ return None ;
149116 }
150117
151- if rhs. is_opaque ( tcx) {
152- candidates. extend (
153- self . probe_misc_candidate ( "define-rhs-opaque" )
154- . enter ( |ecx| ecx. define_opaque ( param_env, rhs, lhs. to_ty ( tcx) . into ( ) ) ) ,
155- ) ;
156- }
157-
158- candidates. extend ( self . probe_misc_candidate ( "args-relate" ) . enter ( |ecx| {
159- ecx. relate ( param_env, lhs, variance, rhs) ?;
160- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
161- } ) ) ;
118+ let ty:: Alias ( _, alias) = * ty. kind ( ) else {
119+ return Some ( ty) ;
120+ } ;
162121
163- if let Some ( result) = self . try_merge_responses ( & candidates) {
164- Ok ( result)
165- } else {
166- self . flounder ( & candidates)
122+ match self . commit_if_ok ( |this| {
123+ let normalized_ty = this. next_ty_infer ( ) ;
124+ let normalizes_to_goal = Goal :: new (
125+ this. tcx ( ) ,
126+ param_env,
127+ ty:: NormalizesTo { alias, term : normalized_ty. into ( ) } ,
128+ ) ;
129+ this. add_goal ( GoalSource :: Misc , normalizes_to_goal) ;
130+ this. try_evaluate_added_goals ( ) ?;
131+ let ty = this. resolve_vars_if_possible ( normalized_ty) ;
132+ Ok ( this. try_normalize_ty_recur ( param_env, depth + 1 , ty) )
133+ } ) {
134+ Ok ( ty) => ty,
135+ Err ( NoSolution ) => Some ( ty) ,
167136 }
168137 }
169138}
0 commit comments