Auto merge of #123413 - petrochenkov:delegmulti2, r=fmease

delegation: Implement list delegation

```rust
reuse prefix::{a, b, c};
```

Using design described in https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2020869823 (the lists are desugared at macro expansion time).
List delegations are expanded eagerly when encountered, similarly to `#[cfg]`s, and not enqueued for later resolution/expansion like regular macros or glob delegation (https://github.com/rust-lang/rust/pull/124135).

Part of https://github.com/rust-lang/rust/issues/118212.
This commit is contained in:
bors 2024-05-15 10:35:31 +00:00
commit 3cb0030fe9
29 changed files with 511 additions and 60 deletions

View File

@ -2961,6 +2961,7 @@ impl Item {
| ItemKind::GlobalAsm(_) | ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_) | ItemKind::MacCall(_)
| ItemKind::Delegation(_) | ItemKind::Delegation(_)
| ItemKind::DelegationMac(_)
| ItemKind::MacroDef(_) => None, | ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None, ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics), ItemKind::Const(i) => Some(&i.generics),
@ -3123,8 +3124,16 @@ pub struct Delegation {
/// Path resolution id. /// Path resolution id.
pub id: NodeId, pub id: NodeId,
pub qself: Option<P<QSelf>>, pub qself: Option<P<QSelf>>,
pub rename: Option<Ident>,
pub path: Path, 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>>, pub body: Option<P<Block>>,
} }
@ -3243,10 +3252,13 @@ pub enum ItemKind {
/// A macro definition. /// A macro definition.
MacroDef(MacroDef), MacroDef(MacroDef),
/// A delegation item (`reuse`). /// A single delegation item (`reuse`).
/// ///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`. /// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>), 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 { impl ItemKind {
@ -3255,7 +3267,7 @@ impl ItemKind {
match self { match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) => "a", | Delegation(..) | DelegationMac(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an", ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
} }
} }
@ -3280,6 +3292,7 @@ impl ItemKind {
ItemKind::MacroDef(..) => "macro definition", ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation", ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function", ItemKind::Delegation(..) => "delegated function",
ItemKind::DelegationMac(..) => "delegation",
} }
} }
@ -3323,6 +3336,8 @@ pub enum AssocItemKind {
MacCall(P<MacCall>), MacCall(P<MacCall>),
/// An associated delegation item. /// An associated delegation item.
Delegation(Box<Delegation>), Delegation(Box<Delegation>),
/// An associated delegation item list.
DelegationMac(Box<DelegationMac>),
} }
impl AssocItemKind { impl AssocItemKind {
@ -3331,7 +3346,9 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. }) Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => 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 @@ impl From<AssocItemKind> for ItemKind {
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a), AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation), AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
} }
} }
} }
@ -3358,6 +3376,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a), ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
ItemKind::Delegation(d) => AssocItemKind::Delegation(d), ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
_ => return Err(item_kind), _ => return Err(item_kind),
}) })
} }

View File

@ -1170,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind {
vis.visit_block(body); 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 @@ impl NoopVisitItemKind for AssocItemKind {
visitor.visit_block(body); 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);
}
}
} }
} }
} }

View File

@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind {
visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body); 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() V::Result::output()
} }
@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind {
visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body); 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() V::Result::output()
} }

View File

