Skip to content

Commit 6e2eb6e

Browse files
committed
WIP on recursive delegation
1 parent a77bf4b commit 6e2eb6e

File tree

11 files changed

+80
-63
lines changed

11 files changed

+80
-63
lines changed

compiler/rustc_ast_lowering/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,5 @@ ast_lowering_yield = yield syntax is experimental
186186
ast_lowering_yield_in_closure =
187187
`yield` can only be used in `#[coroutine]` closures, or `gen` blocks
188188
.suggestion = use `#[coroutine]` to make this closure a coroutine
189+
190+
ast_lowering_unresolved_delegation_callee = failed to resolve delegation callee

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
5656
use {rustc_ast as ast, rustc_hir as hir};
5757

5858
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
59+
use crate::errors::UnresolvedDelegationCallee;
5960
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
6061

6162
pub(crate) struct DelegationResults<'hir> {
@@ -120,16 +121,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
120121
&mut self,
121122
delegation: &Delegation,
122123
item_id: NodeId,
123-
_is_in_trait_impl: bool,
124124
) -> DelegationResults<'hir> {
125125
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
126126

127-
let sig_id = self.get_resolution_id(
127+
let sig_id = self.resolve_callee_sig(
128128
self.resolver
129129
.delegation_resolution_info
130130
.get(&self.local_def_id(item_id))
131131
.unwrap()
132-
.resolution_id,
132+
.sig_resolution_id,
133133
span,
134134
);
135135

@@ -246,44 +246,73 @@ impl<'hir> LoweringContext<'_, 'hir> {
246246
}
247247
}
248248

