Skip to content

Commit 7bdb059

Browse files
committed
Address review comments
1 parent 08342bf commit 7bdb059

37 files changed

Lines changed: 387 additions & 156 deletions

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3922,7 +3922,7 @@ pub struct Delegation {
39223922
}
39233923

39243924
impl Delegation {
3925-
pub fn span(&self) -> Span {
3925+
pub fn last_segment_span(&self) -> Span {
39263926
self.path.segments.last().unwrap().ident.span
39273927
}
39283928
}

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,21 @@ use hir::{BodyId, HirId};
4444
use rustc_abi::ExternAbi;
4545
use rustc_ast as ast;
4646
use rustc_ast::*;
47+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
4748
use rustc_hir::attrs::{AttributeKind, InlineAttr};
48-
use rustc_hir::def_id::DefId;
49+
use rustc_hir::def_id::{DefId, LocalDefId};
4950
use rustc_hir::{self as hir, FnDeclFlags};
5051
use rustc_middle::span_bug;
51-
use rustc_middle::ty::Asyncness;
52+
use rustc_middle::ty::{Asyncness, TyCtxt};
5253
use rustc_span::symbol::kw;
53-
use rustc_span::{Ident, Span, Symbol};
54+
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
55+
use smallvec::SmallVec;
5456

5557
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
58+
use crate::errors::CycleInDelegationSignatureResolution;
5659
use crate::{
5760
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
61+
ResolverAstLoweringExt, index_crate,
5862
};
5963

6064
mod generics;
@@ -100,6 +104,66 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
100104
},
101105
];
102106

