@@ -42,6 +42,8 @@ mod trait_goals;
42
42
43
43
pub use fulfill:: FulfillmentCtxt ;
44
44
45
+ use self :: infcx_ext:: InferCtxtExt ;
46
+
45
47
/// A goal is a statement, i.e. `predicate`, we want to prove
46
48
/// given some assumptions, i.e. `param_env`.
47
49
///
@@ -81,6 +83,21 @@ pub struct Response<'tcx> {
81
83
pub certainty : Certainty ,
82
84
}
83
85
86
+ trait CanonicalResponseExt {
87
+ fn has_no_inference_or_external_constraints ( & self ) -> bool ;
88
+ }
89
+
90
+ impl < ' tcx > CanonicalResponseExt for Canonical < ' tcx , Response < ' tcx > > {
91
+ fn has_no_inference_or_external_constraints ( & self ) -> bool {
92
+ // so that we get a compile error when regions are supported
93
+ // so this code can be checked for being correct
94
+ let _: ( ) = self . value . external_constraints . regions ;
95
+
96
+ self . value . var_values . is_identity ( )
97
+ && self . value . external_constraints . opaque_types . is_empty ( )
98
+ }
99
+ }
100
+
84
101
#[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash , TypeFoldable , TypeVisitable ) ]
85
102
pub enum Certainty {
86
103
Yes ,
@@ -302,9 +319,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
302
319
ty:: PredicateKind :: TypeWellFormedFromEnv ( ..) => {
303
320
bug ! ( "TypeWellFormedFromEnv is only used for Chalk" )
304
321
}
305
- ty:: PredicateKind :: AliasEq ( ..) => {
306
- // FIXME(deferred_projection_equality)
307
- todo ! ( )
322
+ ty:: PredicateKind :: AliasEq ( lhs, rhs) => {
323
+ self . compute_alias_eq_goal ( Goal { param_env, predicate : ( lhs, rhs) } )
308
324
}
309
325
}
310
326
} else {
@@ -402,6 +418,63 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
402
418
None => self . make_canonical_response ( Certainty :: AMBIGUOUS ) ,
403
419
}
404
420
}
421
+
422
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
423
+ fn compute_alias_eq_goal (
424
+ & mut self ,
425
+ goal : Goal < ' tcx , ( ty:: Term < ' tcx > , ty:: Term < ' tcx > ) > ,
426
+ ) -> QueryResult < ' tcx > {
427
+ let tcx = self . tcx ( ) ;
428
+
429
+ let evaluate_normalizes_to = |ecx : & mut EvalCtxt < ' _ , ' tcx > , alias, other| {
430
+ debug ! ( "evaluate_normalizes_to(alias={:?}, other={:?})" , alias, other) ;
431
+ let r = ecx. infcx . probe ( |_| {
432
+ let ( _, certainty) = ecx. evaluate_goal ( goal. with (
433
+ tcx,
434
+ ty:: Binder :: dummy ( ty:: ProjectionPredicate {
435
+ projection_ty : alias,
436
+ term : other,
437
+ } ) ,
438
+ ) ) ?;
439
+ ecx. make_canonical_response ( certainty)
440
+ } ) ;
441
+ debug ! ( "evaluate_normalizes_to(..) -> {:?}" , r) ;
442
+ r
443
+ } ;
444
+
445
+ if goal. predicate . 0 . is_infer ( ) || goal. predicate . 1 . is_infer ( ) {
446
+ bug ! (
447
+ "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
448
+ ) ;
449
+ }
450
+
451
+ match (
452
+ goal. predicate . 0 . to_alias_term_no_opaque ( tcx) ,
453
+ goal. predicate . 1 . to_alias_term_no_opaque ( tcx) ,
454
+ ) {
455
+ ( None , None ) => bug ! ( "`AliasEq` goal without an alias on either lhs or rhs" ) ,
456
+ ( Some ( alias) , None ) => evaluate_normalizes_to ( self , alias, goal. predicate . 1 ) ,
457
+ ( None , Some ( alias) ) => evaluate_normalizes_to ( self , alias, goal. predicate . 0 ) ,
458
+ ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
459
+ debug ! ( "compute_alias_eq_goal: both sides are aliases" ) ;
460
+
461
+ let mut candidates = Vec :: with_capacity ( 3 ) ;
462
+
463
+ // Evaluate all 3 potential candidates for the alias' being equal
464
+ candidates. push ( evaluate_normalizes_to ( self , alias_lhs, goal. predicate . 1 ) ) ;
465
+ candidates. push ( evaluate_normalizes_to ( self , alias_rhs, goal. predicate . 0 ) ) ;
466
+ candidates. push ( self . infcx . probe ( |_| {
467
+ debug ! ( "compute_alias_eq_goal: alias defids are equal, equating substs" ) ;
468
+ let nested_goals = self . infcx . eq ( goal. param_env , alias_lhs, alias_rhs) ?;
469
+ self . evaluate_all_and_make_canonical_response ( nested_goals)
470
+ } ) ) ;
471
+
472
+ debug ! ( ?candidates) ;
473
+
474
+ self . try_merge_responses ( candidates. into_iter ( ) )
475
+ }
476
+ }
477
+ }
405
478
}
406
479
407
480
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
@@ -453,6 +526,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
453
526
) -> QueryResult < ' tcx > {
454
527
self . evaluate_all ( goals) . and_then ( |certainty| self . make_canonical_response ( certainty) )
455
528
}
529
+
530
+ fn try_merge_responses (
531
+ & mut self ,
532
+ responses : impl Iterator < Item = QueryResult < ' tcx > > ,
533
+ ) -> QueryResult < ' tcx > {
534
+ let candidates = responses. into_iter ( ) . flatten ( ) . collect :: < Box < [ _ ] > > ( ) ;
535
+
536
+ if candidates. is_empty ( ) {
537
+ return Err ( NoSolution ) ;
538
+ }
539
+
540
+ // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with
541
+ // a subset of the constraints that all the other responses have.
542
+ let one = candidates[ 0 ] ;
543
+ if candidates[ 1 ..] . iter ( ) . all ( |resp| resp == & one) {
544
+ return Ok ( one) ;
545
+ }
546
+
547
+ if let Some ( response) = candidates. iter ( ) . find ( |response| {
548
+ response. value . certainty == Certainty :: Yes
549
+ && response. has_no_inference_or_external_constraints ( )
550
+ } ) {
551
+ return Ok ( response. clone ( ) ) ;
552
+ }
553
+
554
+ let certainty = candidates. iter ( ) . fold ( Certainty :: AMBIGUOUS , |certainty, response| {
555
+ certainty. unify_and ( response. value . certainty )
556
+ } ) ;
557
+ // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the
558
+ // responses and use that for the constraints of this ambiguous response.
559
+ let response = self . make_canonical_response ( certainty) ;
560
+ if let Ok ( response) = & response {
561
+ assert ! ( response. has_no_inference_or_external_constraints( ) ) ;
562
+ }
563
+
564
+ response
565
+ }
456
566
}
457
567
458
568
#[ instrument( level = "debug" , skip( infcx) , ret) ]
0 commit comments