Skip to content

Commit 7dda3b8

Browse files
committed
delegation: Implement multi-item delegation
```rust reuse prefix::{a, b, c} ```
1 parent 0e15f5e commit 7dda3b8

File tree

12 files changed

+257
-16
lines changed

12 files changed

+257
-16
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3107,12 +3107,19 @@ pub struct Fn {
31073107
pub body: Option<P<Block>>,
31083108
}
31093109

3110+
#[derive(Clone, Encodable, Decodable, Debug)]
3111+
pub enum DelegationKind {
3112+
Single,
3113+
List(ThinVec<Ident>),
3114+
}
3115+
31103116
#[derive(Clone, Encodable, Decodable, Debug)]
31113117
pub struct Delegation {
31123118
/// Path resolution id.
31133119
pub id: NodeId,
31143120
pub qself: Option<P<QSelf>>,
31153121
pub path: Path,
3122+
pub kind: DelegationKind,
31163123
pub body: Option<P<Block>>,
31173124
}
31183125

Diff for: compiler/rustc_ast/src/mut_visit.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -1149,10 +1149,18 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
11491149
}
11501150
ItemKind::MacCall(m) => vis.visit_mac_call(m),
11511151
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
1152-
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
1152+
ItemKind::Delegation(box Delegation { id, qself, path, kind, body }) => {
11531153
vis.visit_id(id);
11541154
vis.visit_qself(qself);
11551155
vis.visit_path(path);
1156+
match kind {
1157+
DelegationKind::Single => {}
1158+
DelegationKind::List(suffixes) => {
1159+
for ident in suffixes {
1160+
vis.visit_ident(ident);
1161+
}
1162+
}
1163+
}
11561164
if let Some(body) = body {
11571165
vis.visit_block(body);
11581166
}
@@ -1195,10 +1203,18 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
11951203
visit_opt(ty, |ty| visitor.visit_ty(ty));
11961204
}
11971205
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
1198-
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
1206+
AssocItemKind::Delegation(box Delegation { id, qself, path, kind, body }) => {
11991207
visitor.visit_id(id);
12001208
visitor.visit_qself(qself);
12011209
visitor.visit_path(path);
1210+
match kind {
1211+
DelegationKind::Single => {}
1212+
DelegationKind::List(suffixes) => {
1213+
for ident in suffixes {
1214+
visitor.visit_ident(ident);
1215+
}
1216+
}
1217+
}
12021218
if let Some(body) = body {
12031219
visitor.visit_block(body);
12041220
}

Diff for: compiler/rustc_ast/src/visit.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,19 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu
382382
}
383383
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
384384
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
385-
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
385+
ItemKind::Delegation(box Delegation { id, qself, path, kind, body }) => {
386386
if let Some(qself) = qself {
387387
try_visit!(visitor.visit_ty(&qself.ty));
388388
}
389389
try_visit!(visitor.visit_path(path, *id));
390+
match kind {
391+
DelegationKind::Single => {}
392+
DelegationKind::List(suffixes) => {
393+
for ident in suffixes {
394+
visitor.visit_ident(*ident);
395+
}
396+
}
397+
}
390398
visit_opt!(visitor, visit_block, body);
391399
}
392400
}
@@ -782,11 +790,19 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
782790
AssocItemKind::MacCall(mac) => {
783791
try_visit!(visitor.visit_mac_call(mac));
784792
}
785-
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
793+
AssocItemKind::Delegation(box Delegation { id, qself, path, kind, body }) => {
786794
if let Some(qself) = qself {
787795
try_visit!(visitor.visit_ty(&qself.ty));
788796
}
789797
try_visit!(visitor.visit_path(path, *id));
798+
match kind {
799+
DelegationKind::Single => {}
800+
DelegationKind::List(suffixes) => {
801+
for ident in suffixes {
802+
visitor.visit_ident(*ident);
803+
}
804+
}
805+
}
790806
visit_opt!(visitor, visit_block, body);
791807
}
792808
}

Diff for: compiler/rustc_expand/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
3030
.label = duplicate binding
3131
.label2 = previous binding
3232
33+
expand_empty_delegation_list =
34+
empty list delegation is not supported
35+
3336
expand_expected_comma_in_list =
3437
expected token: `,`
3538

Diff for: compiler/rustc_expand/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,10 @@ pub struct ExpectedParenOrBrace<'a> {
456456
pub span: Span,
457457
pub token: Cow<'a, str>,
458458
}
459+
460+
#[derive(Diagnostic)]
461+
#[diag(expand_empty_delegation_list)]
462+
pub(crate) struct EmptyDelegationList {
463+
#[primary_span]
464+
pub span: Span,
465+
}