107+
pub fn delegations_resolutions(
108+
tcx: TyCtxt<'_>,
109+
_: (),
110+
) -> FxIndexMap<LocalDefId, Result<DefId, ErrorGuaranteed>> {
111+
let krate = tcx.hir_crate(());
112+
113+
let (resolver, ast_crate) = &*krate.delayed_resolver.borrow();
114+
115+
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
116+
// as it is too bad to reindex whole crate on each delegation lowering.
117+
let ast_index = index_crate(resolver, ast_crate);
118+
119+
let mut result = FxIndexMap::<LocalDefId, Result<DefId, ErrorGuaranteed>>::default();
120+
121+
for &def_id in &krate.delayed_ids {
122+
let delegation = ast_index[def_id].delegation().expect("processing delegations");
123+
let span = delegation.last_segment_span();
124+
125+
if let Some(res_result) = resolver.delegation_info(def_id) {
126+
let res = res_result.map(|info| check_for_cycles(tcx, info.resolution_id, span));
127+
result.insert(def_id, res.flatten());
128+
}
129+
}
130+
131+
result
132+
}
133+
134+
fn check_for_cycles(
135+
tcx: TyCtxt<'_>,
136+
mut def_id: DefId,
137+
span: Span,
138+
) -> Result<DefId, ErrorGuaranteed> {
139+
let mut visited: FxHashSet<DefId> = Default::default();
140+
let mut path: SmallVec<[DefId; 1]> = Default::default();
141+
142+
let (resolver, _) = &*tcx.hir_crate(()).delayed_resolver.borrow();
143+
144+
loop {
145+
visited.insert(def_id);
146+
147+
path.push(def_id);
148+
149+
// If def_id is in local crate and it corresponds to another delegation
150+
// it means that we refer to another delegation as a callee, so in order to obtain
151+
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
152+
if let Some(local_id) = def_id.as_local()
153+
&& let Some(Ok(delegation_info)) = resolver.delegation_info(local_id)
154+
{
155+
def_id = delegation_info.resolution_id;
156+
if visited.contains(&def_id) {
157+
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
158+
// entity, in this case emit an error.
159+
return Err(tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }));
160+
}
161+
} else {
162+
return Ok(path[0]);
163+
}
164+
}
165+
}
166+
103167
impl<'hir> LoweringContext<'_, 'hir> {
104168
fn is_method(&self, def_id: DefId, span: Span) -> bool {
105169
match self.tcx.def_kind(def_id) {
@@ -114,13 +178,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
114178
delegation: &Delegation,
115179
item_id: NodeId,
116180
) -> DelegationResults<'hir> {
117-
let span = self.lower_span(delegation.span());
181+
let span = self.lower_span(delegation.last_segment_span());
118182

119-
let sig_id =
120-
self.tcx.delegations_resolutions(()).get(&self.owner.def_id).copied().flatten();
183+
let sig_id = self.tcx.delegations_resolutions(()).get(&self.owner.def_id).copied();
121184

122185
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
123-
let Some(sig_id) = sig_id else {
186+
let Some(Ok(sig_id)) = sig_id else {
124187
self.dcx().span_delayed_bug(
125188
span,
126189
format!("LoweringContext: the delegation {:?} is unresolved", item_id),

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -522,13 +522,6 @@ pub(crate) struct UnionWithDefault {
522522
pub span: Span,
523523
}
524524

525-
#[derive(Diagnostic)]
526-
#[diag("failed to resolve delegation callee")]
527-
pub(crate) struct UnresolvedDelegationCallee {
528-
#[primary_span]
529-
pub span: Span,
530-
}
531-
532525
#[derive(Diagnostic)]
533526
#[diag("encountered a cycle during delegation signature resolution")]
534527
pub(crate) struct CycleInDelegationSignatureResolution {

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 18 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ use rustc_ast::visit::Visitor;
4343
use rustc_ast::{self as ast, *};
4444
use rustc_attr_parsing::{AttributeParser, OmitDoc, Recovery, ShouldEmit};
4545
use rustc_data_structures::fingerprint::Fingerprint;
46-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
46+
use rustc_data_structures::fx::FxIndexSet;
4747
use rustc_data_structures::sorted_map::SortedMap;
4848
use rustc_data_structures::stable_hash::{StableHash, StableHasher};
4949
use rustc_data_structures::steal::Steal;
5050
use rustc_data_structures::tagged_ptr::TaggedRef;
5151
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
5252
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
53-
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
53+
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
5454
use rustc_hir::definitions::PerParentDisambiguatorState;
5555
use rustc_hir::lints::DelayedLint;
5656
use rustc_hir::{
@@ -64,15 +64,12 @@ use rustc_middle::span_bug;
6464
use rustc_middle::ty::{DelegationInfo, PerOwnerResolverData, ResolverAstLowering, TyCtxt};
6565
use rustc_session::errors::add_feature_diagnostics;
6666
use rustc_span::symbol::{Ident, Symbol, kw, sym};
67-
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
67+
use rustc_span::{DUMMY_SP, DesugaringKind, ErrorGuaranteed, Span};
6868
use smallvec::SmallVec;
6969
use thin_vec::ThinVec;
7070
use tracing::{debug, instrument, trace};
7171

72-
use crate::errors::{
73-
AssocTyParentheses, AssocTyParenthesesSub, CycleInDelegationSignatureResolution,
74-
MisplacedImplTrait, UnresolvedDelegationCallee,
75-
};
72+
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
7673
use crate::item::Owners;
7774

7875
macro_rules! arena_vec {
@@ -84,7 +81,7 @@ macro_rules! arena_vec {
8481
mod asm;
8582
mod block;
8683
mod contract;
87-
mod delegation;
84+
pub mod delegation;
8885
mod errors;
8986
mod expr;
9087
mod format;
@@ -307,8 +304,8 @@ impl<'tcx> ResolverAstLowering<'tcx> {
307304
self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..])
308305
}
309306

310-
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
311-
self.delegation_infos.get(&id)
307+
fn delegation_info(&self, id: LocalDefId) -> Option<Result<DelegationInfo, ErrorGuaranteed>> {
308+
self.delegation_infos.get(&id).copied()
312309
}
313310

314311
fn owner_def_id(&self, id: NodeId) -> LocalDefId {
@@ -441,6 +438,16 @@ enum AstOwner<'a> {
441438
ForeignItem(&'a ast::ForeignItem),
442439
}
443440

441+
impl AstOwner<'_> {
442+
fn delegation(&self) -> Option<&ast::Delegation> {
443+
match self {
444+
AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. })
445+
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(d), .. }, _) => Some(d),
446+
_ => None,
447+
}
448+
}
449+
}
450+
444451
#[derive(Copy, Clone, Debug)]
445452
enum TryBlockScope {
446453
/// There isn't a `try` block, so a `?` will use `return`.
@@ -544,7 +551,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
544551
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
545552

546553
for def_id in ast_index.indices() {
547-
if opt_delegation(&ast_index[def_id]).is_some() {
554+
if ast_index[def_id].delegation().is_some() {
548555
delayed_ids.insert(def_id);
549556
} else {
550557
lowerer.lower_node(def_id);
@@ -559,16 +566,6 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
559566
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
560567
}
561568

562-
fn opt_delegation<'a>(ast_owner: &'a AstOwner<'a>) -> Option<&'a Delegation> {
563-
match ast_owner {
564-
AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. })
565-
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(d), .. }, _) => {
566-
Some(d.as_ref())
567-
}
568-
_ => None,
569-
}
570-
}
571-
572569
/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way.
573570
pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
574571
let krate = tcx.hir_crate(());
@@ -594,65 +591,6 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
594591
}
595592
}
596593

