diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2024-03-15 14:21:03 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2024-05-15 02:32:59 +0300 |
| commit | c30b41012d474586d407392a6b154e7f19c38b2c (patch) | |
| tree | adf34f62f1c929390851853093799427734a4569 /compiler/rustc_expand/src | |
| parent | 8387315ab3c26a57a1f53a90f188f0bc88514bca (diff) | |
| download | rust-c30b41012d474586d407392a6b154e7f19c38b2c.tar.gz rust-c30b41012d474586d407392a6b154e7f19c38b2c.zip | |
delegation: Implement list delegation
```rust
reuse prefix::{a, b, c}
```
Diffstat (limited to 'compiler/rustc_expand/src')
| -rw-r--r-- | compiler/rustc_expand/src/errors.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 117 |
2 files changed, 122 insertions, 2 deletions
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index b0563bfdea7..a5fc9e9d89c 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index ddf7b1a007a..a049ac251e1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,8 +1,8 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::errors::{ - IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, - UnsupportedKeyValue, WrongFragmentKind, + EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, + RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind, }; use crate::mbe::diagnostics::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -1041,6 +1041,7 @@ enum AddSemicolon { trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { type OutputTy = SmallVec<[Self; 1]>; type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec; + type ItemKind = ItemKind; const KIND: AstFragmentKind; fn to_annotatable(self) -> Annotatable; fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; @@ -1059,6 +1060,18 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) { unreachable!() } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + None + } + fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind { + unreachable!() + } + fn from_item(_item: ast::Item<Self::ItemKind>) -> Self { + unreachable!() + } + fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { + unreachable!() + } fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {} fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) { } @@ -1106,6 +1119,21 @@ impl InvocationCollectorNode for P<ast::Item> { _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + match &self.kind { + ItemKind::DelegationMac(deleg) => Some((deleg, self)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind { + ItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item<Self::ItemKind>) -> Self { + P(item) + } + fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { + items.flatten().collect() + } fn wrap_flat_map_node_noop_flat_map( mut node: Self, collector: &mut InvocationCollector<'_, '_>, @@ -1214,6 +1242,7 @@ impl InvocationCollectorNode for P<ast::Item> { struct TraitItemTag; impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> { type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; + type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::TraitItems; fn to_annotatable(self) -> Annotatable { Annotatable::TraitItem(self.wrapped) @@ -1234,11 +1263,27 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + match &self.wrapped.kind { + AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind { + AssocItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item<Self::ItemKind>) -> Self { + AstNodeWrapper::new(P(item), TraitItemTag) + } + fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { + items.flatten().collect() + } } struct ImplItemTag; impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> { type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; + type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { Annotatable::ImplItem(self.wrapped) @@ -1259,6 +1304,21 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + match &self.wrapped.kind { + AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind { + AssocItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item<Self::ItemKind>) -> Self { + AstNodeWrapper::new(P(item), ImplItemTag) + } + fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { + items.flatten().collect() + } } impl InvocationCollectorNode for P<ast::ForeignItem> { @@ -1420,6 +1480,24 @@ impl InvocationCollectorNode for ast::Stmt { }; (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + match &self.kind { + StmtKind::Item(item) => match &item.kind { + ItemKind::DelegationMac(deleg) => Some((deleg, item)), + _ => None, + }, + _ => None, + } + } + fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind { + ItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item<Self::ItemKind>) -> Self { + ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) } + } + fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { + items.flatten().collect() + } fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) { // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -1818,6 +1896,40 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Node::post_flat_map_node_collect_bang(&mut res, add_semicolon); res } + None if let Some((deleg, item)) = node.delegation_list() => { + if deleg.suffixes.is_empty() { + // Report an error for now, to avoid keeping stem for resolution and + // stability checks. + self.cx.dcx().emit_err(EmptyDelegationList { span: item.span }); + } + + Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| { + let mut path = deleg.prefix.clone(); + path.segments.push(ast::PathSegment { + ident, + id: ast::DUMMY_NODE_ID, + args: None, + }); + + let mut item = Node::from_item(ast::Item { + attrs: item.attrs.clone(), + id: ast::DUMMY_NODE_ID, + span: ident.span, + vis: item.vis.clone(), + ident: rename.unwrap_or(ident), + kind: Node::delegation_item_kind(Box::new(ast::Delegation { + id: ast::DUMMY_NODE_ID, + qself: deleg.qself.clone(), + path, + rename, + body: deleg.body.clone(), + })), + tokens: None, + }); + + assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self)) + })) + } None => { match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this)) @@ -1866,6 +1978,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.collect_bang(mac, Node::KIND).make_ast::<Node>() }) } + None if node.delegation_list().is_some() => unreachable!(), None => { assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) } |
