@@ -46,6 +46,8 @@ enum SolverMode {
4646
4747trait CanonicalResponseExt {
4848 fn has_no_inference_or_external_constraints ( & self ) -> bool ;
49+
50+ fn has_only_region_constraints ( & self ) -> bool ;
4951}
5052
5153impl < ' tcx > CanonicalResponseExt for Canonical < ' tcx , Response < ' tcx > > {
@@ -54,6 +56,11 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
5456 && self . value . var_values . is_identity ( )
5557 && self . value . external_constraints . opaque_types . is_empty ( )
5658 }
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+ }
5764}
5865
5966impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
@@ -221,12 +228,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
221228 ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
222229 debug ! ( "both sides are aliases" ) ;
223230
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 (
230242 self . probe ( |ecx| {
231243 let span = tracing:: span!(
232244 tracing:: Level :: DEBUG ,
@@ -247,11 +259,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
247259 }
248260
249261 ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
250- } ) ,
251- ] ;
262+ } )
263+ . ok ( ) ,
264+ ) ;
252265 debug ! ( ?candidates) ;
253266
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+ }
255272 }
256273 }
257274 }
@@ -289,43 +306,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
289306 debug ! ( "added_goals={:?}" , & self . nested_goals. goals[ current_len..] ) ;
290307 }
291308
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) ]
293313 fn try_merge_responses (
294314 & 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 ;
301319 }
302320
303321 // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
304322 // 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) ;
308326 }
309327
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+ }
316336
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 )
319345 } ) ;
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+
323347 let response = self . evaluate_added_goals_and_make_canonical_response ( certainty) ;
324- if let Ok ( response) = & response {
348+ if let Ok ( response) = response {
325349 assert ! ( response. has_no_inference_or_external_constraints( ) ) ;
350+ Ok ( response)
351+ } else {
352+ bug ! ( "failed to make floundered response: {responses:?}" ) ;
326353 }
327-
328- response
329354 }
330355}
331356
0 commit comments