597-
pub fn delegations_resolutions(tcx: TyCtxt<'_>, _: ()) -> FxIndexMap<LocalDefId, Option<DefId>> {
598-
let krate = tcx.hir_crate(());
599-
600-
let (resolver, ast_crate) = &*krate.delayed_resolver.borrow();
601-
602-
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
603-
// as it is too bad to reindex whole crate on each delegation lowering.
604-
let ast_index = index_crate(resolver, ast_crate);
605-
606-
let mut result = FxIndexMap::<LocalDefId, Option<DefId>>::default();
607-
608-
for &def_id in &krate.delayed_ids {
609-
let delegation = opt_delegation(&ast_index[def_id]).expect("processing delegations");
610-
let span = delegation.span();
611-
612-
let res_id = resolver
613-
.delegation_info(def_id)
614-
.and_then(|info| resolve_delegation(tcx, info.resolution_id, span));
615-
616-
result.insert(def_id, res_id);
617-
}
618-
619-
result
620-
}
621-
622-
fn resolve_delegation(tcx: TyCtxt<'_>, mut def_id: DefId, span: Span) -> Option<DefId> {
623-
let mut visited: FxHashSet<DefId> = Default::default();
624-
let mut path: SmallVec<[DefId; 1]> = Default::default();
625-
626-
let (resolver, _) = &*tcx.hir_crate(()).delayed_resolver.borrow();
627-
628-
loop {
629-
visited.insert(def_id);
630-
631-
path.push(def_id);
632-
633-
// If def_id is in local crate and it corresponds to another delegation
634-
// it means that we refer to another delegation as a callee, so in order to obtain
635-
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
636-
if let Some(local_id) = def_id.as_local()
637-
&& let Some(delegation_info) = resolver.delegation_info(local_id)
638-
{
639-
def_id = delegation_info.resolution_id;
640-
if visited.contains(&def_id) {
641-
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
642-
// entity, in this case emit an error.
643-
match visited.len() {
644-
1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }),
645-
_ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
646-
};
647-
648-
return None;
649-
}
650-
} else {
651-
return Some(path[0]);
652-
}
653-
}
654-
}
655-
656594
#[derive(Copy, Clone, PartialEq, Debug)]
657595
enum ParamMode {
658596
/// Any path in a type context.

compiler/rustc_interface/src/passes.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,8 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
879879
providers.queries.analysis = analysis;
880880
providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir;
881881
providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner;
882-
providers.queries.delegations_resolutions = rustc_ast_lowering::delegations_resolutions;
882+
providers.queries.delegations_resolutions =
883+
rustc_ast_lowering::delegation::delegations_resolutions;
883884
// `hir_delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
884885
// as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId.
885886
providers.queries.hir_delayed_owner = |_, _| MaybeOwner::Phantom;

compiler/rustc_middle/src/hir/map.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,8 +1277,6 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
12771277
}
12781278

