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
15
use rustc_infer:: traits:: query:: NoSolution ;
16
16
use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
17
17
use rustc_middle:: ty;
18
18
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
19
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
27
20
#[ instrument( level = "debug" , skip( self ) , ret) ]
28
21
pub ( super ) fn compute_alias_relate_goal (
@@ -31,187 +24,72 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
31
24
) -> QueryResult < ' tcx > {
32
25
let tcx = self . tcx ( ) ;
33
26
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
27
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
- ) ,
28
+ let Some ( lhs) = self . try_normalize_term ( param_env, lhs) ? else {
29
+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
30
+ } ;
51
31
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
- ) ,
32
+ let Some ( rhs) = self . try_normalize_term ( param_env, rhs) ? else {
33
+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
34
+ } ;
60
35
61
- ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
62
- debug ! ( "both sides are aliases" ) ;
36
+ let variance = match direction {
37
+ ty:: AliasRelationDirection :: Equate => ty:: Variance :: Invariant ,
38
+ ty:: AliasRelationDirection :: Subtype => ty:: Variance :: Covariant ,
39
+ } ;
63
40
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) ;
41
+ match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
42
+ ( None , None ) => {
43
+ self . relate ( param_env, lhs, variance, rhs) ?;
44
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
45
+ }
88
46
89
- if let Some ( merged) = self . try_merge_responses ( & candidates) {
90
- Ok ( merged)
47
+ ( Some ( _) , None ) => {
48
+ if rhs. is_infer ( ) {
49
+ self . relate ( param_env, lhs, variance, rhs) ?;
50
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
91
51
} 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
- }
52
+ Err ( NoSolution )
114
53
}
115
54
}
116
- }
117
- }
118
-
119
- #[ instrument( level = "debug" , skip( self ) , ret) ]
120
- fn assemble_normalizes_to_candidate (
121
- & mut self ,
122
- 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
- } )
132
- }
133
-
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 (
137
- & mut self ,
138
- 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
55
+ ( None , Some ( _) ) => {
56
+ if lhs. is_infer ( ) {
57
+ self . relate ( param_env, lhs, variance, rhs) ?;
58
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
59
+ } else {
60
+ Err ( NoSolution )
61
+ }
160
62
}
161
- } ;
162
- self . add_goal ( Goal :: new (
163
- self . tcx ( ) ,
164
- param_env,
165
- ty:: ProjectionPredicate { projection_ty : alias, term : other } ,
166
- ) ) ;
167
63
168
- Ok ( ( ) )
64
+ ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
65
+ self . relate ( param_env, alias_lhs, variance, alias_rhs) ?;
66
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
67
+ }
68
+ }
169
69
}
170
70
171
- fn assemble_subst_relate_candidate (
71
+ /// Normalize the `term` to equate it later.
72
+ fn try_normalize_term (
172
73
& mut self ,
173
74
param_env : ty:: ParamEnv < ' tcx > ,
174
- alias_lhs : ty:: AliasTy < ' tcx > ,
175
- alias_rhs : ty:: AliasTy < ' tcx > ,
176
- direction : ty:: AliasRelationDirection ,
177
- ) -> 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) ?;
75
+ term : ty:: Term < ' tcx > ,
76
+ ) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
77
+ match term. unpack ( ) {
78
+ ty:: TermKind :: Ty ( ty) => Ok ( self . try_normalize_ty ( param_env, ty) . map ( Into :: into) ) ,
79
+ ty:: TermKind :: Const ( _) => {
80
+ if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
81
+ let term = self . next_term_infer_of_kind ( term) ;
82
+ self . add_goal ( Goal :: new (
83
+ self . tcx ( ) ,
84
+ param_env,
85
+ ty:: ProjectionPredicate { projection_ty : alias, term } ,
86
+ ) ) ;
87
+ self . try_evaluate_added_goals ( ) ?;
88
+ Ok ( Some ( self . resolve_vars_if_possible ( term) ) )
89
+ } else {
90
+ Ok ( Some ( term) )
185
91
}
186
92
}
187
-
188
- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
189
- } )
190
- }
191
-
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
- ) ?;
214
- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
215
- } )
93
+ }
216
94
}
217
95
}
0 commit comments