38
38
39
39
use crate :: { ImplTraitPosition , ResolverAstLoweringExt } ;
40
40
41
- use super :: { ImplTraitContext , LoweringContext , ParamMode } ;
41
+ use super :: { ImplTraitContext , LoweringContext , ParamMode , ParenthesizedGenericArgs } ;
42
42
43
43
use ast:: visit:: Visitor ;
44
44
use hir:: def:: { DefKind , PartialRes , Res } ;
@@ -66,15 +66,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
66
66
let Ok ( sig_id) = sig_id else {
67
67
return false ;
68
68
} ;
69
- if let Some ( local_sig_id) = sig_id. as_local ( ) {
70
- self . resolver . delegation_fn_sigs [ & local_sig_id] . has_self
71
- } else {
72
- match self . tcx . def_kind ( sig_id) {
73
- DefKind :: Fn => false ,
74
- DefKind :: AssocFn => self . tcx . associated_item ( sig_id) . fn_has_self_parameter ,
75
- _ => span_bug ! ( span, "unexpected DefKind for delegation item" ) ,
76
- }
77
- }
69
+ self . has_self ( sig_id, span)
78
70
}
79
71
80
72
pub ( crate ) fn lower_delegation (
@@ -105,12 +97,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
105
97
span : Span ,
106
98
) -> Result < DefId , ErrorGuaranteed > {
107
99
let sig_id = if self . is_in_trait_impl { item_id } else { path_id } ;
108
- let sig_id =
109
- self . resolver . get_partial_res ( sig_id) . and_then ( |r| r. expect_full_res ( ) . opt_def_id ( ) ) ;
110
- sig_id. ok_or_else ( || {
111
- self . tcx
112
- . dcx ( )
113
- . span_delayed_bug ( span, "LoweringContext: couldn't resolve delegation item" )
100
+ self . get_resolution_id ( sig_id, span)
101
+ }
102
+
103
+ fn has_self ( & self , def_id : DefId , span : Span ) -> bool {
104
+ if let Some ( local_sig_id) = def_id. as_local ( ) {
105
+ self . resolver . delegation_fn_sigs . get ( & local_sig_id) . map_or ( false , |sig| sig. has_self )
106
+ } else {
107
+ match self . tcx . def_kind ( def_id) {
108
+ DefKind :: Fn => false ,
109
+ DefKind :: AssocFn => self . tcx . associated_item ( def_id) . fn_has_self_parameter ,
110
+ _ => span_bug ! ( span, "unexpected DefKind for delegation item" ) ,
111
+ }
112
+ }
113
+ }
114
+
115
+ fn get_resolution_id ( & self , node_id : NodeId , span : Span ) -> Result < DefId , ErrorGuaranteed > {
116
+ let def_id =
117
+ self . resolver . get_partial_res ( node_id) . and_then ( |r| r. expect_full_res ( ) . opt_def_id ( ) ) ;
118
+ def_id. ok_or_else ( || {
119
+ self . tcx . dcx ( ) . span_delayed_bug (
120
+ span,
121
+ format ! ( "LoweringContext: couldn't resolve node {:?} in delegation item" , node_id) ,
122
+ )
114
123
} )
115
124
}
116
125
@@ -120,7 +129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
120
129
predicates : & [ ] ,
121
130
has_where_clause_predicates : false ,
122
131
where_clause_span : span,
123
- span : span ,
132
+ span,
124
133
} )
125
134
}
126
135
@@ -220,12 +229,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
220
229
} ) ) ;
221
230
222
231
let path = self . arena . alloc ( hir:: Path { span, res : Res :: Local ( param_id) , segments } ) ;
223
-
224
- hir:: Expr {
225
- hir_id : self . next_id ( ) ,
226
- kind : hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) ,
227
- span,
228
- }
232
+ self . mk_expr ( hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) , span)
229
233
}
230
234
231
235
fn lower_delegation_body (
@@ -234,25 +238,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
234
238
param_count : usize ,
235
239
span : Span ,
236
240
) -> BodyId {
237
- let path = self . lower_qpath (
238
- delegation. id ,
239
- & delegation. qself ,
240
- & delegation. path ,
241
- ParamMode :: Optional ,
242
- ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
243
- None ,
244
- ) ;
245
241
let block = delegation. body . as_deref ( ) ;
246
242
247
243
self . lower_body ( |this| {
248
- let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
249
- let mut args: Vec < hir:: Expr < ' hir > > = Vec :: new ( ) ;
244
+ let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: with_capacity ( param_count) ;
245
+ let mut args: Vec < hir:: Expr < ' _ > > = Vec :: with_capacity ( param_count) ;
246
+ let mut target_expr = None ;
250
247
251
248
for idx in 0 ..param_count {
252
249
let ( param, pat_node_id) = this. generate_param ( span) ;
253
250
parameters. push ( param) ;
254
251
255
- let arg = if let Some ( block) = block
252
+ if let Some ( block) = block
256
253
&& idx == 0
257
254
{
258
255
let mut self_resolver = SelfResolver {
@@ -261,56 +258,103 @@ impl<'hir> LoweringContext<'_, 'hir> {
261
258
self_param_id : pat_node_id,
262
259
} ;
263
260
self_resolver. visit_block ( block) ;
264
- let block = this. lower_block ( block, false ) ;
265
- hir:: Expr {
266
- hir_id : this. next_id ( ) ,
267
- kind : hir:: ExprKind :: Block ( block, None ) ,
268
- span : block. span ,
269
- }
261
+ target_expr = Some ( this. lower_block_noalloc ( block, false ) ) ;
270
262
} else {
271
263
let pat_hir_id = this. lower_node_id ( pat_node_id) ;
272
- this. generate_arg ( pat_hir_id, span)
264
+ let arg = this. generate_arg ( pat_hir_id, span) ;
265
+ args. push ( arg) ;
273
266
} ;
274
- args. push ( arg) ;
275
267
}
276
268
277
- let args = self . arena . alloc_from_iter ( args) ;
278
- let final_expr = this. generate_call ( path, args) ;
269
+ let final_expr = this. finalize_body_lowering ( delegation, target_expr, args, span) ;
279
270
( this. arena . alloc_from_iter ( parameters) , final_expr)
280
271
} )
281
272
}
282
273
283
- fn generate_call (
274
+ // Generates expression for the resulting body. If possible, `MethodCall` is used
275
+ // instead of fully qualified call for the self type coercion. See `consider_candidates`
276
+ // for more information.
277
+ fn finalize_body_lowering (
284
278
& mut self ,
285
- path : hir:: QPath < ' hir > ,
286
- args : & ' hir [ hir:: Expr < ' hir > ] ,
279
+ delegation : & Delegation ,
280
+ target_expr : Option < hir:: Block < ' hir > > ,
281
+ mut args : Vec < hir:: Expr < ' hir > > ,
282
+ span : Span ,
287
283
) -> hir:: Expr < ' hir > {
288
- let callee = self . arena . alloc ( hir:: Expr {
289
- hir_id : self . next_id ( ) ,
290
- kind : hir:: ExprKind :: Path ( path) ,
291
- span : path. span ( ) ,
292
- } ) ;
284
+ let ( stmts, call, block_id) = if self
285
+ . get_resolution_id ( delegation. id , span)
286
+ . and_then ( |def_id| Ok ( self . has_self ( def_id, span) ) )
287
+ . unwrap_or_default ( )
288
+ && delegation. qself . is_none ( )
289
+ {
290
+ let ast_segment = delegation. path . segments . last ( ) . unwrap ( ) ;
291
+ let segment = self . lower_path_segment (
292
+ delegation. path . span ,
293
+ ast_segment,
294
+ ParamMode :: Optional ,
295
+ ParenthesizedGenericArgs :: Err ,
296
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
297
+ None ,
298
+ None ,
299
+ ) ;
300
+ let segment = self . arena . alloc ( segment) ;
301
+
302
+ let args = & * self . arena . alloc_from_iter ( args) ;
303
+ let ( stmts, receiver, args, block_id) = if let Some ( target_expr) = target_expr {
304
+ // Use unit type as a receiver if no expression is provided.
305
+ let receiver = target_expr. expr . unwrap_or_else ( || {
306
+ self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Tup ( & [ ] ) , span) )
307
+ } ) ;
308
+ ( target_expr. stmts , receiver, args, target_expr. hir_id )
309
+ } else {
310
+ ( & * self . arena . alloc_from_iter ( [ ] ) , & args[ 0 ] , & args[ 1 ..] , self . next_id ( ) )
311
+ } ;
293
312
294
- let expr = self . arena . alloc ( hir:: Expr {
295
- hir_id : self . next_id ( ) ,
296
- kind : hir:: ExprKind :: Call ( callee, args) ,
297
- span : path. span ( ) ,
298
- } ) ;
313
+ let method_call_id = self . next_id ( ) ;
314
+ if let Some ( traits) = self . resolver . delegation_trait_map . remove ( & delegation. id ) {
315
+ self . trait_map . insert ( method_call_id. local_id , traits. into_boxed_slice ( ) ) ;
316
+ }
317
+
318
+ let method_call = self . arena . alloc ( hir:: Expr {
319
+ hir_id : method_call_id,
320
+ kind : hir:: ExprKind :: MethodCall ( segment, receiver, args, span) ,
321
+ span,
322
+ } ) ;
323
+
324
+ ( stmts, method_call, block_id)
325
+ } else {
326
+ let path = self . lower_qpath (
327
+ delegation. id ,
328
+ & delegation. qself ,
329
+ & delegation. path ,
330
+ ParamMode :: Optional ,
331
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
332
+ None ,
333
+ ) ;
334
+
335
+ if let Some ( target_expr) = target_expr {
336
+ let target_expr = self . arena . alloc ( target_expr) ;
337
+ let fst_arg =
338
+ self . mk_expr ( hir:: ExprKind :: Block ( target_expr, None ) , target_expr. span ) ;
339
+ args. insert ( 0 , fst_arg) ;
340
+ }
299
341
342
+ let args = self . arena . alloc_from_iter ( args) ;
343
+ let callee_path = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Path ( path) , span) ) ;
344
+
345
+ let call = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Call ( callee_path, args) , span) ) ;
346
+
347
+ ( & * self . arena . alloc_from_iter ( [ ] ) , call, self . next_id ( ) )
348
+ } ;
300
349
let block = self . arena . alloc ( hir:: Block {
301
- stmts : & [ ] ,
302
- expr : Some ( expr ) ,
303
- hir_id : self . next_id ( ) ,
350
+ stmts,
351
+ expr : Some ( call ) ,
352
+ hir_id : block_id ,
304
353
rules : hir:: BlockCheckMode :: DefaultBlock ,
305
- span : path . span ( ) ,
354
+ span,
306
355
targeted_by_break : false ,
307
356
} ) ;
308
-
309
- hir:: Expr {
310
- hir_id : self . next_id ( ) ,
311
- kind : hir:: ExprKind :: Block ( block, None ) ,
312
- span : path. span ( ) ,
313
- }
357
+ self . mk_expr ( hir:: ExprKind :: Block ( block, None ) , span)
314
358
}
315
359
316
360
fn generate_delegation_error (
@@ -331,11 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
331
375
let header = self . generate_header_error ( ) ;
332
376
let sig = hir:: FnSig { decl, header, span } ;
333
377
334
- let body_id = self . lower_body ( |this| {
335
- let expr =
336
- hir:: Expr { hir_id : this. next_id ( ) , kind : hir:: ExprKind :: Err ( err) , span : span } ;
337
- ( & [ ] , expr)
338
- } ) ;
378
+ let body_id = self . lower_body ( |this| ( & [ ] , this. mk_expr ( hir:: ExprKind :: Err ( err) , span) ) ) ;
339
379
DelegationResults { generics, body_id, sig }
340
380
}
341
381
@@ -347,6 +387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
347
387
abi : abi:: Abi :: Rust ,
348
388
}
349
389
}
390
+
391
+ #[ inline]
392
+ fn mk_expr ( & mut self , kind : hir:: ExprKind < ' hir > , span : Span ) -> hir:: Expr < ' hir > {
393
+ hir:: Expr { hir_id : self . next_id ( ) , kind, span }
394
+ }
350
395
}
351
396
352
397
struct SelfResolver < ' a > {
0 commit comments