@@ -18,6 +18,49 @@ mod env_elaborator;
18
18
mod generalize;
19
19
pub mod program_clauses;
20
20
21
+ // yields the types "contained" in `app_ty`
22
+ fn constituent_types < I : Interner > (
23
+ db : & dyn RustIrDatabase < I > ,
24
+ app_ty : & ApplicationTy < I > ,
25
+ ) -> Vec < Ty < I > > {
26
+ let interner = db. interner ( ) ;
27
+
28
+ match app_ty. name {
29
+ // For non-phantom_data adts we collect its variants/fields
30
+ TypeName :: Adt ( adt_id) if !db. adt_datum ( adt_id) . flags . phantom_data => {
31
+ let adt_datum = & db. adt_datum ( adt_id) ;
32
+ let adt_datum_bound = adt_datum. binders . substitute ( interner, & app_ty. substitution ) ;
33
+ adt_datum_bound
34
+ . variants
35
+ . into_iter ( )
36
+ . flat_map ( |variant| variant. fields . into_iter ( ) )
37
+ . collect ( )
38
+ }
39
+ // And for `PhantomData<T>`, we pass `T`.
40
+ TypeName :: Adt ( _)
41
+ | TypeName :: Array
42
+ | TypeName :: Tuple ( _)
43
+ | TypeName :: Slice
44
+ | TypeName :: Raw ( _)
45
+ | TypeName :: Ref ( _)
46
+ | TypeName :: Scalar ( _)
47
+ | TypeName :: Str
48
+ | TypeName :: Never
49
+ | TypeName :: FnDef ( _) => app_ty
50
+ . substitution
51
+ . iter ( interner)
52
+ . filter_map ( |x| x. ty ( interner) )
53
+ . cloned ( )
54
+ . collect ( ) ,
55
+
56
+ TypeName :: Closure ( _) => panic ! ( "this function should not be called for closures" ) ,
57
+ TypeName :: Foreign ( _) => panic ! ( "constituent_types of foreign types are unknown!" ) ,
58
+ TypeName :: Error => Vec :: new ( ) ,
59
+ TypeName :: OpaqueType ( _) => unimplemented ! ( ) ,
60
+ TypeName :: AssociatedType ( _) => unimplemented ! ( ) ,
61
+ }
62
+ }
63
+
21
64
/// FIXME(#505) update comments for ADTs
22
65
/// For auto-traits, we generate a default rule for every struct,
23
66
/// unless there is a manual impl for that struct given explicitly.
@@ -53,9 +96,8 @@ pub mod program_clauses;
53
96
pub fn push_auto_trait_impls < I : Interner > (
54
97
builder : & mut ClauseBuilder < ' _ , I > ,
55
98
auto_trait_id : TraitId < I > ,
56
- adt_id : AdtId < I > ,
99
+ app_ty : & ApplicationTy < I > ,
57
100
) {
58
- let adt_datum = & builder. db . adt_datum ( adt_id) ;
59
101
let interner = builder. interner ( ) ;
60
102
61
103
// Must be an auto trait.
@@ -67,44 +109,48 @@ pub fn push_auto_trait_impls<I: Interner>(
67
109
1
68
110
) ;
69
111
112
+ // we assume that the builder has no binders so far.
113
+ assert ! ( builder. placeholders_in_scope( ) . is_empty( ) ) ;
114
+
70
115
// If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait
71
116
// for Foo<..>`, where `Foo` is the adt we're looking at, then
72
117
// we don't generate our own rules.
73
- if builder. db . impl_provided_for ( auto_trait_id, adt_id ) {
118
+ if builder. db . impl_provided_for ( auto_trait_id, app_ty ) {
74
119
debug ! ( "impl provided" ) ;
75
120
return ;
76
121
}
77
122
78
- let binders = adt_datum. binders . map_ref ( |b| & b. variants ) ;
79
- builder. push_binders ( & binders, |builder, variants| {
80
- let self_ty: Ty < _ > = ApplicationTy {
81
- name : adt_id. cast ( interner) ,
82
- substitution : builder. substitution_in_scope ( ) ,
123
+ let mk_ref = |ty : Ty < I > | TraitRef {
124
+ trait_id : auto_trait_id,
125
+ substitution : Substitution :: from1 ( interner, ty. cast ( interner) ) ,
126
+ } ;
127
+
128
+ let consequence = mk_ref ( app_ty. clone ( ) . intern ( interner) ) ;
129
+
130
+ match app_ty. name {
131
+ // auto traits are not implemented for foreign types
132
+ TypeName :: Foreign ( _) => return ,
133
+
134
+ // closures require binders, while the other types do not
135
+ TypeName :: Closure ( closure_id) => {
136
+ let binders = builder
137
+ . db
138
+ . closure_upvars ( closure_id, & Substitution :: empty ( interner) ) ;
139
+ builder. push_binders ( & binders, |builder, upvar_ty| {
140
+ let conditions = iter:: once ( mk_ref ( upvar_ty) ) ;
141
+ builder. push_clause ( consequence, conditions) ;
142
+ } ) ;
83
143
}
84
- . intern ( interner) ;
85
144
86
- // trait_ref = `MyStruct<...>: MyAutoTrait`
87
- let auto_trait_ref = TraitRef {
88
- trait_id : auto_trait_id ,
89
- substitution : Substitution :: from1 ( interner , self_ty ) ,
90
- } ;
145
+ // app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait
146
+ _ => {
147
+ let conditions = constituent_types ( builder . db , app_ty )
148
+ . into_iter ( )
149
+ . map ( mk_ref ) ;
91
150
92
- // forall<P0..Pn> { // generic parameters from struct
93
- // MyStruct<...>: MyAutoTrait :-
94
- // Field0: MyAutoTrait,
95
- // ...
96
- // FieldN: MyAutoTrait
97
- // }
98
- builder. push_clause (
99
- auto_trait_ref,
100
- variants. iter ( ) . flat_map ( |variant| {
101
- variant. fields . iter ( ) . map ( |field_ty| TraitRef {
102
- trait_id : auto_trait_id,
103
- substitution : Substitution :: from1 ( interner, field_ty. clone ( ) ) ,
104
- } )
105
- } ) ,
106
- ) ;
107
- } ) ;
151
+ builder. push_clause ( consequence, conditions) ;
152
+ }
153
+ }
108
154
}
109
155
110
156
/// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs.
@@ -253,13 +299,20 @@ fn program_clauses_that_could_match<I: Interner>(
253
299
// the automatic impls for `Foo`.
254
300
let trait_datum = db. trait_datum ( trait_id) ;
255
301
if trait_datum. is_auto_trait ( ) {
256
- match trait_ref. self_type_parameter ( interner) . data ( interner) {
257
- TyData :: Apply ( apply) => match & apply. name {
258
- TypeName :: Adt ( adt_id) => {
259
- push_auto_trait_impls ( builder, trait_id, * adt_id) ;
260
- }
261
- _ => { }
262
- } ,
302
+ let ty = trait_ref. self_type_parameter ( interner) ;
303
+ match ty. data ( interner) {
304
+ TyData :: Apply ( apply) => {
305
+ push_auto_trait_impls ( builder, trait_id, apply) ;
306
+ }
307
+ // function-types implement auto traits unconditionally
308
+ TyData :: Function ( _) => {
309
+ let auto_trait_ref = TraitRef {
310
+ trait_id,
311
+ substitution : Substitution :: from1 ( interner, ty. cast ( interner) ) ,
312
+ } ;
313
+
314
+ builder. push_fact ( auto_trait_ref) ;
315
+ }
263
316
TyData :: InferenceVar ( _, _) | TyData :: BoundVar ( _) => {
264
317
return Err ( Floundered ) ;
265
318
}
0 commit comments