Skip to content

Commit

Permalink
delegation: Implement multi-item delegation
Browse files Browse the repository at this point in the history
```rust
reuse prefix::{a, b, c}
```
  • Loading branch information
petrochenkov committed Apr 24, 2024
1 parent 5557f8c commit 6dbe452
Show file tree
Hide file tree
Showing 25 changed files with 459 additions and 55 deletions.
27 changes: 23 additions & 4 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2950,6 +2950,7 @@ impl Item {
| ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_)
| ItemKind::Delegation(_)
| ItemKind::DelegationMac(_)
| ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics),
Expand Down Expand Up @@ -3112,8 +3113,16 @@ pub struct Delegation {
/// Path resolution id.
pub id: NodeId,
pub qself: Option<P<QSelf>>,
pub rename: Option<Ident>,
pub path: Path,
pub rename: Option<Ident>,
pub body: Option<P<Block>>,
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelegationMac {
pub qself: Option<P<QSelf>>,
pub prefix: Path,
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
pub body: Option<P<Block>>,
}

Expand Down Expand Up @@ -3203,10 +3212,13 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),

/// A delegation item (`reuse`).
/// A single delegation item (`reuse`).
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
/// A list delegation item (`reuse prefix::{a, b, c}`).
/// Treated similarly to a macro call and expanded early.
DelegationMac(Box<DelegationMac>),
}

impl ItemKind {
Expand All @@ -3215,7 +3227,7 @@ impl ItemKind {
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) => "a",
| Delegation(..) | DelegationMac(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
}
}
Expand All @@ -3240,6 +3252,7 @@ impl ItemKind {
ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function",
ItemKind::DelegationMac(..) => "delegation",
}
}

Expand Down Expand Up @@ -3283,6 +3296,8 @@ pub enum AssocItemKind {
MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
/// An associated delegation item list.
DelegationMac(Box<DelegationMac>),
}

impl AssocItemKind {
Expand All @@ -3291,7 +3306,9 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
Defaultness::Final
}
}
}
}
Expand All @@ -3304,6 +3321,7 @@ impl From<AssocItemKind> for ItemKind {
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
}
}
}
Expand All @@ -3318,6 +3336,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
_ => return Err(item_kind),
})
}
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,19 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
vis.visit_block(body);
}
}
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(body) = body {
vis.visit_block(body);
}
}
}
}

Expand Down Expand Up @@ -1209,6 +1222,20 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
visitor.visit_block(body);
}
}
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
visitor.visit_id(id);
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(body) = body {
visitor.visit_block(body);
}
}
}
visitor.visit_span(span);
visit_lazy_tts(tokens, visitor);
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,19 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
if let Some(qself) = qself {
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);
}
}
visit_opt!(visitor, visit_block, body);
}
}
walk_list!(visitor, visit_attribute, &item.attrs);
V::Result::output()
Expand Down Expand Up @@ -791,6 +804,19 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
if let Some(qself) = qself {
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);
}
}
visit_opt!(visitor, visit_block, body);
}
}
V::Result::output()
}
Expand Down
16 changes: 10 additions & 6 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
delegation_results.body_id,
)
}
ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
}
}
Expand Down Expand Up @@ -844,7 +844,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(delegation_results.generics, item_kind, true)
}
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macro item shouldn't exist at this point")
}
};

let item = hir::TraitItem {
Expand All @@ -868,7 +870,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
},
AssocItemKind::MacCall(..) => unimplemented!(),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => unreachable!(),
};
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef {
Expand Down Expand Up @@ -963,7 +965,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
)
}
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
};

let item = hir::ImplItem {
Expand Down Expand Up @@ -992,7 +996,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
},
AssocItemKind::MacCall(..) => unimplemented!(),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => unreachable!(),
},
trait_item_def_id: self
.resolver
Expand Down
71 changes: 58 additions & 13 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem;
use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::ModKind;
use rustc_span::symbol::Ident;

Expand Down Expand Up @@ -371,9 +372,22 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis)
});
}
ast::ItemKind::Delegation(box delegation) => {
self.print_delegation(delegation, &item.vis, &item.attrs)
}
ast::ItemKind::Delegation(deleg) => self.print_delegation(
&item.attrs,
&item.vis,
&deleg.qself,
&deleg.path,
None,
&deleg.body,
),
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
&item.vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
&deleg.body,
),
}
self.ann.post(self, AnnNode::Item(item))
}
Expand Down Expand Up @@ -550,31 +564,62 @@ impl<'a> State<'a> {
self.word(";");
}
}
ast::AssocItemKind::Delegation(box delegation) => {
self.print_delegation(delegation, vis, &item.attrs)
}
ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
&item.attrs,
vis,
&deleg.qself,
&deleg.path,
None,
&deleg.body,
),
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
&deleg.body,
),
}
self.ann.post(self, AnnNode::SubItem(id))
}

pub(crate) fn print_delegation(
&mut self,
delegation: &ast::Delegation,
vis: &ast::Visibility,
attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
path: &ast::Path,
suffixes: Option<&[(Ident, Option<Ident>)]>,
body: &Option<P<ast::Block>>,
) {
if delegation.body.is_some() {
if body.is_some() {
self.head("");
}
self.print_visibility(vis);
self.word_space("reuse");

if let Some(qself) = &delegation.qself {
self.print_qpath(&delegation.path, qself, false);
if let Some(qself) = qself {
self.print_qpath(path, qself, false);
} else {
self.print_path(&delegation.path, false, 0);
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.word("as");
self.print_ident(*rename);
}
if i != suffixes.len() {
self.word(",");
}
}
self.word("}");
}
if let Some(body) = &delegation.body {
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, attrs);
} else {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_expand/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding
.label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_expected_comma_in_list =
expected token: `,`
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_expand/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,10 @@ pub struct ExpectedParenOrBrace<'a> {
pub span: Span,
pub token: Cow<'a, str>,
}

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

0 comments on commit 6dbe452

Please sign in to comment.