Diff for: compiler/rustc_expand/src/expand.rs

+95-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::base::*;
22
use crate::config::StripUnconfigured;
33
use crate::errors::{
4-
IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
5-
UnsupportedKeyValue, WrongFragmentKind,
4+
EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
5+
RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
66
};
77
use crate::hygiene::SyntaxContext;
88
use crate::mbe::diagnostics::annotate_err_with_kind;
@@ -15,8 +15,8 @@ use rustc_ast::ptr::P;
1515
use rustc_ast::token::{self, Delimiter};
1616
use rustc_ast::tokenstream::TokenStream;
1717
use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorResult};
18-
use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind};
19-
use rustc_ast::{ForeignItemKind, HasAttrs, HasNodeId};
18+
use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DelegationKind};
19+
use rustc_ast::{ExprKind, ForeignItemKind, HasAttrs, HasNodeId};
2020
use rustc_ast::{Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind};
2121
use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind};
2222
use rustc_ast_pretty::pprust;
@@ -1061,7 +1061,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
10611061
fn wrap_flat_map_node_noop_flat_map(
10621062
node: Self,
10631063
collector: &mut InvocationCollector<'_, '_>,
1064-
noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
1064+
mut noop_flat_map: impl FnMut(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
10651065
) -> Result<Self::OutputTy, Self> {
10661066
Ok(noop_flat_map(node, collector))
10671067
}
@@ -1105,8 +1105,19 @@ impl InvocationCollectorNode for P<ast::Item> {
11051105
fn wrap_flat_map_node_noop_flat_map(
11061106
mut node: Self,
11071107
collector: &mut InvocationCollector<'_, '_>,
1108-
noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
1108+
mut noop_flat_map: impl FnMut(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
11091109
) -> Result<Self::OutputTy, Self> {
1110+
if let ItemKind::Delegation(deleg) = &node.kind
1111+
&& let DelegationKind::List(..) = deleg.kind
1112+
{
1113+
return Ok(collector.expand_delegation_list(
1114+
&node,
1115+
deleg,
1116+
ItemKind::Delegation,
1117+
|item, collector| noop_flat_map(item, collector),
1118+
));
1119+
}
1120+
11101121
if !matches!(node.kind, ItemKind::Mod(..)) {
11111122
return Ok(noop_flat_map(node, collector));
11121123
}
@@ -1230,6 +1241,24 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
12301241
_ => unreachable!(),
12311242
}
12321243
}
1244+
fn wrap_flat_map_node_noop_flat_map(
1245+
node: Self,
1246+
collector: &mut InvocationCollector<'_, '_>,
1247+
mut noop_flat_map: impl FnMut(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
1248+
) -> Result<Self::OutputTy, Self> {
1249+
if let AssocItemKind::Delegation(deleg) = &node.wrapped.kind
1250+
&& let DelegationKind::List(..) = deleg.kind
1251+
{
1252+
return Ok(collector.expand_delegation_list(
1253+
&node.wrapped,
1254+
deleg,
1255+
AssocItemKind::Delegation,
1256+
|item, collector| noop_flat_map(AstNodeWrapper::new(item, TraitItemTag), collector),
1257+
));
1258+
}
1259+
1260+
Ok(noop_flat_map(node, collector))
1261+
}
12331262
}
12341263

12351264
struct ImplItemTag;
@@ -1255,6 +1284,24 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
12551284
_ => unreachable!(),
12561285
}
12571286
}
1287+
fn wrap_flat_map_node_noop_flat_map(
1288+
node: Self,
1289+
collector: &mut InvocationCollector<'_, '_>,
1290+
mut noop_flat_map: impl FnMut(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
1291+
) -> Result<Self::OutputTy, Self> {
1292+
if let AssocItemKind::Delegation(deleg) = &node.wrapped.kind
1293+
&& let DelegationKind::List(..) = deleg.kind
1294+
{
1295+
return Ok(collector.expand_delegation_list(
1296+
&node.wrapped,
1297+
deleg,
1298+
AssocItemKind::Delegation,
1299+
|item, collector| noop_flat_map(AstNodeWrapper::new(item, ImplItemTag), collector),
1300+
));
1301+
}
1302+
1303+
Ok(noop_flat_map(node, collector))
1304+
}
12581305
}
12591306

12601307
impl InvocationCollectorNode for P<ast::ForeignItem> {
@@ -1773,6 +1820,48 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17731820
});
17741821
}
17751822

