@@ -512,12 +512,7 @@ pub fn program_clauses_that_could_match<I: Interner>(
512
512
// An alias could normalize to anything, including an
513
513
// opaque type, so push a clause that asks for the self
514
514
// 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 ( ) ) ;
521
516
return Ok ( clauses) ;
522
517
}
523
518
TyKind :: OpaqueType ( opaque_ty_id, _) => {
@@ -781,12 +776,10 @@ fn push_alias_implemented_clause<I: Interner>(
781
776
// TODO: instead generate clauses without reference to the specific type parameters of the goal?
782
777
let generalized = generalize:: Generalize :: apply ( interner, ( trait_ref, alias) ) ;
783
778
builder. push_binders ( generalized, |builder, ( trait_ref, alias) | {
784
- let binders = Binders :: with_fresh_type_var ( interner, |ty_var| ty_var) ;
785
-
786
779
// forall<..., T> {
787
780
// <X as Y>::Z: Trait :- T: Trait, <X as Y>::Z == T
788
781
// }
789
- builder. push_binders ( binders , |builder, bound_var| {
782
+ builder. push_bound_ty ( |builder, bound_var| {
790
783
let fresh_self_subst = Substitution :: from_iter (
791
784
interner,
792
785
std:: iter:: once ( bound_var. clone ( ) . cast ( interner) ) . chain (
@@ -816,7 +809,6 @@ fn push_alias_implemented_clause<I: Interner>(
816
809
fn push_alias_alias_eq_clause < I : Interner > (
817
810
builder : & mut ClauseBuilder < ' _ , I > ,
818
811
projection_ty : ProjectionTy < I > ,
819
- ty : Ty < I > ,
820
812
alias : AliasTy < I > ,
821
813
) {
822
814
let interner = builder. interner ( ) ;
@@ -827,43 +819,69 @@ fn push_alias_alias_eq_clause<I: Interner>(
827
819
assert_eq ! ( * self_ty. kind( interner) , TyKind :: Alias ( alias. clone( ) ) ) ;
828
820
829
821
// 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> {
835
836
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
836
837
// }
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 (
861
869
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 ( ) ,
864
872
} ) ) ,
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
+ } ) ;
867
885
} ) ;
868
886
} ) ;
869
887
}
0 commit comments