summary refs log tree commit diff
path: root/compiler/rustc_expand/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2024-03-15 14:21:03 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2024-05-15 02:32:59 +0300
commitc30b41012d474586d407392a6b154e7f19c38b2c (patch)
treeadf34f62f1c929390851853093799427734a4569 /compiler/rustc_expand/src
parent8387315ab3c26a57a1f53a90f188f0bc88514bca (diff)
downloadrust-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.rs7
-rw-r--r--compiler/rustc_expand/src/expand.rs117
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))
                 }