1
Fork 0

Rollup merge of #124135 - petrochenkov:deleglob, r=fmease

delegation: Implement glob delegation

Support delegating to all trait methods in one go.
Overriding globs with explicit definitions is also supported.

The implementation is generally based on the design from https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2020869823, but unlike with list delegation in https://github.com/rust-lang/rust/pull/123413 we cannot expand glob delegation eagerly.
We have to enqueue it into the queue of unexpanded macros (most other macros are processed this way too), and then a glob delegation waits in that queue until its trait path is resolved, and enough code expands to generate the identifier list produced from the glob.

Glob delegation is only allowed in impls, and can only point to traits.
Supporting it in other places gives very little practical benefit, but significantly raises the implementation complexity.

Part of https://github.com/rust-lang/rust/issues/118212.
This commit is contained in:
许杰友 Jieyou Xu (Joe) 2024-06-19 01:51:36 +01:00 committed by GitHub
commit f8ce1cfbf5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 878 additions and 123 deletions

View file

@ -3161,13 +3161,16 @@ pub struct Delegation {
pub path: Path,
pub rename: Option<Ident>,
pub body: Option<P<Block>>,
/// The item was expanded from a glob delegation item.
pub from_glob: bool,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelegationMac {
pub qself: Option<P<QSelf>>,
pub prefix: Path,
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
// Some for list delegation, and None for glob delegation.
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
pub body: Option<P<Block>>,
}
@ -3294,7 +3297,7 @@ pub enum ItemKind {
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
/// A list delegation item (`reuse prefix::{a, b, c}`).
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
/// Treated similarly to a macro call and expanded early.
DelegationMac(Box<DelegationMac>),
}
@ -3375,7 +3378,7 @@ pub enum AssocItemKind {
MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
/// An associated delegation item list.
/// An associated list or glob delegation item.
DelegationMac(Box<DelegationMac>),
}

View file

@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
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(suffixes) = suffixes {
for (ident, rename) in suffixes {
vis.visit_ident(ident);
if let Some(rename) = rename {
vis.visit_ident(rename);
}
}
}
if let Some(body) = body {
@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
visitor.visit_id(id);
visitor.visit_qself(qself);
visitor.visit_path(path);
@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
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(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(ident);
if let Some(rename) = rename {
visitor.visit_ident(rename);
}
}
}
if let Some(body) = body {

View file

@ -408,7 +408,14 @@ impl WalkItemKind for ItemKind {
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
@ -421,10 +428,12 @@ impl WalkItemKind for ItemKind {
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);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);
@ -837,7 +846,14 @@ impl WalkItemKind for AssocItemKind {
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
@ -850,10 +866,12 @@ impl WalkItemKind for AssocItemKind {
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);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);