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 } ;
@@ -245,12 +245,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
245
245
self . lower_body ( |this| {
246
246
let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: with_capacity ( param_count) ;
247
247
let mut args: Vec < hir:: Expr < ' _ > > = Vec :: with_capacity ( param_count) ;
248
+ let mut target_expr = None ;
248
249
249
250
for idx in 0 ..param_count {
250
251
let ( param, pat_node_id) = this. generate_param ( span) ;
251
252
parameters. push ( param) ;
252
253
253
- let arg = if let Some ( block) = block
254
+ if let Some ( block) = block
254
255
&& idx == 0
255
256
{
256
257
let mut self_resolver = SelfResolver {
@@ -259,44 +260,105 @@ impl<'hir> LoweringContext<'_, 'hir> {
259
260
self_param_id : pat_node_id,
260
261
} ;
261
262
self_resolver. visit_block ( block) ;
262
- let block = this. lower_block ( block, false ) ;
263
- this. mk_expr ( hir:: ExprKind :: Block ( block, None ) , block. span )
263
+ let mut block = this. lower_block_noalloc ( block, false ) ;
264
+ if block. expr . is_none ( ) {
265
+ let pat_hir_id = this. lower_node_id ( pat_node_id) ;
266
+ let arg = & * this. arena . alloc ( this. generate_arg ( pat_hir_id, span) ) ;
267
+ // Use `self` as a first argument if no expression is provided.
268
+ block. expr = Some ( arg) ;
269
+ }
270
+ target_expr = Some ( block) ;
264
271
} else {
265
272
let pat_hir_id = this. lower_node_id ( pat_node_id) ;
266
- this. generate_arg ( pat_hir_id, span)
273
+ let arg = this. generate_arg ( pat_hir_id, span) ;
274
+ args. push ( arg) ;
267
275
} ;
268
- args. push ( arg) ;
269
276
}
270
277
271
- let final_expr = this. finalize_body_lowering ( delegation, args, span) ;
278
+ let final_expr = this. finalize_body_lowering ( delegation, target_expr , args, span) ;
272
279
( this. arena . alloc_from_iter ( parameters) , final_expr)
273
280
} )
274
281
}
275
282
276
- // Generates fully qualified call for the resulting body.
283
+ // Generates expression for the resulting body. If possible, `MethodCall` is used
284
+ // instead of fully qualified call for the self type coercion.
277
285
fn finalize_body_lowering (
278
286
& mut self ,
279
287
delegation : & Delegation ,
280
- args : Vec < hir:: Expr < ' hir > > ,
288
+ target_expr : Option < hir:: Block < ' hir > > ,
289
+ mut args : Vec < hir:: Expr < ' hir > > ,
281
290
span : Span ,
282
291
) -> hir:: Expr < ' hir > {
283
- let path = self . lower_qpath (
284
- delegation. id ,
285
- & delegation. qself ,
286
- & delegation. path ,
287
- ParamMode :: Optional ,
288
- ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
289
- None ,
290
- ) ;
291
-
292
- let args = self . arena . alloc_from_iter ( args) ;
293
- let path_expr = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Path ( path) , span) ) ;
294
- let call = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Call ( path_expr, args) , span) ) ;
292
+ let has_generic_args =
293
+ delegation. path . segments . iter ( ) . rev ( ) . skip ( 1 ) . any ( |segment| segment. args . is_some ( ) ) ;
294
+
295
+ let ( stmts, call, block_id) = if self
296
+ . get_resolution_id ( delegation. id , span)
297
+ . and_then ( |def_id| Ok ( self . has_self ( def_id, span) ) )
298
+ . unwrap_or_default ( )
299
+ && delegation. qself . is_none ( )
300
+ && !has_generic_args
301
+ {
302
+ let ast_segment = delegation. path . segments . last ( ) . unwrap ( ) ;
303
+ let segment = self . lower_path_segment (
304
+ delegation. path . span ,
305
+ ast_segment,
306
+ ParamMode :: Optional ,
307
+ ParenthesizedGenericArgs :: Err ,
308
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
309
+ None ,
310
+ None ,
311
+ ) ;
312
+ let segment = self . arena . alloc ( segment) ;
313
+
314
+ let args = & * self . arena . alloc_from_iter ( args) ;
315
+ let ( stmts, receiver, args, block_id) = if let Some ( target_expr) = target_expr {
316
+ let receiver = target_expr. expr . unwrap ( ) ;
317
+ ( Some ( target_expr. stmts ) , receiver, args, target_expr. hir_id )
318
+ } else {
319
+ ( None , & args[ 0 ] , & args[ 1 ..] , self . next_id ( ) )
320
+ } ;
321
+
322
+ let method_call_id = self . next_id ( ) ;
323
+ if let Some ( traits) = self . resolver . trait_map . remove ( & delegation. id ) {
324
+ self . trait_map . insert ( method_call_id. local_id , traits. into_boxed_slice ( ) ) ;
325
+ }
295
326
327
+ let method_call = self . arena . alloc ( hir:: Expr {
328
+ hir_id : method_call_id,
329
+ kind : hir:: ExprKind :: MethodCall ( segment, receiver, args, span) ,
330
+ span,
331
+ } ) ;
332
+
333
+ ( stmts, method_call, block_id)
334
+ } else {
335
+ let path = self . lower_qpath (
336
+ delegation. id ,
337
+ & delegation. qself ,
338
+ & delegation. path ,
339
+ ParamMode :: Optional ,
340
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
341
+ None ,
342
+ ) ;
343
+
344
+ if let Some ( target_expr) = target_expr {
345
+ let target_expr = self . arena . alloc ( target_expr) ;
346
+ let fst_arg =
347
+ self . mk_expr ( hir:: ExprKind :: Block ( target_expr, None ) , target_expr. span ) ;
348
+ args. insert ( 0 , fst_arg) ;
349
+ }
350
+
351
+ let args = self . arena . alloc_from_iter ( args) ;
352
+ let callee_path = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Path ( path) , span) ) ;
353
+
354
+ let call = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Call ( callee_path, args) , span) ) ;
355
+
356
+ ( None , call, self . next_id ( ) )
357
+ } ;
296
358
let block = self . arena . alloc ( hir:: Block {
297
- stmts : & [ ] ,
359
+ stmts : stmts . unwrap_or ( & [ ] ) ,
298
360
expr : Some ( call) ,
299
- hir_id : self . next_id ( ) ,
361
+ hir_id : block_id ,
300
362
rules : hir:: BlockCheckMode :: DefaultBlock ,
301
363
span,
302
364
targeted_by_break : false ,
0 commit comments