@@ -46,6 +46,8 @@ enum SolverMode {
46
46
47
47
trait CanonicalResponseExt {
48
48
fn has_no_inference_or_external_constraints ( & self ) -> bool ;
49
+
50
+ fn has_only_region_constraints ( & self ) -> bool ;
49
51
}
50
52
51
53
impl < ' tcx > CanonicalResponseExt for Canonical < ' tcx , Response < ' tcx > > {
@@ -54,6 +56,11 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
54
56
&& self . value . var_values . is_identity ( )
55
57
&& self . value . external_constraints . opaque_types . is_empty ( )
56
58
}
59
+
60
+ fn has_only_region_constraints ( & self ) -> bool {
61
+ self . value . var_values . is_identity_modulo_regions ( )
62
+ && self . value . external_constraints . opaque_types . is_empty ( )
63
+ }
57
64
}
58
65
59
66
impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
@@ -221,12 +228,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
221
228
( Some ( alias_lhs) , Some ( alias_rhs) ) => {
222
229
debug ! ( "both sides are aliases" ) ;
223
230
224
- let candidates = vec ! [
225
- // LHS normalizes-to RHS
226
- evaluate_normalizes_to( self , alias_lhs, rhs, direction, Invert :: No ) ,
227
- // RHS normalizes-to RHS
228
- evaluate_normalizes_to( self , alias_rhs, lhs, direction, Invert :: Yes ) ,
229
- // Relate via substs
231
+ let mut candidates = Vec :: new ( ) ;
232
+ // LHS normalizes-to RHS
233
+ candidates. extend (
234
+ evaluate_normalizes_to ( self , alias_lhs, rhs, direction, Invert :: No ) . ok ( ) ,
235
+ ) ;
236
+ // RHS normalizes-to RHS
237
+ candidates. extend (
238
+ evaluate_normalizes_to ( self , alias_rhs, lhs, direction, Invert :: Yes ) . ok ( ) ,
239
+ ) ;
240
+ // Relate via substs
241
+ candidates. extend (
230
242
self . probe ( |ecx| {
231
243
let span = tracing:: span!(
232
244
tracing:: Level :: DEBUG ,
@@ -247,11 +259,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
247
259
}
248
260
249
261
ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
250
- } ) ,
251
- ] ;
262
+ } )
263
+ . ok ( ) ,
264
+ ) ;
252
265
debug ! ( ?candidates) ;
253
266
254
- self . try_merge_responses ( candidates. into_iter ( ) )
267
+ if let Some ( merged) = self . try_merge_responses ( & candidates) {
268
+ Ok ( merged)
269
+ } else {
270
+ self . flounder ( & candidates)
271
+ }
255
272
}
256
273
}
257
274
}
@@ -289,43 +306,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
289
306
debug ! ( "added_goals={:?}" , & self . nested_goals. goals[ current_len..] ) ;
290
307
}
291
308
292
- #[ instrument( level = "debug" , skip( self , responses) ) ]
309
+ /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
310
+ ///
311
+ /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
312
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
293
313
fn try_merge_responses (
294
314
& mut self ,
295
- responses : impl Iterator < Item = QueryResult < ' tcx > > ,
296
- ) -> QueryResult < ' tcx > {
297
- let candidates = responses. into_iter ( ) . flatten ( ) . collect :: < Box < [ _ ] > > ( ) ;
298
-
299
- if candidates. is_empty ( ) {
300
- return Err ( NoSolution ) ;
315
+ responses : & [ CanonicalResponse < ' tcx > ] ,
316
+ ) -> Option < CanonicalResponse < ' tcx > > {
317
+ if responses. is_empty ( ) {
318
+ return None ;
301
319
}
302
320
303
321
// FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
304
322
// a subset of the constraints that all the other responses have.
305
- let one = candidates [ 0 ] ;
306
- if candidates [ 1 ..] . iter ( ) . all ( |resp| resp == & one) {
307
- return Ok ( one) ;
323
+ let one = responses [ 0 ] ;
324
+ if responses [ 1 ..] . iter ( ) . all ( |& resp| resp == one) {
325
+ return Some ( one) ;
308
326
}
309
327
310
- if let Some ( response) = candidates. iter ( ) . find ( |response| {
311
- response. value . certainty == Certainty :: Yes
312
- && response. has_no_inference_or_external_constraints ( )
313
- } ) {
314
- return Ok ( * response) ;
315
- }
328
+ responses
329
+ . iter ( )
330
+ . find ( |response| {
331
+ response. value . certainty == Certainty :: Yes
332
+ && response. has_no_inference_or_external_constraints ( )
333
+ } )
334
+ . copied ( )
335
+ }
316
336
317
- let certainty = candidates. iter ( ) . fold ( Certainty :: AMBIGUOUS , |certainty, response| {
318
- certainty. unify_and ( response. value . certainty )
337
+ /// If we fail to merge responses we flounder and return overflow or ambiguity.
338
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
339
+ fn flounder ( & mut self , responses : & [ CanonicalResponse < ' tcx > ] ) -> QueryResult < ' tcx > {
340
+ if responses. is_empty ( ) {
341
+ return Err ( NoSolution ) ;
342
+ }
343
+ let certainty = responses. iter ( ) . fold ( Certainty :: AMBIGUOUS , |certainty, response| {
344
+ certainty. unify_with ( response. value . certainty )
319
345
} ) ;
320
- // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the
321
- // responses and use that for the constraints of this ambiguous response.
322
- debug ! ( ">1 response, bailing with {certainty:?}" ) ;
346
+
323
347
let response = self . evaluate_added_goals_and_make_canonical_response ( certainty) ;
324
- if let Ok ( response) = & response {
348
+ if let Ok ( response) = response {
325
349
assert ! ( response. has_no_inference_or_external_constraints( ) ) ;
350
+ Ok ( response)
351
+ } else {
352
+ bug ! ( "failed to make floundered response: {responses:?}" ) ;
326
353
}
327
-
328
- response
329
354
}
330
355
}
331
356
0 commit comments