3
3
//! of our more general approach to "lazy normalization".
4
4
//!
5
5
//! 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.
7
7
//! These are related further according to the rules below:
8
8
//!
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.
11
10
//!
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
20
12
//! we assign the alias to the infer var.
21
13
//!
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,
26
15
//! 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.
27
22
28
23
use super :: { EvalCtxt , GoalSource } ;
29
- use rustc_infer:: infer:: DefineOpaqueTypes ;
30
24
use rustc_infer:: traits:: query:: NoSolution ;
31
25
use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
32
- use rustc_middle:: ty;
26
+ use rustc_middle:: ty:: { self , Ty } ;
33
27
34
28
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
35
29
#[ instrument( level = "debug" , skip( self ) , ret) ]
@@ -59,37 +53,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
59
53
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
60
54
}
61
55
62
- ( Some ( alias ) , None ) => {
56
+ ( Some ( _ ) , None ) => {
63
57
if rhs. is_infer ( ) {
64
58
self . relate ( param_env, lhs, variance, rhs) ?;
65
59
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)
69
60
} else {
70
61
Err ( NoSolution )
71
62
}
72
63
}
73
- ( None , Some ( alias ) ) => {
64
+ ( None , Some ( _ ) ) => {
74
65
if lhs. is_infer ( ) {
75
66
self . relate ( param_env, lhs, variance, rhs) ?;
76
67
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)
80
68
} else {
81
69
Err ( NoSolution )
82
70
}
83
71
}
84
72
85
73
( 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 )
87
76
}
88
77
}
89
78
}
90
79
91
80
// 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.
93
82
#[ instrument( level = "debug" , skip( self , param_env) , ret) ]
94
83
fn try_normalize_term (
95
84
& mut self ,
@@ -98,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
98
87
) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
99
88
match term. unpack ( ) {
100
89
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) )
105
91
}
106
92
ty:: TermKind :: Const ( _) => {
107
93
if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
@@ -119,51 +105,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
119
105
}
120
106
}
121
107
122
- fn define_opaque (
108
+ fn try_normalize_ty_recur (
123
109
& mut self ,
124
110
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 ;
149
116
}
150
117
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
+ } ;
162
121
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) ,
167
136
}
168
137
}
169
138
}
0 commit comments