1+ use itertools:: { Either , Itertools } ;
12use rustc_hash:: FxHashSet ;
23
34use super :: builder:: ClauseBuilder ;
4- use crate :: RustIrDatabase ;
5+ use crate :: { split :: Split , RustIrDatabase } ;
56use chalk_ir:: {
6- fold:: shift:: Shift , interner:: Interner , Binders , BoundVar , DebruijnIndex , TraitId , TraitRef ,
7- WhereClause ,
7+ fold:: shift:: Shift , interner:: Interner , AliasEq , AliasTy , Binders , BoundVar , DebruijnIndex ,
8+ Normalize , ProjectionTy , TraitId , TraitRef , Ty , WhereClause ,
89} ;
910
10- /// Generate `Implemented` clauses for `dyn Trait` and opaque types. We need to generate
11- /// `Implemented` clauses for all super traits, and for each trait we require
12- /// its where clauses. (See #203. )
11+ /// Generate `Implemented` and `Normalize` clauses for `dyn Trait` and opaque types.
12+ /// We need to generate those clauses for all super traits, and for each trait we
13+ /// require its where clauses. (See #203)
1314pub ( super ) fn push_trait_super_clauses < I : Interner > (
1415 db : & dyn RustIrDatabase < I > ,
1516 builder : & mut ClauseBuilder < ' _ , I > ,
1617 trait_ref : TraitRef < I > ,
1718) {
1819 let interner = db. interner ( ) ;
19- // Given`trait SuperTrait: WC`, which is a super trait
20+ // Given `trait SuperTrait: WC`, which is a super trait
2021 // of `Trait` (including actually just being the same trait);
2122 // then we want to push
2223 // - for `dyn Trait`:
2324 // `Implemented(dyn Trait: SuperTrait) :- WC`.
2425 // - for placeholder `!T` of `opaque type T: Trait = HiddenTy`:
2526 // `Implemented(!T: SuperTrait) :- WC`
26-
27- let super_trait_refs =
27+ //
28+ // When `SuperTrait` has `AliasEq` bounds like `trait SuperTrait: AnotherTrait<Assoc = Ty>`,
29+ // we also push
30+ // - for `dyn Trait`:
31+ // `Normalize(<dyn Trait as AnotherTrait>::Assoc -> Ty) :- AssocWC, WC`
32+ // - for placeholder `!T` of `opaque type T: Trait = HiddenTy`:
33+ // `Normalize(<!T as AnotherTrait>::Assoc -> Ty) :- AssocWC, WC`
34+ // where `WC` and `AssocWC` are the where clauses for `AnotherTrait` and `AnotherTrait::Assoc`
35+ // respectively.
36+ let ( super_trait_refs, super_trait_proj) =
2837 super_traits ( db, trait_ref. trait_id ) . substitute ( interner, & trait_ref. substitution ) ;
2938
3039 for q_super_trait_ref in super_trait_refs {
31- builder. push_binders ( q_super_trait_ref. clone ( ) , |builder, super_trait_ref| {
40+ builder. push_binders ( q_super_trait_ref, |builder, super_trait_ref| {
3241 let trait_datum = db. trait_datum ( super_trait_ref. trait_id ) ;
3342 let wc = trait_datum
3443 . where_clauses ( )
@@ -37,12 +46,40 @@ pub(super) fn push_trait_super_clauses<I: Interner>(
3746 builder. push_clause ( super_trait_ref, wc) ;
3847 } ) ;
3948 }
49+
50+ for q_super_trait_proj in super_trait_proj {
51+ builder. push_binders ( q_super_trait_proj, |builder, ( proj, ty) | {
52+ let assoc_ty_datum = db. associated_ty_data ( proj. associated_ty_id ) ;
53+ let trait_datum = db. trait_datum ( assoc_ty_datum. trait_id ) ;
54+ let assoc_wc = assoc_ty_datum
55+ . binders
56+ . map_ref ( |b| & b. where_clauses )
57+ . into_iter ( )
58+ . map ( |wc| wc. cloned ( ) . substitute ( interner, & proj. substitution ) ) ;
59+
60+ let impl_params = db. trait_parameters_from_projection ( & proj) ;
61+ let impl_wc = trait_datum
62+ . where_clauses ( )
63+ . into_iter ( )
64+ . map ( |wc| wc. cloned ( ) . substitute ( interner, impl_params) ) ;
65+ builder. push_clause (
66+ Normalize {
67+ alias : AliasTy :: Projection ( proj. clone ( ) ) ,
68+ ty,
69+ } ,
70+ impl_wc. chain ( assoc_wc) ,
71+ ) ;
72+ } ) ;
73+ }
4074}
4175
42- pub fn super_traits < I : Interner > (
76+ fn super_traits < I : Interner > (
4377 db : & dyn RustIrDatabase < I > ,
4478 trait_id : TraitId < I > ,
45- ) -> Binders < Vec < Binders < TraitRef < I > > > > {
79+ ) -> Binders < (
80+ Vec < Binders < TraitRef < I > > > ,
81+ Vec < Binders < ( ProjectionTy < I > , Ty < I > ) > > ,
82+ ) > {
4683 let interner = db. interner ( ) ;
4784 let mut seen_traits = FxHashSet :: default ( ) ;
4885 let trait_datum = db. trait_datum ( trait_id) ;
@@ -57,13 +94,21 @@ pub fn super_traits<I: Interner>(
5794 } ,
5895 ) ;
5996 let mut trait_refs = Vec :: new ( ) ;
60- go ( db, trait_ref, & mut seen_traits, & mut trait_refs) ;
97+ let mut aliases = Vec :: new ( ) ;
98+ go (
99+ db,
100+ trait_ref,
101+ & mut seen_traits,
102+ & mut trait_refs,
103+ & mut aliases,
104+ ) ;
61105
62106 fn go < I : Interner > (
63107 db : & dyn RustIrDatabase < I > ,
64108 trait_ref : Binders < TraitRef < I > > ,
65109 seen_traits : & mut FxHashSet < TraitId < I > > ,
66110 trait_refs : & mut Vec < Binders < TraitRef < I > > > ,
111+ aliases : & mut Vec < Binders < ( ProjectionTy < I > , Ty < I > ) > > ,
67112 ) {
68113 let interner = db. interner ( ) ;
69114 let trait_id = trait_ref. skip_binders ( ) . trait_id ;
@@ -73,32 +118,39 @@ pub fn super_traits<I: Interner>(
73118 }
74119 trait_refs. push ( trait_ref. clone ( ) ) ;
75120 let trait_datum = db. trait_datum ( trait_id) ;
76- let super_trait_refs = trait_datum
121+ let ( super_trait_refs, super_trait_projs ) : ( Vec < _ > , Vec < _ > ) = trait_datum
77122 . binders
78123 . map_ref ( |td| {
79124 td. where_clauses
80125 . iter ( )
81- . filter_map ( |qwc| {
82- qwc. as_ref ( ) . filter_map ( |wc| match wc {
83- WhereClause :: Implemented ( tr) => {
84- let self_ty = tr. self_type_parameter ( db. interner ( ) ) ;
126+ . filter ( |qwc| {
127+ let trait_ref = match qwc. skip_binders ( ) {
128+ WhereClause :: Implemented ( tr) => tr. clone ( ) ,
129+ WhereClause :: AliasEq ( AliasEq {
130+ alias : AliasTy :: Projection ( p) ,
131+ ..
132+ } ) => db. trait_ref_from_projection ( p) ,
133+ _ => return false ,
134+ } ;
135+ // We're looking for where clauses of the form
136+ // `Self: Trait` or `<Self as Trait>::Assoc`. `Self` is
137+ // ^1.0 because we're one binder in.
138+ trait_ref. self_type_parameter ( interner) . bound_var ( interner)
139+ == Some ( BoundVar :: new ( DebruijnIndex :: ONE , 0 ) )
140+ } )
141+ . cloned ( )
142+ . partition_map ( |qwc| {
143+ let ( value, binders) = qwc. into_value_and_skipped_binders ( ) ;
85144
86- // We're looking for where clauses
87- // of the form `Self: Trait`. That's
88- // ^1.0 because we're one binder in.
89- if self_ty. bound_var ( db. interner ( ) )
90- != Some ( BoundVar :: new ( DebruijnIndex :: ONE , 0 ) )
91- {
92- return None ;
93- }
94- Some ( tr. clone ( ) )
95- }
96- WhereClause :: AliasEq ( _) => None ,
97- WhereClause :: LifetimeOutlives ( ..) => None ,
98- WhereClause :: TypeOutlives ( ..) => None ,
99- } )
145+ match value {
146+ WhereClause :: Implemented ( tr) => Either :: Left ( Binders :: new ( binders, tr) ) ,
147+ WhereClause :: AliasEq ( AliasEq {
148+ alias : AliasTy :: Projection ( p) ,
149+ ty,
150+ } ) => Either :: Right ( Binders :: new ( binders, ( p, ty) ) ) ,
151+ _ => unreachable ! ( ) ,
152+ }
100153 } )
101- . collect :: < Vec < _ > > ( )
102154 } )
103155 // we skip binders on the trait_ref here and add them to the binders
104156 // on the trait ref in the loop below. We could probably avoid this if
@@ -109,10 +161,15 @@ pub fn super_traits<I: Interner>(
109161 // binders of super_trait_ref.
110162 let actual_binders = Binders :: new ( trait_ref. binders . clone ( ) , q_super_trait_ref) ;
111163 let q_super_trait_ref = actual_binders. fuse_binders ( interner) ;
112- go ( db, q_super_trait_ref, seen_traits, trait_refs) ;
164+ go ( db, q_super_trait_ref, seen_traits, trait_refs, aliases) ;
165+ }
166+ for q_super_trait_proj in super_trait_projs {
167+ let actual_binders = Binders :: new ( trait_ref. binders . clone ( ) , q_super_trait_proj) ;
168+ let q_super_trait_proj = actual_binders. fuse_binders ( interner) ;
169+ aliases. push ( q_super_trait_proj) ;
113170 }
114171 seen_traits. remove ( & trait_id) ;
115172 }
116173
117- Binders :: new ( trait_datum. binders . binders . clone ( ) , trait_refs)
174+ Binders :: new ( trait_datum. binders . binders . clone ( ) , ( trait_refs, aliases ) )
118175}
0 commit comments