Skip to content

Commit 477664c

Browse files
committed
Auto merge of #150024 - aerooneqq:recursive-delegation-2, r=petrochenkov
Support recursive delegation This PR adds support for recursive delegations and is a part of the delegation feature #118212. r? `@petrochenkov`
2 parents ed0006a + ae5e0d5 commit 477664c

File tree

17 files changed

+330
-69
lines changed

17 files changed

+330
-69
lines changed

compiler/rustc_ast_lowering/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ ast_lowering_coroutine_too_many_parameters =
5656
ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
5757
.label = default fields are only supported on structs
5858
59+
ast_lowering_delegation_cycle_in_signature_resolution = encountered a cycle during delegation signature resolution
60+
ast_lowering_delegation_unresolved_callee = failed to resolve delegation callee
5961
ast_lowering_does_not_support_modifiers =
6062
the `{$class_name}` register class does not support template modifiers
6163

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use hir::{BodyId, HirId};
4444
use rustc_abi::ExternAbi;
4545
use rustc_ast::*;
4646
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
47+
use rustc_data_structures::fx::FxHashSet;
4748
use rustc_errors::ErrorGuaranteed;
4849
use rustc_hir::Target;
4950
use rustc_hir::attrs::{AttributeKind, InlineAttr};
@@ -55,6 +56,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
5556
use {rustc_ast as ast, rustc_hir as hir};
5657

5758
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
59+
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
5860
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
5961

6062
pub(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

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,17 @@ pub(crate) struct UnionWithDefault {
475475
#[primary_span]
476476
pub span: Span,
477477
}
478+
479+
#[derive(Diagnostic)]
480+
#[diag(ast_lowering_delegation_unresolved_callee)]
481+
pub(crate) struct UnresolvedDelegationCallee {
482+
#[primary_span]
483+
pub span: Span,
484+
}
485+
486+
#[derive(Diagnostic)]
487+
#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
488+
pub(crate) struct CycleInDelegationSignatureResolution {
489+
#[primary_span]
490+
pub span: Span,
491+
}

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
541541
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
542542
}
543543
ItemKind::Delegation(box delegation) => {
544-
let delegation_results = self.lower_delegation(delegation, id, false);
544+
let delegation_results = self.lower_delegation(delegation, id);
545545
hir::ItemKind::Fn {
546546
sig: delegation_results.sig,
547547
ident: delegation_results.ident,
@@ -1026,7 +1026,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10261026
(*ident, generics, kind, ty.is_some())
10271027
}
10281028
AssocItemKind::Delegation(box delegation) => {
1029-
let delegation_results = self.lower_delegation(delegation, i.id, false);
1029+
let delegation_results = self.lower_delegation(delegation, i.id);
10301030
let item_kind = hir::TraitItemKind::Fn(
10311031
delegation_results.sig,
10321032
hir::TraitFn::Provided(delegation_results.body_id),
@@ -1196,7 +1196,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
11961196
)
11971197
}
11981198
AssocItemKind::Delegation(box delegation) => {
1199-
let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl);
1199+
let delegation_results = self.lower_delegation(delegation, i.id);
12001200
(
12011201
delegation.ident,
12021202
(

compiler/rustc_hir_analysis/src/delegation.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,6 @@ fn check_constraints<'tcx>(
401401
}));
402402
};
403403

404-
if let Some(local_sig_id) = sig_id.as_local()
405-
&& tcx.hir_opt_delegation_sig_id(local_sig_id).is_some()
406-
{
407-
emit("recursive delegation is not supported yet");
408-
}
409-
410404
if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic {
411405
// See issue #127443 for explanation.
412406
emit("delegation to C-variadic functions is not allowed");

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ pub struct ResolverAstLowering {
221221

222222
/// Information about functions signatures for delegation items expansion
223223
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
224+
// NodeIds (either delegation.id or item_id in case of a trait impl) for signature resolution,
225+
// for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914
226+
pub delegation_sig_resolution_nodes: LocalDefIdMap<ast::NodeId>,
224227
}
225228

226229
bitflags::bitflags! {

compiler/rustc_resolve/src/late.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2928,7 +2928,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
29282928
item.id,
29292929
LifetimeBinderKind::Function,
29302930
span,
2931-
|this| this.resolve_delegation(delegation),
2931+
|this| this.resolve_delegation(delegation, item.id, false),
29322932
);
29332933
}
29342934

