@@ -42,6 +42,8 @@ mod trait_goals;
4242
4343pub use fulfill:: FulfillmentCtxt ;
4444
45+ use self :: infcx_ext:: InferCtxtExt ;
46+
4547/// A goal is a statement, i.e. `predicate`, we want to prove
4648/// given some assumptions, i.e. `param_env`.
4749///
@@ -81,6 +83,21 @@ pub struct Response<'tcx> {
8183 pub certainty : Certainty ,
8284}
8385
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+
84101#[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash , TypeFoldable , TypeVisitable ) ]
85102pub enum Certainty {
86103 Yes ,
@@ -302,9 +319,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
302319 ty:: PredicateKind :: TypeWellFormedFromEnv ( ..) => {
303320 bug ! ( "TypeWellFormedFromEnv is only used for Chalk" )
304321 }
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) } )
308324 }
309325 }
310326 } else {
@@ -402,6 +418,63 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
402418 None => self . make_canonical_response ( Certainty :: AMBIGUOUS ) ,
403419 }
404420 }
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+ }
405478}
406479
407480impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
@@ -453,6 +526,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
453526 ) -> QueryResult < ' tcx > {
454527 self . evaluate_all ( goals) . and_then ( |certainty| self . make_canonical_response ( certainty) )
455528 }
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+ }
456566}
457567
458568#[ instrument( level = "debug" , skip( infcx) , ret) ]
0 commit comments