Skip to content

Commit 22d0b1e

Browse files
committed
delegation: Implement glob delegation
1 parent 7ac6c2f commit 22d0b1e

31 files changed

+893
-136
lines changed

compiler/rustc_ast/src/ast.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -3158,13 +3158,16 @@ pub struct Delegation {
31583158
pub path: Path,
31593159
pub rename: Option<Ident>,
31603160
pub body: Option<P<Block>>,
3161+
/// The item was expanded from a glob delegation item.
3162+
pub from_glob: bool,
31613163
}
31623164

31633165
#[derive(Clone, Encodable, Decodable, Debug)]
31643166
pub struct DelegationMac {
31653167
pub qself: Option<P<QSelf>>,
31663168
pub prefix: Path,
3167-
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
3169+
// Some for list delegation, and None for glob delegation.
3170+
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
31683171
pub body: Option<P<Block>>,
31693172
}
31703173

@@ -3291,7 +3294,7 @@ pub enum ItemKind {
32913294
///
32923295
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
32933296
Delegation(Box<Delegation>),
3294-
/// A list delegation item (`reuse prefix::{a, b, c}`).
3297+
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
32953298
/// Treated similarly to a macro call and expanded early.
32963299
DelegationMac(Box<DelegationMac>),
32973300
}
@@ -3372,7 +3375,7 @@ pub enum AssocItemKind {
33723375
MacCall(P<MacCall>),
33733376
/// An associated delegation item.
33743377
Delegation(Box<Delegation>),
3375-
/// An associated delegation item list.
3378+
/// An associated list or glob delegation item.
33763379
DelegationMac(Box<DelegationMac>),
33773380
}
33783381

compiler/rustc_ast/src/mut_visit.rs