@@ -3257,7 +3257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
32573257
item.id,
32583258
LifetimeBinderKind::Function,
32593259
delegation.path.segments.last().unwrap().ident.span,
3260-
|this| this.resolve_delegation(delegation),
3260+
|this| this.resolve_delegation(delegation, item.id, false),
32613261
);
32623262
}
32633263
AssocItemKind::Type(box TyAlias { generics, .. }) => self
@@ -3550,7 +3550,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
35503550
|i, s, c| MethodNotMemberOfTrait(i, s, c),
35513551
);
35523552

3553-
this.resolve_delegation(delegation)
3553+
this.resolve_delegation(delegation, item.id, trait_id.is_some());
35543554
},
35553555
);
35563556
}
@@ -3699,17 +3699,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
36993699
})
37003700
}
37013701

3702-
fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
3702+
fn resolve_delegation(
3703+
&mut self,
3704+
delegation: &'ast Delegation,
3705+
item_id: NodeId,
3706+
is_in_trait_impl: bool,
3707+
) {
37033708
self.smart_resolve_path(
37043709
delegation.id,
37053710
&delegation.qself,
37063711
&delegation.path,
37073712
PathSource::Delegation,
37083713
);
3714+
37093715
if let Some(qself) = &delegation.qself {
37103716
self.visit_ty(&qself.ty);
37113717
}
3718+
37123719
self.visit_path(&delegation.path);
3720+
3721+
self.r.delegation_sig_resolution_nodes.insert(
3722+
self.r.local_def_id(item_id),
3723+
if is_in_trait_impl { item_id } else { delegation.id },
3724+
);
3725+
37133726
let Some(body) = &delegation.body else { return };
37143727
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
37153728
let span = delegation.path.segments.last().unwrap().ident.span;
@@ -4294,7 +4307,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
42944307
);
42954308
}
42964309

4297-
#[instrument(level = "debug", skip(self))]
42984310
fn smart_resolve_path_fragment(
42994311
&mut self,
43004312
qself: &Option<Box<QSelf>>,

compiler/rustc_resolve/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,7 @@ pub struct Resolver<'ra, 'tcx> {
12751275
/// Amount of lifetime parameters for each item in the crate.
12761276
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
12771277
delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
1278+
delegation_sig_resolution_nodes: LocalDefIdMap<NodeId>,
12781279

12791280
main_def: Option<MainDefinition> = None,
12801281
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
@@ -1693,6 +1694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
16931694
current_crate_outer_attr_insert_span,
16941695
mods_with_parse_errors: Default::default(),
16951696
impl_trait_names: Default::default(),
1697+
delegation_sig_resolution_nodes: Default::default(),
16961698
..
16971699
};
16981700

@@ -1821,6 +1823,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18211823
lifetime_elision_allowed: self.lifetime_elision_allowed,
18221824
lint_buffer: Steal::new(self.lint_buffer),
18231825
delegation_fn_sigs: self.delegation_fn_sigs,
1826+
delegation_sig_resolution_nodes: self.delegation_sig_resolution_nodes,
18241827
};
18251828
ResolverOutputs { global_ctxt, ast_lowering }
18261829
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(fn_delegation)]
2+
#![allow(incomplete_features)]
3+
4+
fn foo() {}
5+
6+
reuse foo as bar;
7+
pub reuse bar as goo;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#![feature(fn_delegation)]
22
#![allow(incomplete_features)]
33

4-
// FIXME(fn_delegation): `recursive delegation` error should be emitted here
54
trait Trait {
65
reuse Trait::foo { &self.0 }
6+
//~^ ERROR failed to resolve delegation callee
77
}
88

99
reuse foo;
10-
//~^ ERROR cycle detected when computing generics of `foo`
10+
//~^ ERROR failed to resolve delegation callee
1111

1212
fn main() {}

0 commit comments

Comments
 (0)