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 } ;
@@ -66,17 +66,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
6666 let Ok ( sig_id) = sig_id else {
6767 return false ;
6868 } ;
69- if let Some ( local_sig_id) = sig_id. as_local ( ) {
70- // The value may be missing due to recursive delegation.
71- // Error will be emmited later during HIR ty lowering.
72- self . resolver . delegation_fn_sigs . get ( & local_sig_id) . map_or ( false , |sig| sig. has_self )
73- } else {
74- match self . tcx . def_kind ( sig_id) {
75- DefKind :: Fn => false ,
76- DefKind :: AssocFn => self . tcx . associated_item ( sig_id) . fn_has_self_parameter ,
77- _ => span_bug ! ( span, "unexpected DefKind for delegation item" ) ,
78- }
79- }
69+ self . has_self ( sig_id, span)
8070 }
8171
8272 pub ( crate ) fn lower_delegation (
@@ -107,12 +97,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
10797 span : Span ,
10898 ) -> Result < DefId , ErrorGuaranteed > {
10999 let sig_id = if self . is_in_trait_impl { item_id } else { path_id } ;
110- let sig_id =
111- self . resolver . get_partial_res ( sig_id) . and_then ( |r| r. expect_full_res ( ) . opt_def_id ( ) ) ;
112- sig_id. ok_or_else ( || {
113- self . tcx
114- . dcx ( )
115- . 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+ )
116123 } )
117124 }
118125
@@ -122,7 +129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
122129 predicates : & [ ] ,
123130 has_where_clause_predicates : false ,
124131 where_clause_span : span,
125- span : span ,
132+ span,
126133 } )
127134 }
128135
@@ -222,12 +229,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
222229 } ) ) ;
223230
224231 let path = self . arena . alloc ( hir:: Path { span, res : Res :: Local ( param_id) , segments } ) ;
225-
226- hir:: Expr {
227- hir_id : self . next_id ( ) ,
228- kind : hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) ,
229- span,
230- }
232+ self . mk_expr ( hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) , span)
231233 }
232234
233235 fn lower_delegation_body (
@@ -236,25 +238,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
236238 param_count : usize ,
237239 span : Span ,
238240 ) -> BodyId {
239- let path = self . lower_qpath (
240- delegation. id ,
241- & delegation. qself ,
242- & delegation. path ,
243- ParamMode :: Optional ,
244- ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
245- None ,
246- ) ;
247241 let block = delegation. body . as_deref ( ) ;
248242
249243 self . lower_body ( |this| {
250- let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
251- 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 ;
252247
253248 for idx in 0 ..param_count {
254249 let ( param, pat_node_id) = this. generate_param ( span) ;
255250 parameters. push ( param) ;
256251
257- let arg = if let Some ( block) = block
252+ if let Some ( block) = block
258253 && idx == 0
259254 {
260255 let mut self_resolver = SelfResolver {
@@ -263,56 +258,103 @@ impl<'hir> LoweringContext<'_, 'hir> {
263258 self_param_id : pat_node_id,
264259 } ;
265260 self_resolver. visit_block ( block) ;
266- let block = this. lower_block ( block, false ) ;
267- hir:: Expr {
268- hir_id : this. next_id ( ) ,
269- kind : hir:: ExprKind :: Block ( block, None ) ,
270- span : block. span ,
271- }
261+ target_expr = Some ( this. lower_block_noalloc ( block, false ) ) ;
272262 } else {
273263 let pat_hir_id = this. lower_node_id ( pat_node_id) ;
274- this. generate_arg ( pat_hir_id, span)
264+ let arg = this. generate_arg ( pat_hir_id, span) ;
265+ args. push ( arg) ;
275266 } ;
276- args. push ( arg) ;
277267 }
278268
279- let args = self . arena . alloc_from_iter ( args) ;
280- let final_expr = this. generate_call ( path, args) ;
269+ let final_expr = this. finalize_body_lowering ( delegation, target_expr, args, span) ;
281270 ( this. arena . alloc_from_iter ( parameters) , final_expr)
282271 } )
283272 }
284273
285- 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 (
286278 & mut self ,
287- path : hir:: QPath < ' hir > ,
288- 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 ,
289283 ) -> hir:: Expr < ' hir > {
290- let callee = self . arena . alloc ( hir:: Expr {
291- hir_id : self . next_id ( ) ,
292- kind : hir:: ExprKind :: Path ( path) ,
293- span : path. span ( ) ,
294- } ) ;
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+ } ;
295312
296- let expr = self . arena . alloc ( hir:: Expr {
297- hir_id : self . next_id ( ) ,
298- kind : hir:: ExprKind :: Call ( callee, args) ,
299- span : path. span ( ) ,
300- } ) ;
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+ }
301341
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+ } ;
302349 let block = self . arena . alloc ( hir:: Block {
303- stmts : & [ ] ,
304- expr : Some ( expr ) ,
305- hir_id : self . next_id ( ) ,
350+ stmts,
351+ expr : Some ( call ) ,
352+ hir_id : block_id ,
306353 rules : hir:: BlockCheckMode :: DefaultBlock ,
307- span : path . span ( ) ,
354+ span,
308355 targeted_by_break : false ,
309356 } ) ;
310-
311- hir:: Expr {
312- hir_id : self . next_id ( ) ,
313- kind : hir:: ExprKind :: Block ( block, None ) ,
314- span : path. span ( ) ,
315- }
357+ self . mk_expr ( hir:: ExprKind :: Block ( block, None ) , span)
316358 }
317359
318360 fn generate_delegation_error (
@@ -333,11 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
333375 let header = self . generate_header_error ( ) ;
334376 let sig = hir:: FnSig { decl, header, span } ;
335377
336- let body_id = self . lower_body ( |this| {
337- let expr =
338- hir:: Expr { hir_id : this. next_id ( ) , kind : hir:: ExprKind :: Err ( err) , span : span } ;
339- ( & [ ] , expr)
340- } ) ;
378+ let body_id = self . lower_body ( |this| ( & [ ] , this. mk_expr ( hir:: ExprKind :: Err ( err) , span) ) ) ;
341379 DelegationResults { generics, body_id, sig }
342380 }
343381
@@ -349,6 +387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
349387 abi : abi:: Abi :: Rust ,
350388 }
351389 }
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+ }
352395}
353396
354397struct SelfResolver < ' a > {
0 commit comments