@@ -79,11 +79,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
79
79
// them. This is necessary for inference during typeck.
80
80
//
81
81
// As this is incomplete, we must not do so during coherence.
82
- match ( self . solver_mode ( ) , subst_relate_response) {
83
- ( SolverMode :: Normal , Ok ( response) ) => Ok ( response) ,
84
- ( SolverMode :: Normal , Err ( NoSolution ) ) | ( SolverMode :: Coherence , _) => {
85
- self . flounder ( & candidates)
82
+ match self . solver_mode ( ) {
83
+ SolverMode :: Normal => {
84
+ if let Ok ( subst_relate_response) = subst_relate_response {
85
+ Ok ( subst_relate_response)
86
+ } else if let Ok ( bidirectional_normalizes_to_response) = self
87
+ . assemble_bidirectional_normalizes_to_candidate (
88
+ param_env, lhs, rhs, direction,
89
+ )
90
+ {
91
+ Ok ( bidirectional_normalizes_to_response)
92
+ } else {
93
+ self . flounder ( & candidates)
94
+ }
86
95
}
96
+ SolverMode :: Coherence => self . flounder ( & candidates) ,
87
97
}
88
98
}
89
99
}
@@ -100,29 +110,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
100
110
invert : Invert ,
101
111
) -> QueryResult < ' tcx > {
102
112
self . probe ( |ecx| {
103
- let other = match direction {
104
- // This is purely an optimization.
105
- ty:: AliasRelationDirection :: Equate => other,
106
-
107
- ty:: AliasRelationDirection :: Subtype => {
108
- let fresh = ecx. next_term_infer_of_kind ( other) ;
109
- let ( sub, sup) = match invert {
110
- Invert :: No => ( fresh, other) ,
111
- Invert :: Yes => ( other, fresh) ,
112
- } ;
113
- ecx. sub ( param_env, sub, sup) ?;
114
- fresh
115
- }
116
- } ;
117
- ecx. add_goal ( Goal :: new (
118
- ecx. tcx ( ) ,
119
- param_env,
120
- ty:: Binder :: dummy ( ty:: ProjectionPredicate { projection_ty : alias, term : other } ) ,
121
- ) ) ;
113
+ ecx. normalizes_to_inner ( param_env, alias, other, direction, invert) ?;
122
114
ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
123
115
} )
124
116
}
125
117
118
+ fn normalizes_to_inner (
119
+ & mut self ,
120
+ param_env : ty:: ParamEnv < ' tcx > ,
121
+ alias : ty:: AliasTy < ' tcx > ,
122
+ other : ty:: Term < ' tcx > ,
123
+ direction : ty:: AliasRelationDirection ,
124
+ invert : Invert ,
125
+ ) -> Result < ( ) , NoSolution > {
126
+ let other = match direction {
127
+ // This is purely an optimization.
128
+ ty:: AliasRelationDirection :: Equate => other,
129
+
130
+ ty:: AliasRelationDirection :: Subtype => {
131
+ let fresh = self . next_term_infer_of_kind ( other) ;
132
+ let ( sub, sup) = match invert {
133
+ Invert :: No => ( fresh, other) ,
134
+ Invert :: Yes => ( other, fresh) ,
135
+ } ;
136
+ self . sub ( param_env, sub, sup) ?;
137
+ fresh
138
+ }
139
+ } ;
140
+ self . add_goal ( Goal :: new (
141
+ self . tcx ( ) ,
142
+ param_env,
143
+ ty:: Binder :: dummy ( ty:: ProjectionPredicate { projection_ty : alias, term : other } ) ,
144
+ ) ) ;
145
+
146
+ Ok ( ( ) )
147
+ }
148
+
126
149
fn assemble_subst_relate_candidate (
127
150
& mut self ,
128
151
param_env : ty:: ParamEnv < ' tcx > ,
@@ -143,4 +166,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
143
166
ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
144
167
} )
145
168
}
169
+
170
+ fn assemble_bidirectional_normalizes_to_candidate (
171
+ & mut self ,
172
+ param_env : ty:: ParamEnv < ' tcx > ,
173
+ lhs : ty:: Term < ' tcx > ,
174
+ rhs : ty:: Term < ' tcx > ,
175
+ direction : ty:: AliasRelationDirection ,
176
+ ) -> QueryResult < ' tcx > {
177
+ self . probe ( |ecx| {
178
+ ecx. normalizes_to_inner (
179
+ param_env,
180
+ lhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
181
+ rhs,
182
+ direction,
183
+ Invert :: No ,
184
+ ) ?;
185
+ ecx. normalizes_to_inner (
186
+ param_env,
187
+ rhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
188
+ lhs,
189
+ direction,
190
+ Invert :: Yes ,
191
+ ) ?;
192
+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
193
+ } )
194
+ }
146
195
}
0 commit comments