12791279
fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
1280-
tcx.ensure_done().delegations_resolutions(());
1281-
12821280
let krate = tcx.hir_crate(());
12831281
for &id in &krate.delayed_ids {
12841282
tcx.ensure_done().lower_delayed_owner(id);

compiler/rustc_middle/src/queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2065,7 +2065,7 @@ rustc_queries! {
20652065
desc { "inheriting delegation signature" }
20662066
}
20672067

2068-
query delegations_resolutions(_: ()) -> &'tcx FxIndexMap<LocalDefId, Option<DefId>> {
2068+
query delegations_resolutions(_: ()) -> &'tcx FxIndexMap<LocalDefId, Result<DefId, ErrorGuaranteed>> {
20692069
arena_cache
20702070
eval_always
20712071
desc { "getting delegations resolutions" }

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,12 @@ pub struct ResolverAstLowering<'tcx> {
257257
pub lint_buffer: Steal<LintBuffer>,
258258

259259
// Information about delegations which is used when handling recursive delegations
260-
pub delegation_infos: LocalDefIdMap<DelegationInfo>,
260+
pub delegation_infos: LocalDefIdMap<Result<DelegationInfo, ErrorGuaranteed>>,
261261

262262
pub disambiguators: LocalDefIdMap<Steal<PerParentDisambiguatorState>>,
263263
}
264264

265-
#[derive(Debug)]
265+
#[derive(Debug, Clone, Copy)]
266266
pub struct DelegationInfo {
267267
// `DefId` (either the resolution at delegation.id or item_id in case of a trait impl) for signature resolution,
268268
// for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914

compiler/rustc_resolve/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,3 +1776,10 @@ pub(crate) enum UnusedImportsSugg {
17761776
num_to_remove: usize,
17771777
},
17781778
}
1779+
1780+
#[derive(Diagnostic)]
1781+
#[diag("failed to resolve delegation callee")]
1782+
pub(crate) struct UnresolvedDelegationCallee {
1783+
#[primary_span]
1784+
pub span: Span,
1785+
}

compiler/rustc_resolve/src/late.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use smallvec::{SmallVec, smallvec};
3939
use thin_vec::ThinVec;
4040
use tracing::{debug, instrument, trace};
4141

42+
use crate::errors::UnresolvedDelegationCallee;
4243
use crate::{
4344
BindingError, BindingKey, Decl, DelegationFnSig, Finalize, IdentKey, LateDecl, LocalModule,
4445
Module, ModuleOrUniformRoot, ParentScope, PathResult, Res, ResolutionError, Resolver, Segment,
@@ -3905,19 +3906,27 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
39053906
.partial_res_map
39063907
.get(&resolution_id)
39073908
.and_then(|r| r.expect_full_res().opt_def_id());
3908-
if let Some(resolution_id) = def_id {
3909-
self.r
3910-
.delegation_infos
3911-
.insert(self.r.current_owner.def_id, DelegationInfo { resolution_id });
3909+
3910+
let resolution = if let Some(resolution_id) = def_id
3911+
// If there is a single unresolved `reuse foo` in a mod it resolves to itself,
3912+
// in this case emit `UnresolvedDelegationCallee` error instead of cycle error.
3913+
&& resolution_id != self.r.current_owner.def_id.to_def_id()
3914+
{
3915+
Ok(DelegationInfo { resolution_id })
39123916
} else {
39133917
self.r.tcx.dcx().span_delayed_bug(
39143918
delegation.path.span,
39153919
format!(
39163920
"LoweringContext: couldn't resolve node {resolution_id:?} in delegation item",
39173921
),
39183922
);
3923+
3924+
let err = UnresolvedDelegationCallee { span: delegation.last_segment_span() };
3925+
Err(self.r.tcx.dcx().emit_err(err))
39193926
};
39203927

3928+
self.r.delegation_infos.insert(self.r.current_owner.def_id, resolution);
3929+
39213930
let Some(body) = &delegation.body else { return };
39223931
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
39233932
let ident = Ident::new(kw::SelfLower, body.span.normalize_to_macro_rules());

0 commit comments

Comments
 (0)