249-
fn get_resolution_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
250-
let create_error = |node_id: NodeId| {
251-
self.tcx.dcx().span_delayed_bug(
252-
span,
253-
format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
254-
)
255-
};
256-
257-
let mut processed: FxHashSet<NodeId> = Default::default();
249+
fn resolve_callee_sig(
250+
&self,
251+
mut node_id: NodeId,
252+
span: Span,
253+
) -> Result<DefId, ErrorGuaranteed> {
254+
let mut visited: FxHashSet<NodeId> = Default::default();
258255

259256
loop {
260-
processed.insert(node_id);
257+
visited.insert(node_id);
261258

262-
let def_id = self
263-
.resolver
264-
.get_partial_res(node_id)
265-
.and_then(|r| r.expect_full_res().opt_def_id());
259+
let def_id = self.opt_get_partial_res_id(node_id);
266260

261+
// If def_id is in local crate and there is no signature in delegation_fn_sigs
262+
// it means that we refer to another delegation as a callee, so in order to obtain
263+
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
267264
if let Some(def_id) = def_id
268265
&& let Some(local_id) = def_id.as_local()
269266
&& !self.resolver.delegation_fn_sigs.contains_key(&local_id)
270267
{
271268
if let Some(info) = self.resolver.delegation_resolution_info.get(&local_id) {
272-
node_id = info.resolution_id;
273-
if processed.contains(&node_id) {
274-
return Err(create_error(node_id));
269+
node_id = info.sig_resolution_id;
270+
if visited.contains(&node_id) {
271+
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
272+
// entity, in this case emit an error.
273+
return Err(self.dcx().emit_err(UnresolvedDelegationCallee { span }));
275274
}
276275

277276
continue;
278277
} else {
279-
return Err(create_error(node_id));
278+
// The LocalDefId for some reason refers not to another delegation, in this case
279+
// we will emit a bug (not an error), as we have to catch such cases on the resolve stage,
280+
// during smart_resolve_path in resolve_delegation.
281+
return Err(self.tcx.dcx().span_delayed_bug(span, format!(
282+
"There is no information about delegation resolution node id for LocalDefId {:?}",
283+
local_id
284+
)));
280285
}
281286
}
282287

283-
return def_id.ok_or_else(|| create_error(node_id));
288+
// Def id is either None or is from non-local crate, fallback to the original routine.
289+
return self.def_id_or_guaranteed_err(def_id, node_id, span);
284290
}
285291
}
286292

293+
fn opt_get_partial_res_id(&self, node_id: NodeId) -> Option<DefId> {
294+
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
295+
}
296+
297+
fn def_id_or_guaranteed_err(
298+
&self,
299+
def_id: Option<DefId>,
300+
node_id: NodeId,
301+
span: Span,
302+
) -> Result<DefId, ErrorGuaranteed> {
303+
def_id.ok_or_else(|| {
304+
self.tcx.dcx().span_delayed_bug(
305+
span,
306+
format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
307+
)
308+
})
309+
}
310+
311+
fn get_resolution_id(&mut self, node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
312+
let def_id = self.opt_get_partial_res_id(node_id);
313+
self.def_id_or_guaranteed_err(def_id, node_id, span)
314+
}
315+
287316
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
288317
self.arena.alloc(hir::Generics {
289318
params: &[],

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,10 @@ pub(crate) struct UnionWithDefault {
475475
#[primary_span]
476476
pub span: Span,
477477
}
478+
479+
#[derive(Diagnostic)]
480+
#[diag(ast_lowering_unresolved_delegation_callee)]
481+
pub(crate) struct UnresolvedDelegationCallee {
482+
#[primary_span]
483+
pub span: Span,
484+
}

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_middle/src/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ pub struct DelegationFnSig {
245245

246246
#[derive(Debug)]
247247
pub struct DelegationResolutionInfo {
248-
pub resolution_id: ast::NodeId,
248+
pub sig_resolution_id: ast::NodeId,
249249
}
250250

251251
#[derive(Clone, Copy, Debug, HashStable)]

compiler/rustc_resolve/src/late.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
2929
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
3030
use rustc_middle::middle::resolve_bound_vars::Set1;
3131
use rustc_middle::ty::{
32-
AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs, Visibility,
32+
AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs,
33+
DelegationResolutionInfo, Visibility,
3334
};
3435
use rustc_middle::ty::{AssocTag, DelegationFnSig, DelegationResolutionInfo, Visibility};
3536
use rustc_middle::{bug, span_bug};
@@ -3723,7 +3724,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
37233724
self.r.delegation_resolution_info.insert(
37243725
def_id,
37253726
DelegationResolutionInfo {
3726-
resolution_id: if is_in_trait_impl { item_id } else { delegation.id },
3727+
sig_resolution_id: if is_in_trait_impl { item_id } else { delegation.id },
37273728
},
37283729
);
37293730
}
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() {}
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
error[E0391]: cycle detected when computing generics of `foo`
2-
--> $DIR/ice-issue-124347.rs:9:7
1+
error: failed to resolve delegation callee
2+
--> $DIR/ice-issue-124347.rs:5:18
33
|
4-
LL | reuse foo;
5-
| ^^^
6-
|
7-
= note: ...which immediately requires computing generics of `foo` again
8-
note: cycle used when checking that `foo` is well-formed
4+
LL | reuse Trait::foo { &self.0 }
5+
| ^^^
6+
7+
error: failed to resolve delegation callee
98
--> $DIR/ice-issue-124347.rs:9:7
109
|
1110
LL | reuse foo;
1211
| ^^^
13-
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
1412

15-
error: aborting due to 1 previous error
13+
error: aborting due to 2 previous errors
1614

17-
For more information about this error, try `rustc --explain E0391`.

tests/ui/delegation/unsupported.current.stderr

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,15 @@ LL | reuse ToReuse::opaque_ret;
3636
| ^^^^^^^^^^
3737
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
3838

39-
error: recursive delegation is not supported yet
40-
--> $DIR/unsupported.rs:46:22
41-
|
42-
LL | pub reuse to_reuse2::foo;
43-
| --- callee defined here
44-
...
45-
LL | reuse to_reuse1::foo;
46-
| ^^^
47-
4839
error[E0283]: type annotations needed
49-
--> $DIR/unsupported.rs:55:18
40+
--> $DIR/unsupported.rs:54:18
5041
|
5142
LL | reuse Trait::foo;
5243
| ^^^ cannot infer type
5344
|
5445
= note: cannot satisfy `_: effects::Trait`
5546

56-
error: aborting due to 4 previous errors
47+
error: aborting due to 3 previous errors
5748

5849
Some errors have detailed explanations: E0283, E0391.
5950
For more information about an error, try `rustc --explain E0283`.

tests/ui/delegation/unsupported.next.stderr

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,15 @@ LL | reuse ToReuse::opaque_ret;
2828
= note: cycle used when computing implied outlives bounds for `<u16 as opaque::ToReuse>::opaque_ret::{anon_assoc#0}` (hack disabled = false)
2929
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
3030

31-
error: recursive delegation is not supported yet
32-
--> $DIR/unsupported.rs:46:22
33-
|
34-
LL | pub reuse to_reuse2::foo;
35-
| --- callee defined here
36-
...
37-
LL | reuse to_reuse1::foo;
38-
| ^^^
39-
4031
error[E0283]: type annotations needed
41-
--> $DIR/unsupported.rs:55:18
32+
--> $DIR/unsupported.rs:54:18
4233
|
4334
LL | reuse Trait::foo;
4435
| ^^^ cannot infer type
4536
|
4637
= note: cannot satisfy `_: effects::Trait`
4738

48-
error: aborting due to 4 previous errors
39+
error: aborting due to 3 previous errors
4940

5041
Some errors have detailed explanations: E0283, E0391.
5142
For more information about an error, try `rustc --explain E0283`.

0 commit comments

Comments
 (0)