From c30b41012d474586d407392a6b154e7f19c38b2c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 15 Mar 2024 14:21:03 +0300 Subject: [PATCH] delegation: Implement list delegation ```rust reuse prefix::{a, b, c} ``` --- compiler/rustc_ast/src/ast.rs | 27 +++- compiler/rustc_ast/src/mut_visit.rs | 26 ++++ compiler/rustc_ast/src/visit.rs | 26 ++++ compiler/rustc_ast_lowering/src/item.rs | 20 ++- .../rustc_ast_pretty/src/pprust/state/item.rs | 74 ++++++++--- compiler/rustc_expand/messages.ftl | 3 + compiler/rustc_expand/src/errors.rs | 7 ++ compiler/rustc_expand/src/expand.rs | 117 +++++++++++++++++- compiler/rustc_parse/src/parser/item.rs | 35 ++++-- compiler/rustc_parse/src/parser/path.rs | 7 +- compiler/rustc_passes/src/hir_stats.rs | 5 +- compiler/rustc_passes/src/lang_items.rs | 8 +- .../rustc_resolve/src/build_reduced_graph.rs | 6 +- compiler/rustc_resolve/src/def_collector.rs | 2 + .../src/effective_visibilities.rs | 2 +- compiler/rustc_resolve/src/late.rs | 15 ++- .../rustc_resolve/src/late/diagnostics.rs | 4 +- src/tools/rustfmt/src/items.rs | 4 +- src/tools/rustfmt/src/visitor.rs | 2 +- tests/ui/delegation/bad-resolve.rs | 4 + tests/ui/delegation/bad-resolve.stderr | 16 ++- tests/ui/delegation/body-identity-list.rs | 32 +++++ tests/ui/delegation/empty-list.rs | 8 ++ tests/ui/delegation/empty-list.stderr | 8 ++ tests/ui/delegation/inner-attr.rs | 8 ++ tests/ui/delegation/inner-attr.stderr | 18 +++ tests/ui/delegation/list.rs | 46 +++++++ tests/ui/delegation/macro-inside-list.rs | 26 ++++ tests/ui/delegation/rename.rs | 15 ++- 29 files changed, 511 insertions(+), 60 deletions(-) create mode 100644 tests/ui/delegation/body-identity-list.rs create mode 100644 tests/ui/delegation/empty-list.rs create mode 100644 tests/ui/delegation/empty-list.stderr create mode 100644 tests/ui/delegation/inner-attr.rs create mode 100644 tests/ui/delegation/inner-attr.stderr create mode 100644 tests/ui/delegation/list.rs create mode 100644 tests/ui/delegation/macro-inside-list.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7951b7e7b75..6d3ee2bb54b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2961,6 +2961,7 @@ pub fn opt_generics(&self) -> Option<&Generics> { | ItemKind::GlobalAsm(_) | ItemKind::MacCall(_) | ItemKind::Delegation(_) + | ItemKind::DelegationMac(_) | ItemKind::MacroDef(_) => None, ItemKind::Static(_) => None, ItemKind::Const(i) => Some(&i.generics), @@ -3123,8 +3124,16 @@ pub struct Delegation { /// Path resolution id. pub id: NodeId, pub qself: Option>, - pub rename: Option, pub path: Path, + pub rename: Option, + pub body: Option>, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct DelegationMac { + pub qself: Option>, + pub prefix: Path, + pub suffixes: ThinVec<(Ident, Option)>, pub body: Option>, } @@ -3243,10 +3252,13 @@ pub enum ItemKind { /// A macro definition. MacroDef(MacroDef), - /// A delegation item (`reuse`). + /// A single delegation item (`reuse`). /// /// E.g. `reuse ::name { target_expr_template }`. Delegation(Box), + /// A list delegation item (`reuse prefix::{a, b, c}`). + /// Treated similarly to a macro call and expanded early. + DelegationMac(Box), } impl ItemKind { @@ -3255,7 +3267,7 @@ pub fn article(&self) -> &'static str { 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", } } @@ -3280,6 +3292,7 @@ pub fn descr(&self) -> &'static str { ItemKind::MacroDef(..) => "macro definition", ItemKind::Impl { .. } => "implementation", ItemKind::Delegation(..) => "delegated function", + ItemKind::DelegationMac(..) => "delegation", } } @@ -3323,6 +3336,8 @@ pub enum AssocItemKind { MacCall(P), /// An associated delegation item. Delegation(Box), + /// An associated delegation item list. + DelegationMac(Box), } impl AssocItemKind { @@ -3331,7 +3346,9 @@ pub fn defaultness(&self) -> Defaultness { 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 + } } } } @@ -3344,6 +3361,7 @@ fn from(assoc_item_kind: AssocItemKind) -> 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), } } } @@ -3358,6 +3376,7 @@ fn try_from(item_kind: ItemKind) -> Result { 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), }) } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5c4162295bb..1cfb8972a62 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1170,6 +1170,19 @@ fn noop_visit(&mut self, vis: &mut impl MutVisitor) { 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); + } + } } } } @@ -1213,6 +1226,19 @@ fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { 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); + } + } } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d36193ef7b0..7794edc3505 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -403,6 +403,19 @@ fn walk<'a, V: Visitor<'a>>( 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() } @@ -815,6 +828,19 @@ fn walk<'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() } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 61fb5c16ad6..1255c1bba08 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -460,8 +460,8 @@ fn lower_item_kind( 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") } } } @@ -845,7 +845,9 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'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 { @@ -869,7 +871,9 @@ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { 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 { @@ -964,7 +968,9 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'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 { @@ -993,7 +999,9 @@ fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { 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 diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 09f9ca53a7a..16c3ee948a4 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -5,6 +5,7 @@ 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; @@ -374,9 +375,22 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) { 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)) } @@ -553,31 +567,63 @@ fn print_assoc_item(&mut self, item: &ast::AssocItem) { 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>, + path: &ast::Path, + suffixes: Option<&[(Ident, Option)]>, + body: &Option>, ) { - 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(body) = &delegation.body { + 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) = body { self.nbsp(); self.print_block_with_attrs(body, attrs); } else { diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index b7aae2af9ef..7ae988a5be6 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -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}` 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 = 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 @@ fn is_mac_call(&self) -> bool { fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { unreachable!() } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + None + } + fn delegation_item_kind(_deleg: Box) -> Self::ItemKind { + unreachable!() + } + fn from_item(_item: ast::Item) -> Self { + unreachable!() + } + fn flatten_outputs(_outputs: impl Iterator) -> 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 @@ fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + match &self.kind { + ItemKind::DelegationMac(deleg) => Some((deleg, self)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box) -> Self::ItemKind { + ItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item) -> Self { + P(item) + } + fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { + items.flatten().collect() + } fn wrap_flat_map_node_noop_flat_map( mut node: Self, collector: &mut InvocationCollector<'_, '_>, @@ -1214,6 +1242,7 @@ fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec) { struct TraitItemTag; impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> { type OutputTy = SmallVec<[P; 1]>; + type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::TraitItems; fn to_annotatable(self) -> Annotatable { Annotatable::TraitItem(self.wrapped) @@ -1234,11 +1263,27 @@ fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + match &self.wrapped.kind { + AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box) -> Self::ItemKind { + AssocItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item) -> Self { + AstNodeWrapper::new(P(item), TraitItemTag) + } + fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { + items.flatten().collect() + } } struct ImplItemTag; impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> { type OutputTy = SmallVec<[P; 1]>; + type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { Annotatable::ImplItem(self.wrapped) @@ -1259,6 +1304,21 @@ fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { _ => unreachable!(), } } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + match &self.wrapped.kind { + AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box) -> Self::ItemKind { + AssocItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item) -> Self { + AstNodeWrapper::new(P(item), ImplItemTag) + } + fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { + items.flatten().collect() + } } impl InvocationCollectorNode for P { @@ -1420,6 +1480,24 @@ fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { }; (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) } + fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + match &self.kind { + StmtKind::Item(item) => match &item.kind { + ItemKind::DelegationMac(deleg) => Some((deleg, item)), + _ => None, + }, + _ => None, + } + } + fn delegation_item_kind(deleg: Box) -> Self::ItemKind { + ItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item) -> Self { + ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) } + } + fn flatten_outputs(items: impl Iterator) -> 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 @@ fn flat_map_node>( 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 @@ fn visit_node + DummyAstNode>( self.collect_bang(mac, Node::KIND).make_ast::() }) } + None if node.delegation_list().is_some() => unreachable!(), None => { assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 29957bd2f71..5a3bfb83725 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -685,20 +685,35 @@ fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> { (None, self.parse_path(PathStyle::Expr)?) }; - let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; - - let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { - Some(self.parse_block()?) - } else { - self.expect(&token::Semi)?; - None + let rename = |this: &mut Self| { + Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None }) }; + let body = |this: &mut Self| { + Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) { + Some(this.parse_block()?) + } else { + this.expect(&token::Semi)?; + None + }) + }; + + let (ident, item_kind) = if self.eat(&token::PathSep) { + let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| { + Ok((p.parse_path_segment_ident()?, rename(p)?)) + })?; + let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? }; + (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg))) + } else { + let rename = rename(self)?; + let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); + let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? }; + (ident, ItemKind::Delegation(Box::new(deleg))) + }; + let span = span.to(self.prev_token.span); self.psess.gated_spans.gate(sym::fn_delegation, span); - let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); - let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body }; - Ok((ident, ItemKind::Delegation(Box::new(deleg)))) + Ok((ident, item_kind)) } fn parse_item_list( diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c37d3f0441d..d845e8ab90d 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -95,12 +95,15 @@ pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (P, debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); } - if !self.recover_colon_before_qpath_proj() { + let is_import_coupler = self.is_import_coupler(); + if !is_import_coupler && !self.recover_colon_before_qpath_proj() { self.expect(&token::PathSep)?; } let qself = P(QSelf { ty, path_span, position: path.segments.len() }); - self.parse_path_segments(&mut path.segments, style, None)?; + if !is_import_coupler { + self.parse_path_segments(&mut path.segments, style, None)?; + } Ok(( qself, diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d7664d1c1ff..a980d5dcaba 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -522,7 +522,8 @@ fn visit_item(&mut self, i: &'v ast::Item) { Impl, MacCall, MacroDef, - Delegation + Delegation, + DelegationMac ] ); ast_visit::walk_item(self, i) @@ -650,7 +651,7 @@ fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: Span, _: NodeId) { fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { record_variants!( (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind), - [Const, Fn, Type, MacCall, Delegation] + [Const, Fn, Type, MacCall, Delegation, DelegationMac] ); ast_visit::walk_assoc_item(self, i, ctxt); } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index c1da8928f30..a5fa94faead 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -285,7 +285,9 @@ fn visit_item(&mut self, i: &'ast ast::Item) { ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, ast::ItemKind::Impl(_) => Target::Impl, ast::ItemKind::MacroDef(_) => Target::MacroDef, - ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => { + unreachable!("macros should have been expanded") + } }; self.check_for_lang( @@ -340,7 +342,9 @@ fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) } ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)), ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)), - ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => { + unreachable!("macros should have been expanded") + } }; self.check_for_lang( diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3467f1c3edf..3e9aa3e0a6f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -825,7 +825,9 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) { } ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} - ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(), + ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { + unreachable!() + } } } @@ -1381,7 +1383,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => ValueNS, AssocItemKind::Type(..) => TypeNS, - AssocItemKind::MacCall(_) => bug!(), // handled above + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above }; let parent = self.parent_scope.module; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index a27a6bceda3..741a650da55 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -139,6 +139,7 @@ fn visit_item(&mut self, i: &'a Item) { ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(..) => return visit::walk_item(self, i), ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), + ItemKind::DelegationMac(..) => unreachable!(), }; let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); @@ -278,6 +279,7 @@ fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { AssocItemKind::Const(..) => DefKind::AssocConst, AssocItemKind::Type(..) => DefKind::AssocTy, AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), + AssocItemKind::DelegationMac(..) => unreachable!(), }; let def = self.create_def(i.id, i.ident.name, def_kind, i.span); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 3443bbe6e11..074bf810eaf 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -236,7 +236,7 @@ fn visit_item(&mut self, item: &'ast ast::Item) { ast::ItemKind::Impl(..) => return, // Should be unreachable at this stage - ast::ItemKind::MacCall(..) => panic!( + ast::ItemKind::MacCall(..) | ast::ItemKind::DelegationMac(..) => panic!( "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage" ), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5dd95a1896b..322f2922f92 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2561,7 +2561,9 @@ fn resolve_item(&mut self, item: &'ast Item) { ItemKind::ExternCrate(..) => {} - ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"), + ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { + panic!("unexpanded macro in resolve!") + } } } @@ -2849,7 +2851,7 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [P]) { .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) }), - AssocItemKind::MacCall(_) => { + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { panic!("unexpanded macro in resolve!") } }; @@ -3116,7 +3118,7 @@ fn resolve_impl_item( }, ); } - AssocItemKind::MacCall(_) => { + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { panic!("unexpanded macro in resolve!") } } @@ -3218,7 +3220,9 @@ fn check_trait_item( AssocItemKind::Fn(..) => (E0324, "method"), AssocItemKind::Type(..) => (E0325, "type"), AssocItemKind::Delegation(..) => (E0324, "method"), - AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"), + AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { + span_bug!(span, "unexpanded macro") + } }; let trait_path = path_names_to_string(path); self.report_error( @@ -4790,7 +4794,8 @@ fn visit_item(&mut self, item: &'ast Item) { | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) - | ItemKind::MacCall(..) => {} + | ItemKind::MacCall(..) + | ItemKind::DelegationMac(..) => {} ItemKind::Delegation(..) => { // Delegated functions have lifetimes, their count is not necessarily zero. // But skipping the delegation items here doesn't mean that the count will be considered zero, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 64451030adf..12815291c1d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2045,7 +2045,9 @@ fn extract_node_id(t: &Ty) -> Option { AssocSuggestion::MethodWithSelf { called } } ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called }, - ast::AssocItemKind::MacCall(_) => continue, + ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => { + continue; + } }); } } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e196d1817f3..90e9e58ef9c 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -739,8 +739,8 @@ fn visit_impl_items(&mut self, items: &[ptr::P]) { (_, Const(..)) => Ordering::Greater, (MacCall(..), _) => Ordering::Less, (_, MacCall(..)) => Ordering::Greater, - (Delegation(..), _) => Ordering::Less, - (_, Delegation(..)) => Ordering::Greater, + (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less, + (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater, }); let mut prev_kind = None; for (buf, item) in buffer { diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 6209b37004b..e1c7dc35087 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -586,7 +586,7 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) { ); self.push_rewrite(item.span, rewrite); } - ast::ItemKind::Delegation(..) => { + ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => { // TODO: rewrite delegation items once syntax is established. // For now, leave the contents of the Span unformatted. self.push_rewrite(item.span, None) diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index d2723dc32e0..f378e05304b 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -36,4 +36,8 @@ impl Trait for S { //~^ ERROR cannot find function `foo` in this scope } +mod prefix {} +reuse unresolved_prefix::{a, b, c}; //~ ERROR use of undeclared crate or module `unresolved_prefix` +reuse prefix::{self, super, crate}; //~ ERROR `crate` in paths can only be used in start position + fn main() {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index f669ac3730e..883ff523bcf 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -63,7 +63,19 @@ LL | type Type; LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation -error: aborting due to 8 previous errors +error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix` + --> $DIR/bad-resolve.rs:40:7 + | +LL | reuse unresolved_prefix::{a, b, c}; + | ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix` -Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0575, E0576. +error[E0433]: failed to resolve: `crate` in paths can only be used in start position + --> $DIR/bad-resolve.rs:41:29 + | +LL | reuse prefix::{self, super, crate}; + | ^^^^^ `crate` in paths can only be used in start position + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/body-identity-list.rs b/tests/ui/delegation/body-identity-list.rs new file mode 100644 index 00000000000..1f08ab4e1a4 --- /dev/null +++ b/tests/ui/delegation/body-identity-list.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait::{foo, bar} { + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); + s.bar(); +} diff --git a/tests/ui/delegation/empty-list.rs b/tests/ui/delegation/empty-list.rs new file mode 100644 index 00000000000..e0697f42283 --- /dev/null +++ b/tests/ui/delegation/empty-list.rs @@ -0,0 +1,8 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod m {} + +reuse m::{}; //~ ERROR empty list delegation is not supported + +fn main() {} diff --git a/tests/ui/delegation/empty-list.stderr b/tests/ui/delegation/empty-list.stderr new file mode 100644 index 00000000000..50d3c0eee22 --- /dev/null +++ b/tests/ui/delegation/empty-list.stderr @@ -0,0 +1,8 @@ +error: empty list delegation is not supported + --> $DIR/empty-list.rs:6:1 + | +LL | reuse m::{}; + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/inner-attr.rs b/tests/ui/delegation/inner-attr.rs new file mode 100644 index 00000000000..6c996807d6b --- /dev/null +++ b/tests/ui/delegation/inner-attr.rs @@ -0,0 +1,8 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +fn a() {} + +reuse a as b { #![rustc_dummy] self } //~ ERROR an inner attribute is not permitted in this context + +fn main() {} diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr new file mode 100644 index 00000000000..f3b53e331ad --- /dev/null +++ b/tests/ui/delegation/inner-attr.stderr @@ -0,0 +1,18 @@ +error: an inner attribute is not permitted in this context + --> $DIR/inner-attr.rs:6:16 + | +LL | reuse a as b { #![rustc_dummy] self } + | ^^^^^^^^^^^^^^^ +LL | +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - reuse a as b { #![rustc_dummy] self } +LL + reuse a as b { #[rustc_dummy] self } + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/list.rs b/tests/ui/delegation/list.rs new file mode 100644 index 00000000000..208b1481679 --- /dev/null +++ b/tests/ui/delegation/list.rs @@ -0,0 +1,46 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); +struct Z(u8); + +impl Trait for S { + reuse Trait::{foo, bar} { &self.0 } +} + +impl Trait for Z { + reuse ::{foo, bar} { &self.0 } +} + +trait Trait2 where Self: Trait { + reuse Trait::{foo, bar}; +} + +mod to_reuse { + pub fn a() {} + pub fn b() {} +} + +reuse to_reuse::{a, b}; + +fn main() { + let s = S(2); + s.foo(); + s.bar(); + + let z = Z(3); + z.foo(); + z.bar(); + + a(); + b(); +} diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs new file mode 100644 index 00000000000..16c74d396ef --- /dev/null +++ b/tests/ui/delegation/macro-inside-list.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); + +// Macro expansion works inside delegation items. +macro_rules! u8 { () => { u8 } } +macro_rules! self_0 { () => { &self.0 } } +impl Trait for S { + reuse ::{foo, bar} { self_0!() } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); +} diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs index f4b3da76c56..80b8724a5bf 100644 --- a/tests/ui/delegation/rename.rs +++ b/tests/ui/delegation/rename.rs @@ -5,16 +5,23 @@ mod to_reuse { pub fn a() {} + pub fn b() {} } -reuse to_reuse::a as b; +reuse to_reuse::a as x; +reuse to_reuse::{a as y, b as z}; struct S; impl S { - reuse to_reuse::a as b; + reuse to_reuse::a as x; + reuse to_reuse::{a as y, b as z}; } fn main() { - b(); - S::b(); + x(); + y(); + z(); + S::x(); + S::y(); + S::z(); }