Skip to content

Commit

Permalink
delegation: Implement glob delegation
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Jun 14, 2024
1 parent 7ac6c2f commit 22d0b1e
Show file tree
Hide file tree
Showing 31 changed files with 893 additions and 136 deletions.
9 changes: 6 additions & 3 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3158,13 +3158,16 @@ pub struct Delegation {
pub path: Path,
pub rename: Option<Ident>,
pub body: Option<P<Block>>,
/// The item was expanded from a glob delegation item.
pub from_glob: bool,
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelegationMac {
pub qself: Option<P<QSelf>>,
pub prefix: Path,
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
// Some for list delegation, and None for glob delegation.
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
pub body: Option<P<Block>>,
}

Expand Down Expand Up @@ -3291,7 +3294,7 @@ pub enum ItemKind {
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
/// A list delegation item (`reuse prefix::{a, b, c}`).
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
/// Treated similarly to a macro call and expanded early.
DelegationMac(Box<DelegationMac>),
}
Expand Down Expand Up @@ -3372,7 +3375,7 @@ pub enum AssocItemKind {
MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
/// An associated delegation item list.
/// An associated list or glob delegation item.
DelegationMac(Box<DelegationMac>),
}

Expand Down
38 changes: 28 additions & 10 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
Expand All @@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
vis.visit_qself(qself);
vis.visit_path(prefix);
for (ident, rename) in suffixes {
vis.visit_ident(ident);
if let Some(rename) = rename {
vis.visit_ident(rename);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
vis.visit_ident(ident);
if let Some(rename) = rename {
vis.visit_ident(rename);
}
}
}
if let Some(body) = body {
Expand Down Expand Up @@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
visitor.visit_id(id);
visitor.visit_qself(qself);
visitor.visit_path(path);
Expand All @@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
visitor.visit_qself(qself);
visitor.visit_path(prefix);
for (ident, rename) in suffixes {
visitor.visit_ident(ident);
if let Some(rename) = rename {
visitor.visit_ident(rename);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(ident);
if let Some(rename) = rename {
visitor.visit_ident(rename);
}
}
}
if let Some(body) = body {
Expand Down
38 changes: 28 additions & 10 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,14 @@ impl WalkItemKind for ItemKind {
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
Expand All @@ -411,10 +418,12 @@ impl WalkItemKind for ItemKind {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);
Expand Down Expand Up @@ -828,7 +837,14 @@ impl WalkItemKind for AssocItemKind {
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
Expand All @@ -841,10 +857,12 @@ impl WalkItemKind for AssocItemKind {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);
Expand Down
51 changes: 32 additions & 19 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
use rustc_ast::ModKind;
use rustc_span::symbol::Ident;

enum DelegationKind<'a> {
Single,
List(&'a [(Ident, Option<Ident>)]),
Glob,
}

fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
}
Expand Down Expand Up @@ -387,15 +393,15 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
&item.vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
Expand Down Expand Up @@ -579,28 +585,28 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
self.ann.post(self, AnnNode::SubItem(id))
}

pub(crate) fn print_delegation(
fn print_delegation(
&mut self,
attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
path: &ast::Path,
suffixes: Option<&[(Ident, Option<Ident>)]>,
kind: DelegationKind<'_>,
body: &Option<P<ast::Block>>,
) {
if body.is_some() {
Expand All @@ -614,21 +620,28 @@ impl<'a> State<'a> {
} else {
self.print_path(path, false, 0);
}
if let Some(suffixes) = suffixes {
self.word("::");
self.word("{");
for (i, (ident, rename)) in suffixes.iter().enumerate() {
self.print_ident(*ident);
if let Some(rename) = rename {
self.nbsp();
self.word_nbsp("as");
self.print_ident(*rename);
}
if i != suffixes.len() - 1 {
self.word_space(",");
match kind {
DelegationKind::Single => {}
DelegationKind::List(suffixes) => {
self.word("::");
self.word("{");
for (i, (ident, rename)) in suffixes.iter().enumerate() {
self.print_ident(*ident);
if let Some(rename) = rename {
self.nbsp();
self.word_nbsp("as");
self.print_ident(*rename);
}
if i != suffixes.len() - 1 {
self.word_space(",");
}
}
self.word("}");
}
DelegationKind::Glob => {
self.word("::");
self.word("*");
}
self.word("}");
}
if let Some(body) = body {
self.nbsp();
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_expand/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding
.label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_empty_delegation_mac =
empty {$kind} delegation is not supported
expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}`
Expand All @@ -58,6 +58,9 @@ expand_feature_removed =
.label = feature has been removed
.reason = {$reason}
expand_glob_delegation_outside_impls =
glob delegation is only supported in impls
expand_helper_attribute_name_invalid =
`{$name}` cannot be a name of derive helper attribute
Expand Down
47 changes: 46 additions & 1 deletion compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,10 @@ where
}
}

pub trait GlobDelegationExpander {
fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>;
}

// Use a macro because forwarding to a simple function has type system issues
macro_rules! make_stmts_default {
($me:expr) => {
Expand Down Expand Up @@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
/// The produced AST fragment is appended to the input AST fragment.
Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),

/// A glob delegation.
GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
}

/// A struct representing a macro definition in "lowered" form ready for expansion.
Expand Down Expand Up @@ -748,7 +755,9 @@ impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn macro_kind(&self) -> MacroKind {
match self.kind {
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Bang(..)
| SyntaxExtensionKind::LegacyBang(..)
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
Expand Down Expand Up @@ -922,6 +931,32 @@ impl SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
}

pub fn glob_delegation(
trait_def_id: DefId,
impl_def_id: LocalDefId,
edition: Edition,
) -> SyntaxExtension {
struct GlobDelegationExpanderImpl {
trait_def_id: DefId,
impl_def_id: LocalDefId,
}
impl GlobDelegationExpander for GlobDelegationExpanderImpl {
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> {
match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
Ok(suffixes) => ExpandResult::Ready(suffixes),
Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
Err(Indeterminate) => ExpandResult::Retry(()),
}
}
}

let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition)
}

pub fn expn_data(
&self,
parent: LocalExpnId,
Expand Down Expand Up @@ -1030,6 +1065,16 @@ pub trait ResolverExpand {

/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &RegisteredTools;

/// Mark this invocation id as a glob delegation.
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId);

/// Names of specific methods to which glob delegation expands.
fn glob_delegation_suffixes(
&mut self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
}

pub trait LintStoreExpand {
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_expand/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
}

#[derive(Diagnostic)]
#[diag(expand_empty_delegation_list)]
pub(crate) struct EmptyDelegationList {
#[diag(expand_empty_delegation_mac)]
pub(crate) struct EmptyDelegationMac {
#[primary_span]
pub span: Span,
pub kind: String,
}

#[derive(Diagnostic)]
#[diag(expand_glob_delegation_outside_impls)]
pub(crate) struct GlobDelegationOutsideImpls {
#[primary_span]
pub span: Span,
}
Expand Down
Loading

0 comments on commit 22d0b1e

Please sign in to comment.