1823+
fn expand_delegation_list<K: 'static>(
1824+
&mut self,
1825+
item: &ast::Item<K>,
1826+
deleg: &ast::Delegation,
1827+
kind_delegation: impl Copy + FnOnce(Box<ast::Delegation>) -> K,
1828+
mut noop_flat_map: impl FnMut(P<ast::Item<K>>, &mut Self) -> SmallVec<[P<ast::Item<K>>; 1]>,
1829+
) -> SmallVec<[P<ast::Item<K>>; 1]> {
1830+
assert_eq!(item.id, ast::DUMMY_NODE_ID);
1831+
let DelegationKind::List(suffixes) = &deleg.kind else { unreachable!() };
1832+
1833+
if suffixes.is_empty() {
1834+
// Report an error for now, to avoid keeping stem for resolution and stability checks.
1835+
self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
1836+
}
1837+
1838+
suffixes
1839+
.iter()
1840+
.flat_map(|&ident| {
1841+
let mut path = deleg.path.clone();
1842+
path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None });
1843+
1844+
let item = ast::Item {
1845+
attrs: item.attrs.clone(),
1846+
id: item.id,
1847+
span: item.span,
1848+
vis: item.vis.clone(),
1849+
ident,
1850+
kind: kind_delegation(Box::new(ast::Delegation {
1851+
id: ast::DUMMY_NODE_ID,
1852+
qself: deleg.qself.clone(),
1853+
path,
1854+
kind: DelegationKind::Single,
1855+
body: deleg.body.clone(),
1856+
})),
1857+
tokens: item.tokens.clone(),
1858+
};
1859+
1860+
noop_flat_map(P(item), self)
1861+
})
1862+
.collect()
1863+
}
1864+
17761865
fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
17771866
&mut self,
17781867
mut node: Node,

Diff for: compiler/rustc_parse/src/parser/item.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,14 @@ impl<'a> Parser<'a> {
686686
(None, self.parse_path(PathStyle::Expr)?)
687687
};
688688

689+
let kind = if self.eat(&token::ModSep) {
690+
let (suffixes, _) =
691+
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_path_segment_ident())?;
692+
DelegationKind::List(suffixes)
693+
} else {
694+
DelegationKind::Single
695+
};
696+
689697
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
690698
Some(self.parse_block()?)
691699
} else {
@@ -696,10 +704,8 @@ impl<'a> Parser<'a> {
696704
self.psess.gated_spans.gate(sym::fn_delegation, span);
697705

698706
let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
699-
Ok((
700-
ident,
701-
ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
702-
))
707+
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, kind, body };
708+
Ok((ident, ItemKind::Delegation(Box::new(deleg))))
703709
}
704710

705711
fn parse_item_list<T>(

Diff for: compiler/rustc_parse/src/parser/path.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,15 @@ impl<'a> Parser<'a> {
9595
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
9696
}
9797

98-
if !self.recover_colon_before_qpath_proj() {
98+
let is_import_coupler = self.is_import_coupler();
99+
if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
99100
self.expect(&token::PathSep)?;
100101
}
101102

102103
let qself = P(QSelf { ty, path_span, position: path.segments.len() });
103-
self.parse_path_segments(&mut path.segments, style, None)?;
104+
if !is_import_coupler {
105+
self.parse_path_segments(&mut path.segments, style, None)?;
106+
}
104107

105108
Ok((
106109
qself,

Diff for: tests/ui/delegation/multiple-names-body-identity.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
3+
#![feature(fn_delegation)]
4+
#![allow(incomplete_features)]
5+
6+
trait Trait {
7+
fn foo(&self) {}
8+
fn bar(&self) {}
9+
}
10+
11+
impl Trait for u8 {}
12+
13+
struct S(u8);
14+
15+
mod to_import {
16+
pub fn check(arg: &u8) -> &u8 { arg }
17+
}
18+
19+
impl Trait for S {
20+
reuse Trait::{foo, bar} {
21+
use to_import::check;
22+
23+
let _arr = Some(self.0).map(|x| [x * 2; 3]);
24+
check(&self.0)
25+
}
26+
}
27+
28+
fn main() {
29+
let s = S(0);
30+
s.foo();
31+
s.bar();
32+
}

Diff for: tests/ui/delegation/multiple-names-empty.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(fn_delegation)]
2+
#![allow(incomplete_features)]
3+
4+
mod m {}
5+
6+
reuse m::{}; //~ ERROR empty list delegation is not supported
7+
8+
fn main() {}

Diff for: tests/ui/delegation/multiple-names-empty.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: empty list delegation is not supported
2+
--> $DIR/multiple-names-empty.rs:6:1
3+
|
4+
LL | reuse m::{};
5+
| ^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)