3838
3939use crate :: { ImplTraitPosition , ResolverAstLoweringExt } ;
4040
41- use super :: { ImplTraitContext , LoweringContext , ParamMode } ;
41+ use super :: { ImplTraitContext , LoweringContext , ParamMode , ParenthesizedGenericArgs } ;
4242
4343use ast:: visit:: Visitor ;
4444use hir:: def:: { DefKind , PartialRes , Res } ;
@@ -259,8 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
259259 self_param_id : pat_node_id,
260260 } ;
261261 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)
264263 } else {
265264 let pat_hir_id = this. lower_node_id ( pat_node_id) ;
266265 this. generate_arg ( pat_hir_id, span)
@@ -273,26 +272,81 @@ impl<'hir> LoweringContext<'_, 'hir> {
273272 } )
274273 }
275274
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.
277303 fn finalize_body_lowering (
278304 & mut self ,
279305 delegation : & Delegation ,
280306 args : Vec < hir:: Expr < ' hir > > ,
281307 span : Span ,
282308 ) -> 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-
292309 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) ) ;
295310
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+ } ;
296350 let block = self . arena . alloc ( hir:: Block {
297351 stmts : & [ ] ,
298352 expr : Some ( call) ,
0 commit comments