@ -460,8 +460,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
delegation_results.body_id, delegation_results.body_id,
) )
} }
ItemKind::MacCall(..) => { ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
panic!("`TyMac` should have been expanded by now") panic!("macros should have been expanded by now")
} }
} }
} }
@ -845,7 +845,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
(delegation_results.generics, item_kind, true) (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 { let item = hir::TraitItem {
@ -869,7 +871,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span), 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) } }; let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef { hir::TraitItemRef {
@ -964,7 +968,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), 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 { let item = hir::ImplItem {
@ -993,7 +999,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span), 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 trait_item_def_id: self
.resolver .resolver

View File

@ -5,6 +5,7 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem; use ast::StaticItem;
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::ModKind; use rustc_ast::ModKind;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
@ -374,9 +375,22 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis) state.print_visibility(&item.vis)
}); });
} }
ast::ItemKind::Delegation(box delegation) => { ast::ItemKind::Delegation(deleg) => self.print_delegation(
self.print_delegation(delegation, &item.vis, &item.attrs) &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)) self.ann.post(self, AnnNode::Item(item))
} }
@ -553,31 +567,63 @@ impl<'a> State<'a> {
self.word(";"); self.word(";");
} }
} }
ast::AssocItemKind::Delegation(box delegation) => { ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
self.print_delegation(delegation, vis, &item.attrs) &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)) self.ann.post(self, AnnNode::SubItem(id))
} }
pub(crate) fn print_delegation( pub(crate) fn print_delegation(
&mut self, &mut self,
delegation: &ast::Delegation,
vis: &ast::Visibility,
attrs: &[ast::Attribute], 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.head("");
} }
self.print_visibility(vis); self.print_visibility(vis);
self.word_space("reuse"); self.word_nbsp("reuse");
if let Some(qself) = &delegation.qself { if let Some(qself) = qself {
self.print_qpath(&delegation.path, qself, false); self.print_qpath(path, qself, false);
} else { } 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.nbsp();
self.print_block_with_attrs(body, attrs); self.print_block_with_attrs(body, attrs);
} else { } else {

View File

@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding .label = duplicate binding
.label2 = previous binding .label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_expected_paren_or_brace = expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}` expected `(` or `{"{"}`, found `{$token}`

View File

@ -433,3 +433,10 @@ pub struct ExpectedParenOrBrace<'a> {
pub span: Span, pub span: Span,
pub token: Cow<'a, str>, pub token: Cow<'a, str>,
} }
#[derive(Diagnostic)]
#[diag(expand_empty_delegation_list)]
pub(crate) struct EmptyDelegationList {
#[primary_span]
pub span: Span,
}

View File

@ -1,8 +1,8 @@
use crate::base::*; use crate::base::*;
use crate::config::StripUnconfigured; use crate::config::StripUnconfigured;
use crate::errors::{ use crate::errors::{
IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
UnsupportedKeyValue, WrongFragmentKind, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
}; };
use crate::mbe::diagnostics::annotate_err_with_kind; use crate::mbe::diagnostics::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@ -1041,6 +1041,7 @@ enum AddSemicolon {
trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
type OutputTy = SmallVec<[Self; 1]>; type OutputTy = SmallVec<[Self; 1]>;
type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec; type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
type ItemKind = ItemKind;
const KIND: AstFragmentKind; const KIND: AstFragmentKind;
fn to_annotatable(self) -> Annotatable; fn to_annotatable(self) -> Annotatable;
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; 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) { fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
unreachable!() 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 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) { 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!(), _ => 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( fn wrap_flat_map_node_noop_flat_map(
mut node: Self, mut node: Self,
collector: &mut InvocationCollector<'_, '_>, collector: &mut InvocationCollector<'_, '_>,
@ -1214,6 +1242,7 @@ impl InvocationCollectorNode for P<ast::Item> {
struct TraitItemTag; struct TraitItemTag;
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> { impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
type ItemKind = AssocItemKind;
const KIND: AstFragmentKind = AstFragmentKind::TraitItems; const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
fn to_annotatable(self) -> Annotatable { fn to_annotatable(self) -> Annotatable {
Annotatable::TraitItem(self.wrapped) Annotatable::TraitItem(self.wrapped)
@ -1234,11 +1263,27 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
_ => unreachable!(), _ => 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; struct ImplItemTag;
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> { impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
type ItemKind = AssocItemKind;
const KIND: AstFragmentKind = AstFragmentKind::ImplItems; const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
fn to_annotatable(self) -> Annotatable { fn to_annotatable(self) -> Annotatable {
Annotatable::ImplItem(self.wrapped) Annotatable::ImplItem(self.wrapped)
@ -1259,6 +1304,21 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
_ => unreachable!(), _ => 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> { 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 }) (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) { 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 // If this is a macro invocation with a semicolon, then apply that
// semicolon to the final statement produced by expansion. // 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); Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
res 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 => { None => {
match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { 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)) 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>() self.collect_bang(mac, Node::KIND).make_ast::<Node>()
}) })
} }
None if node.delegation_list().is_some() => unreachable!(),
None => { None => {
assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
} }

View File

@ -685,20 +685,35 @@ impl<'a> Parser<'a> {
(None, self.parse_path(PathStyle::Expr)?) (None, self.parse_path(PathStyle::Expr)?)
}; };
let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; let rename = |this: &mut Self| {
Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
Some(self.parse_block()?)
} else {
self.expect(&token::Semi)?;
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); let span = span.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::fn_delegation, span); self.psess.gated_spans.gate(sym::fn_delegation, span);
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); Ok((ident, item_kind))
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
Ok((ident, ItemKind::Delegation(Box::new(deleg))))
} }
fn parse_item_list<T>( fn parse_item_list<T>(

View File

@ -95,12 +95,15 @@ impl<'a> Parser<'a> {
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); 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)?; self.expect(&token::PathSep)?;
} }
let qself = P(QSelf { ty, path_span, position: path.segments.len() }); 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(( Ok((
qself, qself,

View File

@ -522,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Impl, Impl,
MacCall, MacCall,
MacroDef, MacroDef,
Delegation Delegation,
DelegationMac
] ]
); );
ast_visit::walk_item(self, i) ast_visit::walk_item(self, i)
@ -650,7 +651,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!( record_variants!(
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind), (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); ast_visit::walk_assoc_item(self, i, ctxt);
} }

View File

@ -285,7 +285,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
ast::ItemKind::Impl(_) => Target::Impl, ast::ItemKind::Impl(_) => Target::Impl,
ast::ItemKind::MacroDef(_) => Target::MacroDef, 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( self.check_for_lang(
@ -340,7 +342,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
} }
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)), ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.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( self.check_for_lang(

View File

@ -825,7 +825,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
} }
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(), ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
unreachable!()
}
} }
} }
@ -1381,7 +1383,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
| AssocItemKind::Delegation(..) | AssocItemKind::Delegation(..)
| AssocItemKind::Fn(..) => ValueNS, | AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Type(..) => TypeNS, AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) => bug!(), // handled above AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
}; };
let parent = self.parent_scope.module; let parent = self.parent_scope.module;

View File

@ -139,6 +139,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(..) => return visit::walk_item(self, i), ItemKind::Use(..) => return visit::walk_item(self, i),
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), 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); let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
@ -278,6 +279,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
AssocItemKind::Const(..) => DefKind::AssocConst, AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy, AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), 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); let def = self.create_def(i.id, i.ident.name, def_kind, i.span);

View File

@ -236,7 +236,7 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
ast::ItemKind::Impl(..) => return, ast::ItemKind::Impl(..) => return,
// Should be unreachable at this stage // 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" "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
), ),

View File

@ -2561,7 +2561,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::ExternCrate(..) => {} ItemKind::ExternCrate(..) => {}
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"), ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!")
}
} }
} }
@ -2849,7 +2851,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
}), }),
AssocItemKind::MacCall(_) => { AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!") panic!("unexpanded macro in resolve!")
} }
}; };
@ -3116,7 +3118,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}, },
); );
} }
AssocItemKind::MacCall(_) => { AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!") panic!("unexpanded macro in resolve!")
} }
} }
@ -3218,7 +3220,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Fn(..) => (E0324, "method"), AssocItemKind::Fn(..) => (E0324, "method"),
AssocItemKind::Type(..) => (E0325, "type"), AssocItemKind::Type(..) => (E0325, "type"),
AssocItemKind::Delegation(..) => (E0324, "method"), 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); let trait_path = path_names_to_string(path);
self.report_error( self.report_error(
@ -4790,7 +4794,8 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
| ItemKind::ExternCrate(..) | ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..) | ItemKind::MacroDef(..)
| ItemKind::GlobalAsm(..) | ItemKind::GlobalAsm(..)
| ItemKind::MacCall(..) => {} | ItemKind::MacCall(..)
| ItemKind::DelegationMac(..) => {}
ItemKind::Delegation(..) => { ItemKind::Delegation(..) => {
// Delegated functions have lifetimes, their count is not necessarily zero. // 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, // But skipping the delegation items here doesn't mean that the count will be considered zero,

View File

@ -2045,7 +2045,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
AssocSuggestion::MethodWithSelf { called } AssocSuggestion::MethodWithSelf { called }
} }
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::MacCall(_) => continue, ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
continue;
}
}); });
} }
} }

View File

@ -739,8 +739,8 @@ impl<'a> FmtVisitor<'a> {
(_, Const(..)) => Ordering::Greater, (_, Const(..)) => Ordering::Greater,
(MacCall(..), _) => Ordering::Less, (MacCall(..), _) => Ordering::Less,
(_, MacCall(..)) => Ordering::Greater, (_, MacCall(..)) => Ordering::Greater,
(Delegation(..), _) => Ordering::Less, (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
(_, Delegation(..)) => Ordering::Greater, (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
}); });
let mut prev_kind = None; let mut prev_kind = None;
for (buf, item) in buffer { for (buf, item) in buffer {

View File

@ -586,7 +586,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
); );
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
ast::ItemKind::Delegation(..) => { ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
// TODO: rewrite delegation items once syntax is established. // TODO: rewrite delegation items once syntax is established.
// For now, leave the contents of the Span unformatted. // For now, leave the contents of the Span unformatted.
self.push_rewrite(item.span, None) self.push_rewrite(item.span, None)

View File

@ -36,4 +36,8 @@ impl Trait for S {
//~^ ERROR cannot find function `foo` in this scope //~^ 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() {} fn main() {}

View File

@ -63,7 +63,19 @@ LL | type Type;
LL | impl Trait for S { LL | impl Trait for S {
| ^^^^^^^^^^^^^^^^ missing `Type` in implementation | ^^^^^^^^^^^^^^^^ 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`. For more information about an error, try `rustc --explain E0046`.

View File

@ -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();
}

View File

@ -0,0 +1,8 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
mod m {}
reuse m::{}; //~ ERROR empty list delegation is not supported
fn main() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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 <u8 as Trait>::{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();
}

View File

@ -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 <u8!() as Trait>::{foo, bar} { self_0!() }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
}

View File

@ -5,16 +5,23 @@
mod to_reuse { mod to_reuse {
pub fn a() {} 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; struct S;
impl 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() { fn main() {
b(); x();
S::b(); y();
z();
S::x();
S::y();
S::z();
} }