+28-10
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
11621162
}
11631163
ItemKind::MacCall(m) => vis.visit_mac_call(m),
11641164
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
1165-
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
1165+
ItemKind::Delegation(box Delegation {
1166+
id,
1167+
qself,
1168+
path,
1169+
rename,
1170+
body,
1171+
from_glob: _,
1172+
}) => {
11661173
vis.visit_id(id);
11671174
vis.visit_qself(qself);
11681175
vis.visit_path(path);
@@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
11761183
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
11771184
vis.visit_qself(qself);
11781185
vis.visit_path(prefix);
1179-
for (ident, rename) in suffixes {
1180-
vis.visit_ident(ident);
1181-
if let Some(rename) = rename {
1182-
vis.visit_ident(rename);
1186+
if let Some(suffixes) = suffixes {
1187+
for (ident, rename) in suffixes {
1188+
vis.visit_ident(ident);
1189+
if let Some(rename) = rename {
1190+
vis.visit_ident(rename);
1191+
}
11831192
}
11841193
}
11851194
if let Some(body) = body {
@@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
12181227
visit_opt(ty, |ty| visitor.visit_ty(ty));
12191228
}
12201229
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
1221-
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
1230+
AssocItemKind::Delegation(box Delegation {
1231+
id,
1232+
qself,
1233+
path,
1234+
rename,
1235+
body,
1236+
from_glob: _,
1237+
}) => {
12221238
visitor.visit_id(id);
12231239
visitor.visit_qself(qself);
12241240
visitor.visit_path(path);
@@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
12321248
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
12331249
visitor.visit_qself(qself);
12341250
visitor.visit_path(prefix);
1235-
for (ident, rename) in suffixes {
1236-
visitor.visit_ident(ident);
1237-
if let Some(rename) = rename {
1238-
visitor.visit_ident(rename);
1251+
if let Some(suffixes) = suffixes {
1252+
for (ident, rename) in suffixes {
1253+
visitor.visit_ident(ident);
1254+
if let Some(rename) = rename {
1255+
visitor.visit_ident(rename);
1256+
}
12391257
}
12401258
}
12411259
if let Some(body) = body {

compiler/rustc_ast/src/visit.rs

+28-10
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,14 @@ impl WalkItemKind for ItemKind {
398398
}
399399
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
400400
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
401-
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
401+
ItemKind::Delegation(box Delegation {
402+
id,
403+
qself,
404+
path,
405+
rename,
406+
body,
407+
from_glob: _,
408+
}) => {
402409
if let Some(qself) = qself {
403410
try_visit!(visitor.visit_ty(&qself.ty));
404411
}
@@ -411,10 +418,12 @@ impl WalkItemKind for ItemKind {
411418
try_visit!(visitor.visit_ty(&qself.ty));
412419
}
413420
try_visit!(visitor.visit_path(prefix, item.id));
414-
for (ident, rename) in suffixes {
415-
visitor.visit_ident(*ident);
416-
if let Some(rename) = rename {
417-
visitor.visit_ident(*rename);
421+
if let Some(suffixes) = suffixes {
422+
for (ident, rename) in suffixes {
423+
visitor.visit_ident(*ident);
424+
if let Some(rename) = rename {
425+
visitor.visit_ident(*rename);
426+
}
418427
}
419428
}
420429
visit_opt!(visitor, visit_block, body);
@@ -828,7 +837,14 @@ impl WalkItemKind for AssocItemKind {
828837
AssocItemKind::MacCall(mac) => {
829838
try_visit!(visitor.visit_mac_call(mac));
830839
}
831-
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
840+
AssocItemKind::Delegation(box Delegation {
841+
id,
842+
qself,
843+
path,
844+
rename,
845+
body,
846+
from_glob: _,
847+
}) => {
832848
if let Some(qself) = qself {
833849
try_visit!(visitor.visit_ty(&qself.ty));
834850
}
@@ -841,10 +857,12 @@ impl WalkItemKind for AssocItemKind {
841857
try_visit!(visitor.visit_ty(&qself.ty));
842858
}
843859
try_visit!(visitor.visit_path(prefix, item.id));
844-
for (ident, rename) in suffixes {
845-
visitor.visit_ident(*ident);
846-
if let Some(rename) = rename {
847-
visitor.visit_ident(*rename);
860+
if let Some(suffixes) = suffixes {
861+
for (ident, rename) in suffixes {
862+
visitor.visit_ident(*ident);
863+
if let Some(rename) = rename {
864+
visitor.visit_ident(*rename);
865+
}
848866
}
849867
}
850868
visit_opt!(visitor, visit_block, body);

compiler/rustc_ast_pretty/src/pprust/state/item.rs

+32-19
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
99
use rustc_ast::ModKind;
1010
use rustc_span::symbol::Ident;
1111

12+
enum DelegationKind<'a> {
13+
Single,
14+
List(&'a [(Ident, Option<Ident>)]),
15+
Glob,
16+
}
17+
1218
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
1319
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
1420
}
@@ -387,15 +393,15 @@ impl<'a> State<'a> {
387393
&item.vis,
388394
&deleg.qself,
389395
&deleg.path,
390-
None,
396+
DelegationKind::Single,
391397
&deleg.body,
392398
),
393399
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
394400
&item.attrs,
395401
&item.vis,
396402
&deleg.qself,
397403
&deleg.prefix,
398-
Some(&deleg.suffixes),
404+
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
399405
&deleg.body,
400406
),
401407
}
@@ -579,28 +585,28 @@ impl<'a> State<'a> {
579585
vis,
580586
&deleg.qself,
581587
&deleg.path,
582-
None,
588+
DelegationKind::Single,
583589
&deleg.body,
584590
),
585591
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
586592
&item.attrs,
587593
vis,
588594
&deleg.qself,
589595
&deleg.prefix,
590-
Some(&deleg.suffixes),
596+
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
591597
&deleg.body,
592598
),
593599
}
594600
self.ann.post(self, AnnNode::SubItem(id))
595601
}
596602

597-
pub(crate) fn print_delegation(
603+
fn print_delegation(
598604
&mut self,
599605
attrs: &[ast::Attribute],
600606
vis: &ast::Visibility,
601607
qself: &Option<P<ast::QSelf>>,
602608
path: &ast::Path,
603-
suffixes: Option<&[(Ident, Option<Ident>)]>,
609+
kind: DelegationKind<'_>,
604610
body: &Option<P<ast::Block>>,
605611
) {
606612
if body.is_some() {
@@ -614,21 +620,28 @@ impl<'a> State<'a> {
614620
} else {
615621
self.print_path(path, false, 0);
616622
}
617-
if let Some(suffixes) = suffixes {
618-
self.word("::");
619-
self.word("{");
620-
for (i, (ident, rename)) in suffixes.iter().enumerate() {
621-
self.print_ident(*ident);
622-
if let Some(rename) = rename {
623-
self.nbsp();
624-
self.word_nbsp("as");
625-
self.print_ident(*rename);
626-
}
627-
if i != suffixes.len() - 1 {
628-
self.word_space(",");
623+
match kind {
624+
DelegationKind::Single => {}
625+
DelegationKind::List(suffixes) => {
626+
self.word("::");
627+
self.word("{");
628+
for (i, (ident, rename)) in suffixes.iter().enumerate() {
629+
self.print_ident(*ident);
630+
if let Some(rename) = rename {
631+
self.nbsp();
632+
self.word_nbsp("as");
633+
self.print_ident(*rename);
634+
}
635+
if i != suffixes.len() - 1 {
636+
self.word_space(",");
637+
}
629638
}
639+
self.word("}");
640+
}
641+
DelegationKind::Glob => {
642+
self.word("::");
643+
self.word("*");
630644
}
631-
self.word("}");
632645
}
633646
if let Some(body) = body {
634647
self.nbsp();

compiler/rustc_expand/messages.ftl

+5-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
3535
.label = duplicate binding
3636
.label2 = previous binding
3737
38-
expand_empty_delegation_list =
39-
empty list delegation is not supported
38+
expand_empty_delegation_mac =
39+
empty {$kind} delegation is not supported
4040
4141
expand_expected_paren_or_brace =
4242
expected `(` or `{"{"}`, found `{$token}`
@@ -58,6 +58,9 @@ expand_feature_removed =
5858
.label = feature has been removed
5959
.reason = {$reason}
6060
61+
expand_glob_delegation_outside_impls =
62+
glob delegation is only supported in impls
63+
6164
expand_helper_attribute_name_invalid =
6265
`{$name}` cannot be a name of derive helper attribute
6366

compiler/rustc_expand/src/base.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ where
357357
}
358358
}
359359

360+
pub trait GlobDelegationExpander {
361+
fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>;
362+
}
363+
360364
// Use a macro because forwarding to a simple function has type system issues
361365
macro_rules! make_stmts_default {
362366
($me:expr) => {
@@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
714718
/// The produced AST fragment is appended to the input AST fragment.
715719
Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
716720
),
721+
722+
/// A glob delegation.
723+
GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
717724
}
718725

719726
/// A struct representing a macro definition in "lowered" form ready for expansion.
@@ -748,7 +755,9 @@ impl SyntaxExtension {
748755
/// Returns which kind of macro calls this syntax extension.
749756
pub fn macro_kind(&self) -> MacroKind {
750757
match self.kind {
751-
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
758+
SyntaxExtensionKind::Bang(..)
759+
| SyntaxExtensionKind::LegacyBang(..)
760+
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
752761
SyntaxExtensionKind::Attr(..)
753762
| SyntaxExtensionKind::LegacyAttr(..)
754763
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
@@ -922,6 +931,32 @@ impl SyntaxExtension {
922931
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
923932
}
924933

934+
pub fn glob_delegation(
935+
trait_def_id: DefId,
936+
impl_def_id: LocalDefId,
937+
edition: Edition,
938+
) -> SyntaxExtension {
939+
struct GlobDelegationExpanderImpl {
940+
trait_def_id: DefId,
941+
impl_def_id: LocalDefId,
942+
}
943+
impl GlobDelegationExpander for GlobDelegationExpanderImpl {
944+
fn expand(
945+
&self,
946+
ecx: &mut ExtCtxt<'_>,
947+
) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> {
948+
match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
949+
Ok(suffixes) => ExpandResult::Ready(suffixes),
950+
Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
951+
Err(Indeterminate) => ExpandResult::Retry(()),
952+
}
953+
}
954+
}
955+
956+
let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
957+
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition)
958+
}
959+
925960
pub fn expn_data(
926961
&self,
927962
parent: LocalExpnId,
@@ -1030,6 +1065,16 @@ pub trait ResolverExpand {
10301065

10311066
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
10321067
fn registered_tools(&self) -> &RegisteredTools;
1068+
1069+
/// Mark this invocation id as a glob delegation.
1070+
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId);
1071+
1072+
/// Names of specific methods to which glob delegation expands.
1073+
fn glob_delegation_suffixes(
1074+
&mut self,
1075+
trait_def_id: DefId,
1076+
impl_def_id: LocalDefId,
1077+
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
10331078
}
10341079

10351080
pub trait LintStoreExpand {

compiler/rustc_expand/src/errors.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
435435
}
436436

437437
#[derive(Diagnostic)]
438-
#[diag(expand_empty_delegation_list)]
439-
pub(crate) struct EmptyDelegationList {
438+
#[diag(expand_empty_delegation_mac)]
439+
pub(crate) struct EmptyDelegationMac {
440+
#[primary_span]
441+
pub span: Span,
442+
pub kind: String,
443+
}
444+
445+
#[derive(Diagnostic)]
446+
#[diag(expand_glob_delegation_outside_impls)]
447+
pub(crate) struct GlobDelegationOutsideImpls {
440448
#[primary_span]
441449
pub span: Span,
442450
}

0 commit comments

Comments
 (0)