1
+ use itertools:: Itertools ;
1
2
use rustc_data_structures:: fx:: FxHashMap ;
2
3
use rustc_hir:: def:: DefKind ;
3
4
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
4
5
use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
5
6
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
6
7
use rustc_span:: ErrorGuaranteed ;
8
+ use rustc_type_ir:: visit:: TypeVisitableExt ;
7
9
8
10
type RemapTable = FxHashMap < u32 , u32 > ;
9
11
@@ -18,21 +20,39 @@ impl<'tcx, 'a> TypeFolder<TyCtxt<'tcx>> for IndicesFolder<'tcx, 'a> {
18
20
}
19
21
20
22
fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
21
- if let ty:: Param ( param) = ty. kind ( ) {
22
- return Ty :: new_param ( self . tcx , self . remap_table [ & param. index ] , param. name ) ;
23
+ if !ty. has_param ( ) {
24
+ return ty;
25
+ }
26
+
27
+ if let ty:: Param ( param) = ty. kind ( )
28
+ && let Some ( idx) = self . remap_table . get ( & param. index )
29
+ {
30
+ return Ty :: new_param ( self . tcx , * idx, param. name ) ;
23
31
}
24
32
ty. super_fold_with ( self )
25
33
}
26
34
27
35
fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
28
- if let ty:: ReEarlyParam ( param) = r. kind ( ) {
36
+ if let ty:: ReEarlyParam ( param) = r. kind ( )
37
+ && let Some ( idx) = self . remap_table . get ( & param. index )
38
+ {
29
39
return ty:: Region :: new_early_param (
30
40
self . tcx ,
31
- ty:: EarlyParamRegion { index : self . remap_table [ & param . index ] , name : param. name } ,
41
+ ty:: EarlyParamRegion { index : * idx , name : param. name } ,
32
42
) ;
33
43
}
34
44
r
35
45
}
46
+
47
+ fn fold_const ( & mut self , ct : ty:: Const < ' tcx > ) -> ty:: Const < ' tcx > {
48
+ if let ty:: ConstKind :: Param ( param) = ct. kind ( )
49
+ && let Some ( idx) = self . remap_table . get ( & param. index )
50
+ {
51
+ let param = ty:: ParamConst :: new ( * idx, param. name ) ;
52
+ return ty:: Const :: new_param ( self . tcx , param, ct. ty ( ) ) ;
53
+ }
54
+ ct. super_fold_with ( self )
55
+ }
36
56
}
37
57
38
58
#[ derive( Clone , Copy , Debug , PartialEq ) ]
@@ -55,28 +75,76 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
55
75
}
56
76
}
57
77
58
- // Lifetime parameters must be declared before type and const parameters.
59
- // Therefore, When delegating from a free function to a associated function,
60
- // generic parameters need to be reordered:
61
- //
62
- // trait Trait<'a, A> {
63
- // fn foo<'b, B>(...) {...}
64
- // }
65
- //
66
- // reuse Trait::foo;
67
- // desugaring:
68
- // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
69
- // Trait::foo(...)
70
- // }
71
- fn create_remap_table < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId , sig_id : DefId ) -> RemapTable {
78
+ fn create_generic_args < ' tcx > (
79
+ tcx : TyCtxt < ' tcx > ,
80
+ def_id : LocalDefId ,
81
+ sig_id : DefId ,
82
+ ) -> ty:: GenericArgsRef < ' tcx > {
72
83
let caller_generics = tcx. generics_of ( def_id) ;
73
84
let callee_generics = tcx. generics_of ( sig_id) ;
74
- let mut remap_table: RemapTable = FxHashMap :: default ( ) ;
75
- for caller_param in & caller_generics. own_params {
76
- let callee_index = callee_generics. param_def_id_to_index ( tcx, caller_param. def_id ) . unwrap ( ) ;
77
- remap_table. insert ( callee_index, caller_param. index ) ;
85
+
86
+ let caller_kind = fn_kind ( tcx, def_id. into ( ) ) ;
87
+ let callee_kind = fn_kind ( tcx, sig_id) ;
88
+ // FIXME(fn_delegation): early bound generics are only supported for trait
89
+ // implementations and free functions. Error was reported in `check_constraints`.
90
+ match ( caller_kind, callee_kind) {
91
+ ( FnKind :: Free , _) => {
92
+ let args = ty:: GenericArgs :: identity_for_item ( tcx, sig_id) ;
93
+ // Lifetime parameters must be declared before type and const parameters.
94
+ // Therefore, When delegating from a free function to a associated function,
95
+ // generic parameters need to be reordered:
96
+ //
97
+ // trait Trait<'a, A> {
98
+ // fn foo<'b, B>(...) {...}
99
+ // }
100
+ //
101
+ // reuse Trait::foo;
102
+ // desugaring:
103
+ // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
104
+ // Trait::foo(...)
105
+ // }
106
+ let mut remap_table: RemapTable = FxHashMap :: default ( ) ;
107
+ for caller_param in & caller_generics. own_params {
108
+ let callee_index =
109
+ callee_generics. param_def_id_to_index ( tcx, caller_param. def_id ) . unwrap ( ) ;
110
+ remap_table. insert ( callee_index, caller_param. index ) ;
111
+ }
112
+ let mut folder = IndicesFolder { tcx, remap_table : & remap_table } ;
113
+ args. fold_with ( & mut folder)
114
+ }
115
+ ( FnKind :: AssocTraitImpl , FnKind :: AssocTrait ) => {
116
+ let parent = tcx. parent ( def_id. into ( ) ) ;
117
+ let parent_args =
118
+ tcx. impl_trait_header ( parent) . unwrap ( ) . trait_ref . instantiate_identity ( ) . args ;
119
+
120
+ let callee_generics = tcx. generics_of ( sig_id) ;
121
+ let trait_args = ty:: GenericArgs :: identity_for_item ( tcx, sig_id) ;
122
+ let method_args = trait_args. iter ( ) . skip ( callee_generics. parent_count ) . collect_vec ( ) ;
123
+
124
+ // For trait implementations only the method's own parameters are copied.
125
+ // They need to be reindexed adjusted for impl parameters.
126
+ let mut remap_table: RemapTable = FxHashMap :: default ( ) ;
127
+ let parent_count = caller_generics. parent_count as u32 ;
128
+ for ( idx, callee_own_param) in callee_generics. own_params . iter ( ) . enumerate ( ) {
129
+ let callee_index = callee_own_param. index as u32 ;
130
+ remap_table. insert ( callee_index, idx as u32 + parent_count) ;
131
+ }
132
+ let mut folder = IndicesFolder { tcx, remap_table : & remap_table } ;
133
+ let method_args = method_args. fold_with ( & mut folder) ;
134
+
135
+ tcx. mk_args_from_iter ( parent_args. iter ( ) . chain ( method_args) )
136
+ }
137
+ // only `Self` param supported here
138
+ ( FnKind :: AssocInherentImpl , FnKind :: AssocTrait ) => {
139
+ let parent = tcx. parent ( def_id. into ( ) ) ;
140
+ let self_ty = tcx. type_of ( parent) . instantiate_identity ( ) ;
141
+ let generic_self_ty = ty:: GenericArg :: from ( self_ty) ;
142
+ tcx. mk_args_from_iter ( std:: iter:: once ( generic_self_ty) )
143
+ }
144
+ // `sig_id` is taken from corresponding trait method
145
+ ( FnKind :: AssocTraitImpl , _) => unreachable ! ( ) ,
146
+ _ => ty:: GenericArgs :: identity_for_item ( tcx, sig_id) ,
78
147
}
79
- remap_table
80
148
}
81
149
82
150
pub ( crate ) fn inherit_generics_for_delegation_item < ' tcx > (
@@ -87,8 +155,12 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
87
155
let caller_kind = fn_kind ( tcx, def_id. into ( ) ) ;
88
156
let callee_kind = fn_kind ( tcx, sig_id) ;
89
157
90
- // FIXME(fn_delegation): Support generics on associated delegation items.
91
- // Error was reported in `check_delegation_constraints`.
158
+ let param_def_id_to_index = |own_params : & Vec < ty:: GenericParamDef > | {
159
+ own_params. iter ( ) . map ( |param| ( param. def_id , param. index ) ) . collect ( )
160
+ } ;
161
+
162
+ // FIXME(fn_delegation): early bound generics are only supported for trait
163
+ // implementations and free functions. Error was reported in `check_constraints`.
92
164
match ( caller_kind, callee_kind) {
93
165
( FnKind :: Free , _) => {
94
166
let mut own_params = vec ! [ ] ;
@@ -112,14 +184,33 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
112
184
}
113
185
}
114
186
115
- let param_def_id_to_index =
116
- own_params. iter ( ) . map ( |param| ( param. def_id , param. index ) ) . collect ( ) ;
117
-
118
187
Some ( ty:: Generics {
119
188
parent : None ,
120
189
parent_count : 0 ,
190
+ param_def_id_to_index : param_def_id_to_index ( & own_params) ,
191
+ own_params,
192
+ has_self : false ,
193
+ has_late_bound_regions : callee_generics. has_late_bound_regions ,
194
+ host_effect_index : None ,
195
+ } )
196
+ }
197
+ ( FnKind :: AssocTraitImpl , FnKind :: AssocTrait ) => {
198
+ let callee_generics = tcx. generics_of ( sig_id) ;
199
+
200
+ let parent = tcx. parent ( def_id. into ( ) ) ;
201
+ let parent_generics = tcx. generics_of ( parent) ;
202
+ let parent_count = parent_generics. count ( ) ;
203
+
204
+ let mut own_params = tcx. generics_of ( sig_id) . own_params . clone ( ) ;
205
+ for ( idx, param) in own_params. iter_mut ( ) . enumerate ( ) {
206
+ param. index = ( parent_count + idx) as u32 ;
207
+ }
208
+
209
+ Some ( ty:: Generics {
210
+ parent : Some ( parent) ,
211
+ parent_count,
212
+ param_def_id_to_index : param_def_id_to_index ( & own_params) ,
121
213
own_params,
122
- param_def_id_to_index,
123
214
has_self : false ,
124
215
has_late_bound_regions : callee_generics. has_late_bound_regions ,
125
216
host_effect_index : None ,
@@ -134,41 +225,38 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
134
225
def_id : LocalDefId ,
135
226
sig_id : DefId ,
136
227
) -> Option < ty:: GenericPredicates < ' tcx > > {
228
+ // FIXME(fn_delegation): early bound generics are only supported for trait
229
+ // implementations and free functions. Error was reported in `check_constraints`.
137
230
let caller_kind = fn_kind ( tcx, def_id. into ( ) ) ;
138
- let callee_kind = fn_kind ( tcx, sig_id) ;
139
-
140
- // FIXME(fn_delegation): Support generics on associated delegation items.
141
- // Error was reported in `check_delegation_constraints`.
142
- match ( caller_kind, callee_kind) {
143
- ( FnKind :: Free , _) => {
144
- let mut predicates = vec ! [ ] ;
145
- let callee_predicates = tcx. predicates_of ( sig_id) ;
146
- if let Some ( parent_sig_id) = callee_predicates. parent {
147
- let parent_sig_predicates = tcx. predicates_of ( parent_sig_id) ;
148
- predicates. extend_from_slice ( parent_sig_predicates. predicates ) ;
149
- }
150
- predicates. extend_from_slice ( callee_predicates. predicates ) ;
231
+ if caller_kind != FnKind :: Free && caller_kind != FnKind :: AssocTraitImpl {
232
+ return None ;
233
+ }
151
234
152
- let remap_table = create_remap_table ( tcx, def_id, sig_id) ;
153
- let mut folder = IndicesFolder { tcx, remap_table : & remap_table } ;
154
- let predicates = predicates. fold_with ( & mut folder) ;
235
+ let callee_predicates = tcx. predicates_of ( sig_id) ;
236
+ let args = create_generic_args ( tcx, def_id, sig_id) ;
155
237
156
- Some ( ty:: GenericPredicates {
157
- parent : None ,
158
- predicates : tcx. arena . alloc_from_iter ( predicates) ,
159
- } )
160
- }
161
- _ => None ,
238
+ let mut preds = vec ! [ ] ;
239
+ if let Some ( parent_id) = callee_predicates. parent {
240
+ preds. extend ( tcx. predicates_of ( parent_id) . instantiate_own ( tcx, args) ) ;
162
241
}
242
+ preds. extend ( callee_predicates. instantiate_own ( tcx, args) ) ;
243
+
244
+ let parent = match fn_kind ( tcx, def_id. to_def_id ( ) ) {
245
+ FnKind :: Free => None ,
246
+ _ => Some ( tcx. parent ( def_id. into ( ) ) ) ,
247
+ } ;
248
+
249
+ Some ( ty:: GenericPredicates { parent, predicates : tcx. arena . alloc_from_iter ( preds) } )
163
250
}
164
251
165
252
fn check_constraints < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) -> Result < ( ) , ErrorGuaranteed > {
166
253
let mut ret = Ok ( ( ) ) ;
167
254
let sig_id = tcx. hir ( ) . delegation_sig_id ( def_id) ;
255
+ let span = tcx. def_span ( def_id) ;
168
256
169
257
let mut emit = |descr| {
170
258
ret = Err ( tcx. dcx ( ) . emit_err ( crate :: errors:: UnsupportedDelegation {
171
- span : tcx . def_span ( def_id ) ,
259
+ span,
172
260
descr,
173
261
callee_span : tcx. def_span ( sig_id) ,
174
262
} ) ) ;
@@ -177,20 +265,33 @@ fn check_constraints<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Result<(),
177
265
if let Some ( local_sig_id) = sig_id. as_local ( )
178
266
&& tcx. hir ( ) . opt_delegation_sig_id ( local_sig_id) . is_some ( )
179
267
{
180
- emit ( "recursive delegation" ) ;
268
+ emit ( "recursive delegation is not supported yet " ) ;
181
269
}
182
270
183
271
let caller_kind = fn_kind ( tcx, def_id. into ( ) ) ;
184
- if caller_kind != FnKind :: Free {
185
- let sig_generics = tcx. generics_of ( sig_id) ;
186
- let parent = tcx. parent ( def_id. into ( ) ) ;
187
- let parent_generics = tcx. generics_of ( parent) ;
272
+ let callee_kind = fn_kind ( tcx, sig_id) ;
273
+
274
+ match ( caller_kind, callee_kind) {
275
+ ( FnKind :: Free , _) | ( FnKind :: AssocTraitImpl , FnKind :: AssocTrait ) => { }
276
+ // `sig_id` is taken from corresponding trait method
277
+ ( FnKind :: AssocTraitImpl , _) => {
278
+ return Err ( tcx
279
+ . dcx ( )
280
+ . span_delayed_bug ( span, "unexpected callee path resolution in delegation item" ) ) ;
281
+ }
282
+ _ => {
283
+ let sig_generics = tcx. generics_of ( sig_id) ;
284
+ let parent = tcx. parent ( def_id. into ( ) ) ;
285
+ let parent_generics = tcx. generics_of ( parent) ;
188
286
189
- let parent_is_trait = ( tcx . def_kind ( parent ) == DefKind :: Trait ) as usize ;
190
- let sig_has_self = sig_generics . has_self as usize ;
287
+ let sig_has_self = sig_generics . has_self as usize ;
288
+ let parent_has_self = parent_generics . has_self as usize ;
191
289
192
- if sig_generics. count ( ) > sig_has_self || parent_generics. count ( ) > parent_is_trait {
193
- emit ( "early bound generics are not supported for associated delegation items" ) ;
290
+ if sig_generics. count ( ) > sig_has_self || parent_generics. count ( ) > parent_has_self {
291
+ emit (
292
+ "early bound generics are only supported for trait implementations and free functions" ,
293
+ ) ;
294
+ }
194
295
}
195
296
}
196
297
@@ -208,32 +309,11 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
208
309
let err_type = Ty :: new_error ( tcx, err) ;
209
310
return tcx. arena . alloc_from_iter ( ( 0 ..sig_len) . map ( |_| err_type) ) ;
210
311
}
312
+ let args = create_generic_args ( tcx, def_id, sig_id) ;
211
313
212
- let caller_kind = fn_kind ( tcx, def_id. into ( ) ) ;
213
- let callee_kind = fn_kind ( tcx, sig_id) ;
214
-
215
- // FIXME(fn_delegation): Support generics on associated delegation items.
216
- // Error was reported in `check_constraints`.
217
- let sig = match ( caller_kind, callee_kind) {
218
- ( FnKind :: Free , _) => {
219
- let remap_table = create_remap_table ( tcx, def_id, sig_id) ;
220
- let mut folder = IndicesFolder { tcx, remap_table : & remap_table } ;
221
- caller_sig. instantiate_identity ( ) . fold_with ( & mut folder)
222
- }
223
- // only `Self` param supported here
224
- ( FnKind :: AssocTraitImpl , FnKind :: AssocTrait )
225
- | ( FnKind :: AssocInherentImpl , FnKind :: AssocTrait ) => {
226
- let parent = tcx. parent ( def_id. into ( ) ) ;
227
- let self_ty = tcx. type_of ( parent) . instantiate_identity ( ) ;
228
- let generic_self_ty = ty:: GenericArg :: from ( self_ty) ;
229
- let args = tcx. mk_args_from_iter ( std:: iter:: once ( generic_self_ty) ) ;
230
- caller_sig. instantiate ( tcx, args)
231
- }
232
- _ => caller_sig. instantiate_identity ( ) ,
233
- } ;
234
314
// Bound vars are also inherited from `sig_id`.
235
315
// They will be rebound later in `lower_fn_ty`.
236
- let sig = sig . skip_binder ( ) ;
316
+ let sig = caller_sig . instantiate ( tcx , args ) . skip_binder ( ) ;
237
317
let sig_it = sig. inputs ( ) . iter ( ) . cloned ( ) . chain ( std:: iter:: once ( sig. output ( ) ) ) ;
238
318
tcx. arena . alloc_from_iter ( sig_it)
239
319
}
0 commit comments