@@ -44,6 +44,7 @@ use hir::{BodyId, HirId};
4444use rustc_abi:: ExternAbi ;
4545use rustc_ast:: * ;
4646use rustc_attr_parsing:: { AttributeParser , ShouldEmit } ;
47+ use rustc_data_structures:: fx:: FxHashSet ;
4748use rustc_errors:: ErrorGuaranteed ;
4849use rustc_hir:: Target ;
4950use rustc_hir:: attrs:: { AttributeKind , InlineAttr } ;
@@ -55,6 +56,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
5556use { rustc_ast as ast, rustc_hir as hir} ;
5657
5758use super :: { GenericArgsMode , ImplTraitContext , LoweringContext , ParamMode } ;
59+ use crate :: errors:: { CycleInDelegationSignatureResolution , UnresolvedDelegationCallee } ;
5860use crate :: { AllowReturnTypeNotation , ImplTraitPosition , ResolverAstLoweringExt } ;
5961
6062pub ( crate ) struct DelegationResults < ' hir > {
@@ -119,10 +121,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
119121 & mut self ,
120122 delegation : & Delegation ,
121123 item_id : NodeId ,
122- is_in_trait_impl : bool ,
123124 ) -> DelegationResults < ' hir > {
124125 let span = self . lower_span ( delegation. path . segments . last ( ) . unwrap ( ) . ident . span ) ;
125- let sig_id = self . get_delegation_sig_id ( item_id, delegation. id , span, is_in_trait_impl) ;
126+
127+ let sig_id = self . get_delegation_sig_id (
128+ self . resolver . delegation_sig_resolution_nodes [ & self . local_def_id ( item_id) ] ,
129+ span,
130+ ) ;
131+
126132 match sig_id {
127133 Ok ( sig_id) => {
128134 self . add_attributes_if_needed ( span, sig_id) ;
@@ -238,24 +244,48 @@ impl<'hir> LoweringContext<'_, 'hir> {
238244
239245 fn get_delegation_sig_id (
240246 & self ,
241- item_id : NodeId ,
242- path_id : NodeId ,
247+ mut node_id : NodeId ,
243248 span : Span ,
244- is_in_trait_impl : bool ,
245249 ) -> Result < DefId , ErrorGuaranteed > {
246- let sig_id = if is_in_trait_impl { item_id } else { path_id } ;
247- self . get_resolution_id ( sig_id, span)
250+ let mut visited: FxHashSet < NodeId > = Default :: default ( ) ;
251+
252+ loop {
253+ visited. insert ( node_id) ;
254+
255+ let Some ( def_id) = self . get_resolution_id ( node_id) else {
256+ return Err ( self . tcx . dcx ( ) . span_delayed_bug (
257+ span,
258+ format ! (
259+ "LoweringContext: couldn't resolve node {:?} in delegation item" ,
260+ node_id
261+ ) ,
262+ ) ) ;
263+ } ;
264+
265+ // If def_id is in local crate and it corresponds to another delegation
266+ // it means that we refer to another delegation as a callee, so in order to obtain
267+ // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
268+ if let Some ( local_id) = def_id. as_local ( )
269+ && let Some ( next_node_id) =
270+ self . resolver . delegation_sig_resolution_nodes . get ( & local_id)
271+ {
272+ node_id = * next_node_id;
273+ if visited. contains ( & node_id) {
274+ // We encountered a cycle in the resolution, or delegation callee refers to non-existent
275+ // entity, in this case emit an error.
276+ return Err ( match visited. len ( ) {
277+ 1 => self . dcx ( ) . emit_err ( UnresolvedDelegationCallee { span } ) ,
278+ _ => self . dcx ( ) . emit_err ( CycleInDelegationSignatureResolution { span } ) ,
279+ } ) ;
280+ }
281+ } else {
282+ return Ok ( def_id) ;
283+ }
284+ }
248285 }
249286
250- fn get_resolution_id ( & self , node_id : NodeId , span : Span ) -> Result < DefId , ErrorGuaranteed > {
251- let def_id =
252- self . resolver . get_partial_res ( node_id) . and_then ( |r| r. expect_full_res ( ) . opt_def_id ( ) ) ;
253- def_id. ok_or_else ( || {
254- self . tcx . dcx ( ) . span_delayed_bug (
255- span,
256- format ! ( "LoweringContext: couldn't resolve node {:?} in delegation item" , node_id) ,
257- )
258- } )
287+ fn get_resolution_id ( & self , node_id : NodeId ) -> Option < DefId > {
288+ self . resolver . get_partial_res ( node_id) . and_then ( |r| r. expect_full_res ( ) . opt_def_id ( ) )
259289 }
260290
261291 fn lower_delegation_generics ( & mut self , span : Span ) -> & ' hir hir:: Generics < ' hir > {
@@ -271,8 +301,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
271301 // Function parameter count, including C variadic `...` if present.
272302 fn param_count ( & self , sig_id : DefId ) -> ( usize , bool /*c_variadic*/ ) {
273303 if let Some ( local_sig_id) = sig_id. as_local ( ) {
274- // Map may be filled incorrectly due to recursive delegation.
275- // Error will be emitted later during HIR ty lowering.
276304 match self . resolver . delegation_fn_sigs . get ( & local_sig_id) {
277305 Some ( sig) => ( sig. param_count , sig. c_variadic ) ,
278306 None => ( 0 , false ) ,
@@ -489,8 +517,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
489517 delegation. path . segments . iter ( ) . rev ( ) . skip ( 1 ) . any ( |segment| segment. args . is_some ( ) ) ;
490518
491519 let call = if self
492- . get_resolution_id ( delegation. id , span )
493- . and_then ( |def_id| Ok ( self . is_method ( def_id, span) ) )
520+ . get_resolution_id ( delegation. id )
521+ . map ( |def_id| self . is_method ( def_id, span) )
494522 . unwrap_or_default ( )
495523 && delegation. qself . is_none ( )
496524 && !has_generic_args
0 commit comments