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 } ;
@@ -259,8 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
259
259
self_param_id : pat_node_id,
260
260
} ;
261
261
self_resolver. visit_block ( block) ;
262
- let block = this. lower_block ( block, false ) ;
263
- this. mk_expr ( hir:: ExprKind :: Block ( block, None ) , block. span )
262
+ this. lower_target_expr ( & block)
264
263
} else {
265
264
let pat_hir_id = this. lower_node_id ( pat_node_id) ;
266
265
this. generate_arg ( pat_hir_id, span)
@@ -273,26 +272,81 @@ impl<'hir> LoweringContext<'_, 'hir> {
273
272
} )
274
273
}
275
274
276
- // Generates fully qualified call for the resulting body.
275
+ // FIXME(fn_delegation): Alternatives for target expression lowering:
276
+ // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
277
+ fn lower_target_expr ( & mut self , block : & Block ) -> hir:: Expr < ' hir > {
278
+ if block. stmts . len ( ) == 1
279
+ && let StmtKind :: Expr ( expr) = & block. stmts [ 0 ] . kind
280
+ {
281
+ return self . lower_expr_mut ( expr) ;
282
+ }
283
+
284
+ let block = self . lower_block ( block, false ) ;
285
+ self . mk_expr ( hir:: ExprKind :: Block ( block, None ) , block. span )
286
+ }
287
+
288
+ // Generates expression for the resulting body. If possible, `MethodCall` is used
289
+ // to allow autoref/autoderef for target expression. For example in:
290
+ //
291
+ // trait Trait : Sized {
292
+ // fn by_value(self) -> i32 { 1 }
293
+ // fn by_mut_ref(&mut self) -> i32 { 2 }
294
+ // fn by_ref(&self) -> i32 { 3 }
295
+ // }
296
+ //
297
+ // struct NewType(SomeType);
298
+ // impl Trait for NewType {
299
+ // reuse Trait::* { self.0 }
300
+ // }
301
+ //
302
+ // `self.0` will automatically coerce.
277
303
fn finalize_body_lowering (
278
304
& mut self ,
279
305
delegation : & Delegation ,
280
306
args : Vec < hir:: Expr < ' hir > > ,
281
307
span : Span ,
282
308
) -> 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
309
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) ) ;
295
310
311
+ let has_generic_args =
312
+ delegation. path . segments . iter ( ) . rev ( ) . skip ( 1 ) . any ( |segment| segment. args . is_some ( ) ) ;
313
+
314
+ let call = if self
315
+ . get_resolution_id ( delegation. id , span)
316
+ . and_then ( |def_id| Ok ( self . has_self ( def_id, span) ) )
317
+ . unwrap_or_default ( )
318
+ && delegation. qself . is_none ( )
319
+ && !has_generic_args
320
+ {
321
+ let ast_segment = delegation. path . segments . last ( ) . unwrap ( ) ;
322
+ let segment = self . lower_path_segment (
323
+ delegation. path . span ,
324
+ ast_segment,
325
+ ParamMode :: Optional ,
326
+ ParenthesizedGenericArgs :: Err ,
327
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
328
+ None ,
329
+ ) ;
330
+ let segment = self . arena . alloc ( segment) ;
331
+
332
+ self . arena . alloc ( hir:: Expr {
333
+ hir_id : self . next_id ( ) ,
334
+ kind : hir:: ExprKind :: MethodCall ( segment, & args[ 0 ] , & args[ 1 ..] , span) ,
335
+ span,
336
+ } )
337
+ } else {
338
+ let path = self . lower_qpath (
339
+ delegation. id ,
340
+ & delegation. qself ,
341
+ & delegation. path ,
342
+ ParamMode :: Optional ,
343
+ ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
344
+ None ,
345
+ ) ;
346
+
347
+ let callee_path = self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Path ( path) , span) ) ;
348
+ self . arena . alloc ( self . mk_expr ( hir:: ExprKind :: Call ( callee_path, args) , span) )
349
+ } ;
296
350
let block = self . arena . alloc ( hir:: Block {
297
351
stmts : & [ ] ,
298
352
expr : Some ( call) ,
0 commit comments