11
11
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
12
12
//! may apply, then we can compute the "intersection" of both normalizes-to by
13
13
//! performing them together. This is used specifically to resolve ambiguities.
14
- use super :: { EvalCtxt , SolverMode } ;
14
+ use super :: EvalCtxt ;
15
+ use rustc_infer:: infer:: DefineOpaqueTypes ;
15
16
use rustc_infer:: traits:: query:: NoSolution ;
16
17
use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
17
18
use rustc_middle:: ty;
18
19
19
- /// We may need to invert the alias relation direction if dealing an alias on the RHS.
20
- #[ derive( Debug ) ]
21
- enum Invert {
22
- No ,
23
- Yes ,
24
- }
25
-
26
20
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
27
21
#[ instrument( level = "debug" , skip( self ) , ret) ]
28
22
pub ( super ) fn compute_alias_relate_goal (
@@ -31,187 +25,130 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
31
25
) -> QueryResult < ' tcx > {
32
26
let tcx = self . tcx ( ) ;
33
27
let Goal { param_env, predicate : ( lhs, rhs, direction) } = goal;
34
- if lhs. is_infer ( ) || rhs. is_infer ( ) {
35
- bug ! (
36
- "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
37
- ) ;
38
- }
39
-
40
- match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
41
- ( None , None ) => bug ! ( "`AliasRelate` goal without an alias on either lhs or rhs" ) ,
42
28
43
- // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
44
- ( Some ( alias_lhs) , None ) => self . assemble_normalizes_to_candidate (
45
- param_env,
46
- alias_lhs,
47
- rhs,
48
- direction,
49
- Invert :: No ,
50
- ) ,
29
+ let Some ( lhs) = self . try_normalize_term ( param_env, lhs) ? else {
30
+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
31
+ } ;
51
32
52
- // LHS is not a projection, only way this is true is if RHS normalizes-to LHS
53
- ( None , Some ( alias_rhs) ) => self . assemble_normalizes_to_candidate (
54
- param_env,
55
- alias_rhs,
56
- lhs,
57
- direction,
58
- Invert :: Yes ,
59
- ) ,
33
+ let Some ( rhs) = self . try_normalize_term ( param_env, rhs) ? else {
34
+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
35
+ } ;
60
36
61
- ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
62
- debug ! ( "both sides are aliases" ) ;
37
+ let variance = match direction {
38
+ ty:: AliasRelationDirection :: Equate => ty:: Variance :: Invariant ,
39
+ ty:: AliasRelationDirection :: Subtype => ty:: Variance :: Covariant ,
40
+ } ;
63
41
64
- let mut candidates = Vec :: new ( ) ;
65
- // LHS normalizes-to RHS
66
- candidates. extend ( self . assemble_normalizes_to_candidate (
67
- param_env,
68
- alias_lhs,
69
- rhs,
70
- direction,
71
- Invert :: No ,
72
- ) ) ;
73
- // RHS normalizes-to RHS
74
- candidates. extend ( self . assemble_normalizes_to_candidate (
75
- param_env,
76
- alias_rhs,
77
- lhs,
78
- direction,
79
- Invert :: Yes ,
80
- ) ) ;
81
- // Relate via args
82
- candidates. extend (
83
- self . assemble_subst_relate_candidate (
84
- param_env, alias_lhs, alias_rhs, direction,
85
- ) ,
86
- ) ;
87
- debug ! ( ?candidates) ;
42
+ match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
43
+ ( None , None ) => {
44
+ self . relate ( param_env, lhs, variance, rhs) ?;
45
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
46
+ }
88
47
89
- if let Some ( merged) = self . try_merge_responses ( & candidates) {
90
- Ok ( merged)
48
+ ( Some ( alias) , None ) => {
49
+ if rhs. is_infer ( ) {
50
+ self . relate ( param_env, lhs, variance, rhs) ?;
51
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
52
+ } else if alias. is_opaque ( tcx) {
53
+ self . define_opaque ( param_env, alias, rhs)
91
54
} else {
92
- // When relating two aliases and we have ambiguity, if both
93
- // aliases can be normalized to something, we prefer
94
- // "bidirectionally normalizing" both of them within the same
95
- // candidate.
96
- //
97
- // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/25>.
98
- //
99
- // As this is incomplete, we must not do so during coherence.
100
- match self . solver_mode ( ) {
101
- SolverMode :: Normal => {
102
- if let Ok ( bidirectional_normalizes_to_response) = self
103
- . assemble_bidirectional_normalizes_to_candidate (
104
- param_env, lhs, rhs, direction,
105
- )
106
- {
107
- Ok ( bidirectional_normalizes_to_response)
108
- } else {
109
- self . flounder ( & candidates)
110
- }
111
- }
112
- SolverMode :: Coherence => self . flounder ( & candidates) ,
113
- }
55
+ Err ( NoSolution )
114
56
}
115
57
}
58
+ ( None , Some ( alias) ) => {
59
+ if lhs. is_infer ( ) {
60
+ self . relate ( param_env, lhs, variance, rhs) ?;
61
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
62
+ } else if alias. is_opaque ( tcx) {
63
+ self . define_opaque ( param_env, alias, lhs)
64
+ } else {
65
+ Err ( NoSolution )
66
+ }
67
+ }
68
+
69
+ ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
70
+ self . relate_rigid_alias_or_opaque ( param_env, alias_lhs, variance, alias_rhs)
71
+ }
116
72
}
117
73
}
118
74
119
- #[ instrument( level = "debug" , skip( self ) , ret) ]
120
- fn assemble_normalizes_to_candidate (
75
+ /// Normalize the `term` to equate it later. This does not define opaque types.
76
+ #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
77
+ fn try_normalize_term (
121
78
& mut self ,
122
79
param_env : ty:: ParamEnv < ' tcx > ,
123
- alias : ty:: AliasTy < ' tcx > ,
124
- other : ty:: Term < ' tcx > ,
125
- direction : ty:: AliasRelationDirection ,
126
- invert : Invert ,
127
- ) -> QueryResult < ' tcx > {
128
- self . probe_misc_candidate ( "normalizes-to" ) . enter ( |ecx| {
129
- ecx. normalizes_to_inner ( param_env, alias, other, direction, invert) ?;
130
- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
131
- } )
80
+ term : ty:: Term < ' tcx > ,
81
+ ) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
82
+ match term. unpack ( ) {
83
+ ty:: TermKind :: Ty ( ty) => {
84
+ // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
85
+ Ok ( self
86
+ . try_normalize_ty_recur ( param_env, DefineOpaqueTypes :: No , 0 , ty)
87
+ . map ( Into :: into) )
88
+ }
89
+ ty:: TermKind :: Const ( _) => {
90
+ if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
91
+ let term = self . next_term_infer_of_kind ( term) ;
92
+ self . add_goal ( Goal :: new (
93
+ self . tcx ( ) ,
94
+ param_env,
95
+ ty:: ProjectionPredicate { projection_ty : alias, term } ,
96
+ ) ) ;
97
+ self . try_evaluate_added_goals ( ) ?;
98
+ Ok ( Some ( self . resolve_vars_if_possible ( term) ) )
99
+ } else {
100
+ Ok ( Some ( term) )
101
+ }
102
+ }
103
+ }
132
104
}
133
105
134
- // Computes the normalizes-to branch, with side-effects. This must be performed
135
- // in a probe in order to not taint the evaluation context.
136
- fn normalizes_to_inner (
106
+ fn define_opaque (
137
107
& mut self ,
138
108
param_env : ty:: ParamEnv < ' tcx > ,
139
- alias : ty:: AliasTy < ' tcx > ,
140
- other : ty:: Term < ' tcx > ,
141
- direction : ty:: AliasRelationDirection ,
142
- invert : Invert ,
143
- ) -> Result < ( ) , NoSolution > {
144
- let other = match direction {
145
- // This is purely an optimization. No need to instantiate a new
146
- // infer var and equate the RHS to it.
147
- ty:: AliasRelationDirection :: Equate => other,
148
-
149
- // Instantiate an infer var and subtype our RHS to it, so that we
150
- // properly represent a subtype relation between the LHS and RHS
151
- // of the goal.
152
- ty:: AliasRelationDirection :: Subtype => {
153
- let fresh = self . next_term_infer_of_kind ( other) ;
154
- let ( sub, sup) = match invert {
155
- Invert :: No => ( fresh, other) ,
156
- Invert :: Yes => ( other, fresh) ,
157
- } ;
158
- self . sub ( param_env, sub, sup) ?;
159
- fresh
160
- }
161
- } ;
109
+ opaque : ty:: AliasTy < ' tcx > ,
110
+ term : ty:: Term < ' tcx > ,
111
+ ) -> QueryResult < ' tcx > {
162
112
self . add_goal ( Goal :: new (
163
113
self . tcx ( ) ,
164
114
param_env,
165
- ty:: ProjectionPredicate { projection_ty : alias , term : other } ,
115
+ ty:: ProjectionPredicate { projection_ty : opaque , term } ,
166
116
) ) ;
167
-
168
- Ok ( ( ) )
117
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
169
118
}
170
119
171
- fn assemble_subst_relate_candidate (
120
+ fn relate_rigid_alias_or_opaque (
172
121
& mut self ,
173
122
param_env : ty:: ParamEnv < ' tcx > ,
174
- alias_lhs : ty:: AliasTy < ' tcx > ,
175
- alias_rhs : ty:: AliasTy < ' tcx > ,
176
- direction : ty:: AliasRelationDirection ,
123
+ lhs : ty:: AliasTy < ' tcx > ,
124
+ variance : ty:: Variance ,
125
+ rhs : ty:: AliasTy < ' tcx > ,
177
126
) -> QueryResult < ' tcx > {
178
- self . probe_misc_candidate ( "args relate" ) . enter ( |ecx| {
179
- match direction {
180
- ty:: AliasRelationDirection :: Equate => {
181
- ecx. eq ( param_env, alias_lhs, alias_rhs) ?;
182
- }
183
- ty:: AliasRelationDirection :: Subtype => {
184
- ecx. sub ( param_env, alias_lhs, alias_rhs) ?;
185
- }
186
- }
127
+ let tcx = self . tcx ( ) ;
128
+ let mut candidates = vec ! [ ] ;
129
+ if lhs. is_opaque ( tcx) {
130
+ candidates. extend (
131
+ self . probe_misc_candidate ( "define-lhs-opaque" )
132
+ . enter ( |ecx| ecx. define_opaque ( param_env, lhs, rhs. to_ty ( tcx) . into ( ) ) ) ,
133
+ ) ;
134
+ }
187
135
188
- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
189
- } )
190
- }
136
+ if rhs. is_opaque ( tcx) {
137
+ candidates. extend (
138
+ self . probe_misc_candidate ( "define-rhs-opaque" )
139
+ . enter ( |ecx| ecx. define_opaque ( param_env, rhs, lhs. to_ty ( tcx) . into ( ) ) ) ,
140
+ ) ;
141
+ }
191
142
192
- fn assemble_bidirectional_normalizes_to_candidate (
193
- & mut self ,
194
- param_env : ty:: ParamEnv < ' tcx > ,
195
- lhs : ty:: Term < ' tcx > ,
196
- rhs : ty:: Term < ' tcx > ,
197
- direction : ty:: AliasRelationDirection ,
198
- ) -> QueryResult < ' tcx > {
199
- self . probe_misc_candidate ( "bidir normalizes-to" ) . enter ( |ecx| {
200
- ecx. normalizes_to_inner (
201
- param_env,
202
- lhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
203
- rhs,
204
- direction,
205
- Invert :: No ,
206
- ) ?;
207
- ecx. normalizes_to_inner (
208
- param_env,
209
- rhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
210
- lhs,
211
- direction,
212
- Invert :: Yes ,
213
- ) ?;
143
+ candidates. extend ( self . probe_misc_candidate ( "args-relate" ) . enter ( |ecx| {
144
+ ecx. relate ( param_env, lhs, variance, rhs) ?;
214
145
ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
215
- } )
146
+ } ) ) ;
147
+
148
+ if let Some ( result) = self . try_merge_responses ( & candidates) {
149
+ Ok ( result)
150
+ } else {
151
+ self . flounder ( & candidates)
152
+ }
216
153
}
217
154
}
0 commit comments