1
+ use itertools:: { Either , Itertools } ;
1
2
use rustc_hash:: FxHashSet ;
2
3
3
4
use super :: builder:: ClauseBuilder ;
4
- use crate :: RustIrDatabase ;
5
+ use crate :: { split :: Split , RustIrDatabase } ;
5
6
use 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 ,
8
9
} ;
9
10
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)
13
14
pub ( super ) fn push_trait_super_clauses < I : Interner > (
14
15
db : & dyn RustIrDatabase < I > ,
15
16
builder : & mut ClauseBuilder < ' _ , I > ,
16
17
trait_ref : TraitRef < I > ,
17
18
) {
18
19
let interner = db. interner ( ) ;
19
- // Given`trait SuperTrait: WC`, which is a super trait
20
+ // Given `trait SuperTrait: WC`, which is a super trait
20
21
// of `Trait` (including actually just being the same trait);
21
22
// then we want to push
22
23
// - for `dyn Trait`:
23
24
// `Implemented(dyn Trait: SuperTrait) :- WC`.
24
25
// - for placeholder `!T` of `opaque type T: Trait = HiddenTy`:
25
26
// `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) =
28
37
super_traits ( db, trait_ref. trait_id ) . substitute ( interner, & trait_ref. substitution ) ;
29
38
30
39
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| {
32
41
let trait_datum = db. trait_datum ( super_trait_ref. trait_id ) ;
33
42
let wc = trait_datum
34
43
. where_clauses ( )
@@ -37,12 +46,40 @@ pub(super) fn push_trait_super_clauses<I: Interner>(
37
46
builder. push_clause ( super_trait_ref, wc) ;
38
47
} ) ;
39
48
}
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
+ }
40
74
}
41
75
42
- pub fn super_traits < I : Interner > (
76
+ fn super_traits < I : Interner > (
43
77
db : & dyn RustIrDatabase < I > ,
44
78
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
+ ) > {
46
83
let interner = db. interner ( ) ;
47
84
let mut seen_traits = FxHashSet :: default ( ) ;
48
85
let trait_datum = db. trait_datum ( trait_id) ;
@@ -57,13 +94,21 @@ pub fn super_traits<I: Interner>(
57
94
} ,
58
95
) ;
59
96
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
+ ) ;
61
105
62
106
fn go < I : Interner > (
63
107
db : & dyn RustIrDatabase < I > ,
64
108
trait_ref : Binders < TraitRef < I > > ,
65
109
seen_traits : & mut FxHashSet < TraitId < I > > ,
66
110
trait_refs : & mut Vec < Binders < TraitRef < I > > > ,
111
+ aliases : & mut Vec < Binders < ( ProjectionTy < I > , Ty < I > ) > > ,
67
112
) {
68
113
let interner = db. interner ( ) ;
69
114
let trait_id = trait_ref. skip_binders ( ) . trait_id ;
@@ -73,32 +118,39 @@ pub fn super_traits<I: Interner>(
73
118
}
74
119
trait_refs. push ( trait_ref. clone ( ) ) ;
75
120
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
77
122
. binders
78
123
. map_ref ( |td| {
79
124
td. where_clauses
80
125
. 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 ( ) ;
85
144
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
+ }
100
153
} )
101
- . collect :: < Vec < _ > > ( )
102
154
} )
103
155
// we skip binders on the trait_ref here and add them to the binders
104
156
// on the trait ref in the loop below. We could probably avoid this if
@@ -109,10 +161,15 @@ pub fn super_traits<I: Interner>(
109
161
// binders of super_trait_ref.
110
162
let actual_binders = Binders :: new ( trait_ref. binders . clone ( ) , q_super_trait_ref) ;
111
163
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) ;
113
170
}
114
171
seen_traits. remove ( & trait_id) ;
115
172
}
116
173
117
- Binders :: new ( trait_datum. binders . binders . clone ( ) , trait_refs)
174
+ Binders :: new ( trait_datum. binders . binders . clone ( ) , ( trait_refs, aliases ) )
118
175
}
0 commit comments