Skip to content

Commit

Permalink
delegation: Implement list delegation
Browse files Browse the repository at this point in the history
```rust
reuse prefix::{a, b, c}
```
  • Loading branch information
petrochenkov committed May 14, 2024
1 parent 8387315 commit c30b410
Show file tree
Hide file tree
Showing 29 changed files with 509 additions and 58 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 @@ -2961,6 +2961,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 @@ -3123,8 +3124,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 @@ -3243,10 +3252,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 @@ -3255,7 +3267,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 @@ -3280,6 +3292,7 @@ impl ItemKind {
ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function",
ItemKind::DelegationMac(..) => "delegation",
}
}

Expand Down Expand Up @@ -3323,6 +3336,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 @@ -3331,7 +3346,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 @@ -3344,6 +3361,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 @@ -3358,6 +3376,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
26 changes: 26 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind {
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 @@ -1213,6 +1226,19 @@ impl NoopVisitItemKind for AssocItemKind {
visitor.visit_block(body);
}
}
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(body) = body {
visitor.visit_block(body);
}
}
}
}
}
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 @@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind {
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);
}
}
V::Result::output()
}
Expand Down Expand Up @@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind {
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
20 changes: 14 additions & 6 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,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 @@ -845,7 +845,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!("macros should have been expanded by now")
}
};

let item = hir::TraitItem {
Expand All @@ -869,7 +871,9 @@ 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(..) => {
panic!("macros should have been expanded by now")
}
};
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef {
Expand Down Expand Up @@ -964,7 +968,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 @@ -993,7 +999,9 @@ 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(..) => {
panic!("macros should have been expanded by now")
}
},
trait_item_def_id: self
.resolver
Expand Down
74 changes: 60 additions & 14 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 @@ -374,9 +375,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 @@ -553,31 +567,63 @@ 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");
self.word_nbsp("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.nbsp();
self.word_nbsp("as");
self.print_ident(*rename);
}
if i != suffixes.len() - 1 {
self.word_space(",");
}
}
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_paren_or_brace =
expected `(` or `{"{"}`, found `{$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 @@ -433,3 +433,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 c30b410

Please sign in to comment.