@@ -512,12 +512,7 @@ pub fn program_clauses_that_could_match<I: Interner>(
512512 // An alias could normalize to anything, including an
513513 // opaque type, so push a clause that asks for the self
514514 // type to be normalized and return.
515- push_alias_alias_eq_clause (
516- builder,
517- proj. clone ( ) ,
518- alias_eq. ty . clone ( ) ,
519- alias. clone ( ) ,
520- ) ;
515+ push_alias_alias_eq_clause ( builder, proj. clone ( ) , alias. clone ( ) ) ;
521516 return Ok ( clauses) ;
522517 }
523518 TyKind :: OpaqueType ( opaque_ty_id, _) => {
@@ -781,12 +776,10 @@ fn push_alias_implemented_clause<I: Interner>(
781776 // TODO: instead generate clauses without reference to the specific type parameters of the goal?
782777 let generalized = generalize:: Generalize :: apply ( interner, ( trait_ref, alias) ) ;
783778 builder. push_binders ( generalized, |builder, ( trait_ref, alias) | {
784- let binders = Binders :: with_fresh_type_var ( interner, |ty_var| ty_var) ;
785-
786779 // forall<..., T> {
787780 // <X as Y>::Z: Trait :- T: Trait, <X as Y>::Z == T
788781 // }
789- builder. push_binders ( binders , |builder, bound_var| {
782+ builder. push_bound_ty ( |builder, bound_var| {
790783 let fresh_self_subst = Substitution :: from_iter (
791784 interner,
792785 std:: iter:: once ( bound_var. clone ( ) . cast ( interner) ) . chain (
@@ -816,7 +809,6 @@ fn push_alias_implemented_clause<I: Interner>(
816809fn push_alias_alias_eq_clause < I : Interner > (
817810 builder : & mut ClauseBuilder < ' _ , I > ,
818811 projection_ty : ProjectionTy < I > ,
819- ty : Ty < I > ,
820812 alias : AliasTy < I > ,
821813) {
822814 let interner = builder. interner ( ) ;
@@ -827,43 +819,69 @@ fn push_alias_alias_eq_clause<I: Interner>(
827819 assert_eq ! ( * self_ty. kind( interner) , TyKind :: Alias ( alias. clone( ) ) ) ;
828820
829821 // TODO: instead generate clauses without reference to the specific type parameters of the goal?
830- let generalized = generalize:: Generalize :: apply ( interner, ( projection_ty, ty, alias) ) ;
831- builder. push_binders ( generalized, |builder, ( projection_ty, ty, alias) | {
832- let binders = Binders :: with_fresh_type_var ( interner, |ty_var| ty_var) ;
833-
834- // forall<..., T> {
822+ let generalized = generalize:: Generalize :: apply ( interner, ( projection_ty, alias) ) ;
823+ builder. push_binders ( generalized, |builder, ( projection_ty, alias) | {
824+ // Given the following canonical goal:
825+ //
826+ // ```
827+ // forall<...> {
828+ // <<X as Y>::A as Z>::B == W
829+ // }
830+ // ```
831+ //
832+ // we generate:
833+ //
834+ // ```
835+ // forall<..., T, U> {
835836 // <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
836837 // }
837- builder. push_binders ( binders, |builder, bound_var| {
838- let ( _, trait_args, assoc_args) = builder. db . split_projection ( & projection_ty) ;
839- let fresh_self_subst = Substitution :: from_iter (
840- interner,
841- assoc_args
842- . iter ( )
843- . cloned ( )
844- . chain ( std:: iter:: once ( bound_var. clone ( ) . cast ( interner) ) )
845- . chain ( trait_args[ 1 ..] . iter ( ) . cloned ( ) ) ,
846- ) ;
847- let fresh_alias = AliasTy :: Projection ( ProjectionTy {
848- associated_ty_id : projection_ty. associated_ty_id ,
849- substitution : fresh_self_subst,
850- } ) ;
851- builder. push_clause (
852- DomainGoal :: Holds ( WhereClause :: AliasEq ( AliasEq {
853- alias : AliasTy :: Projection ( projection_ty. clone ( ) ) ,
854- ty : ty. clone ( ) ,
855- } ) ) ,
856- & [
857- DomainGoal :: Holds ( WhereClause :: AliasEq ( AliasEq {
858- alias : fresh_alias,
859- ty : ty. clone ( ) ,
860- } ) ) ,
838+ // ```
839+ //
840+ // `T` and `U` are `intermediate_eq_ty` and `eq_ty` respectively below.
841+ //
842+ // Note that we used to "reuse" `W` and push:
843+ //
844+ // ```
845+ // forall<..., T> {
846+ // <<X as Y>::A as Z>::B == W :- <T as Z>::B == W, <X as Y>::A == T
847+ // }
848+ // ```
849+ //
850+ // but it caused a cycle which led to false `NoSolution` under certain conditions, in
851+ // particular when `W` itself is a nested projection type. See test
852+ // `nested_proj_eq_nested_proj_should_flounder`.
853+ builder. push_bound_ty ( |builder, intermediate_eq_ty| {
854+ builder. push_bound_ty ( |builder, eq_ty| {
855+ let ( _, trait_args, assoc_args) = builder. db . split_projection ( & projection_ty) ;
856+ let fresh_self_subst = Substitution :: from_iter (
857+ interner,
858+ assoc_args
859+ . iter ( )
860+ . cloned ( )
861+ . chain ( std:: iter:: once ( intermediate_eq_ty. clone ( ) . cast ( interner) ) )
862+ . chain ( trait_args[ 1 ..] . iter ( ) . cloned ( ) ) ,
863+ ) ;
864+ let fresh_alias = AliasTy :: Projection ( ProjectionTy {
865+ associated_ty_id : projection_ty. associated_ty_id ,
866+ substitution : fresh_self_subst,
867+ } ) ;
868+ builder. push_clause (
861869 DomainGoal :: Holds ( WhereClause :: AliasEq ( AliasEq {
862- alias : alias . clone ( ) ,
863- ty : bound_var ,
870+ alias : AliasTy :: Projection ( projection_ty . clone ( ) ) ,
871+ ty : eq_ty . clone ( ) ,
864872 } ) ) ,
865- ] ,
866- ) ;
873+ & [
874+ DomainGoal :: Holds ( WhereClause :: AliasEq ( AliasEq {
875+ alias : fresh_alias,
876+ ty : eq_ty,
877+ } ) ) ,
878+ DomainGoal :: Holds ( WhereClause :: AliasEq ( AliasEq {
879+ alias,
880+ ty : intermediate_eq_ty,
881+ } ) ) ,
882+ ] ,
883+ ) ;
884+ } ) ;
867885 } ) ;
868886 } ) ;
869887}
0 commit comments