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);

View File

@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
use rustc_ast::ModKind;
use rustc_span::symbol::Ident;
enum DelegationKind<'a> {
Single,
List(&'a [(Ident, Option<Ident>)]),
Glob,
}
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
}
@ -387,7 +393,7 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
@ -395,7 +401,7 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
@ -579,7 +585,7 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
@ -587,20 +593,20 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
self.ann.post(self, AnnNode::SubItem(id))
}
pub(crate) fn print_delegation(
fn print_delegation(
&mut self,
attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
path: &ast::Path,
suffixes: Option<&[(Ident, Option<Ident>)]>,
kind: DelegationKind<'_>,
body: &Option<P<ast::Block>>,
) {
if body.is_some() {
@ -614,21 +620,28 @@ impl<'a> State<'a> {
} else {
self.print_path(path, false, 0);
}
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(",");
match kind {
DelegationKind::Single => {}
DelegationKind::List(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("}");
}
DelegationKind::Glob => {
self.word("::");
self.word("*");
}
self.word("}");
}
if let Some(body) = body {
self.nbsp();

View File

@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding
.label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_empty_delegation_mac =
empty {$kind} delegation is not supported
expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}`
@ -58,6 +58,9 @@ expand_feature_removed =
.label = feature has been removed
.reason = {$reason}
expand_glob_delegation_outside_impls =
glob delegation is only supported in impls
expand_helper_attribute_name_invalid =
`{$name}` cannot be a name of derive helper attribute

View File

@ -357,6 +357,10 @@ where
}
}
pub trait GlobDelegationExpander {
fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>;
}
// Use a macro because forwarding to a simple function has type system issues
macro_rules! make_stmts_default {
($me:expr) => {
@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
/// The produced AST fragment is appended to the input AST fragment.
Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),
/// A glob delegation.
GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
}
/// A struct representing a macro definition in "lowered" form ready for expansion.
@ -748,7 +755,9 @@ impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn macro_kind(&self) -> MacroKind {
match self.kind {
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Bang(..)
| SyntaxExtensionKind::LegacyBang(..)
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
@ -922,6 +931,32 @@ impl SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
}
pub fn glob_delegation(
trait_def_id: DefId,
impl_def_id: LocalDefId,
edition: Edition,
) -> SyntaxExtension {
struct GlobDelegationExpanderImpl {
trait_def_id: DefId,
impl_def_id: LocalDefId,
}
impl GlobDelegationExpander for GlobDelegationExpanderImpl {
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> {
match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
Ok(suffixes) => ExpandResult::Ready(suffixes),
Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
Err(Indeterminate) => ExpandResult::Retry(()),
}
}
}
let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition)
}
pub fn expn_data(
&self,
parent: LocalExpnId,
@ -1030,6 +1065,16 @@ pub trait ResolverExpand {
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &RegisteredTools;
/// Mark this invocation id as a glob delegation.
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId);
/// Names of specific methods to which glob delegation expands.
fn glob_delegation_suffixes(
&mut self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
}
pub trait LintStoreExpand {

View File

@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
}
#[derive(Diagnostic)]
#[diag(expand_empty_delegation_list)]
pub(crate) struct EmptyDelegationList {
#[diag(expand_empty_delegation_mac)]
pub(crate) struct EmptyDelegationMac {
#[primary_span]
pub span: Span,
pub kind: String,
}
#[derive(Diagnostic)]
#[diag(expand_glob_delegation_outside_impls)]
pub(crate) struct GlobDelegationOutsideImpls {
#[primary_span]
pub span: Span,
}

View File

@ -1,8 +1,8 @@
use crate::base::*;
use crate::config::StripUnconfigured;
use crate::errors::{
EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
EmptyDelegationMac, GlobDelegationOutsideImpls, 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};
@ -343,6 +343,9 @@ pub enum InvocationKind {
is_const: bool,
item: Annotatable,
},
GlobDelegation {
item: P<ast::AssocItem>,
},
}
impl InvocationKind {
@ -370,6 +373,7 @@ impl Invocation {
InvocationKind::Bang { span, .. } => *span,
InvocationKind::Attr { attr, .. } => attr.span,
InvocationKind::Derive { path, .. } => path.span,
InvocationKind::GlobDelegation { item } => item.span,
}
}
@ -378,6 +382,7 @@ impl Invocation {
InvocationKind::Bang { span, .. } => span,
InvocationKind::Attr { attr, .. } => &mut attr.span,
InvocationKind::Derive { path, .. } => &mut path.span,
InvocationKind::GlobDelegation { item } => &mut item.span,
}
}
}
@ -800,6 +805,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
_ => unreachable!(),
},
InvocationKind::GlobDelegation { item } => {
let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
let suffixes = match ext {
SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx)
{
ExpandResult::Ready(suffixes) => suffixes,
ExpandResult::Retry(()) => {
// Reassemble the original invocation for retrying.
return ExpandResult::Retry(Invocation {
kind: InvocationKind::GlobDelegation { item },
..invoc
});
}
},
SyntaxExtensionKind::LegacyBang(..) => {
let msg = "expanded a dummy glob delegation";
let guar = self.cx.dcx().span_delayed_bug(span, msg);
return ExpandResult::Ready(fragment_kind.dummy(span, guar));
}
_ => unreachable!(),
};
type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>;
let single_delegations = build_single_delegations::<Node>(
self.cx, deleg, &item, &suffixes, item.span, true,
);
fragment_kind.expect_from_annotatables(
single_delegations.map(|item| Annotatable::ImplItem(P(item))),
)
}
})
}
@ -1067,7 +1102,7 @@ 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>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
None
}
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
@ -1126,7 +1161,7 @@ impl InvocationCollectorNode for P<ast::Item> {
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
_ => None,
@ -1270,7 +1305,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
@ -1311,7 +1346,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
@ -1487,7 +1522,7 @@ 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>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
StmtKind::Item(item) => match &item.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
@ -1684,6 +1719,44 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
}
}
fn build_single_delegations<'a, Node: InvocationCollectorNode>(
ecx: &ExtCtxt<'_>,
deleg: &'a ast::DelegationMac,
item: &'a ast::Item<Node::ItemKind>,
suffixes: &'a [(Ident, Option<Ident>)],
item_span: Span,
from_glob: bool,
) -> impl Iterator<Item = ast::Item<Node::ItemKind>> + 'a {
if suffixes.is_empty() {
// Report an error for now, to avoid keeping stem for resolution and
// stability checks.
let kind = String::from(if from_glob { "glob" } else { "list" });
ecx.dcx().emit_err(EmptyDelegationMac { span: item.span, kind });
}
suffixes.iter().map(move |&(ident, rename)| {
let mut path = deleg.prefix.clone();
path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None });
ast::Item {
attrs: item.attrs.clone(),
id: ast::DUMMY_NODE_ID,
span: if from_glob { item_span } else { 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(),
from_glob,
})),
tokens: None,
}
})
}
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@ -1702,6 +1775,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
let expn_id = LocalExpnId::fresh_empty();
if matches!(kind, InvocationKind::GlobDelegation { .. }) {
// In resolver we need to know which invocation ids are delegations early,
// before their `ExpnData` is filled.
self.cx.resolver.register_glob_delegation(expn_id);
}
let vis = kind.placeholder_visibility();
self.invocations.push((
Invocation {
@ -1734,6 +1812,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.collect(kind, InvocationKind::Attr { attr, pos, item, derives })
}
fn collect_glob_delegation(
&mut self,
item: P<ast::AssocItem>,
kind: AstFragmentKind,
) -> AstFragment {
self.collect(kind, InvocationKind::GlobDelegation { item })
}
/// If `item` is an attribute invocation, remove the attribute and return it together with
/// its position and derives following it. We have to collect the derives in order to resolve
/// legacy derive helpers (helpers written before derives that introduce them).
@ -1901,37 +1987,27 @@ 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,
});
None if let Some((deleg, item)) = node.delegation() => {
let Some(suffixes) = &deleg.suffixes else {
let item = match node.to_annotatable() {
Annotatable::ImplItem(item) => item,
ann @ (Annotatable::Item(_)
| Annotatable::TraitItem(_)
| Annotatable::Stmt(_)) => {
let span = ann.span();
self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
return Default::default();
}
_ => unreachable!(),
};
return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>();
};
let single_delegations = build_single_delegations::<Node>(
self.cx, deleg, item, suffixes, item.span, false,
);
Node::flatten_outputs(single_delegations.map(|item| {
let mut item = Node::from_item(item);
assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
}))
}
@ -1983,7 +2059,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 if node.delegation().is_some() => unreachable!(),
None => {
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
}

View File

@ -2699,12 +2699,13 @@ pub(crate) struct SingleColonImportPath {
#[derive(Diagnostic)]
#[diag(parse_bad_item_kind)]
#[help]
pub(crate) struct BadItemKind {
#[primary_span]
pub span: Span,
pub descr: &'static str,
pub ctx: &'static str,
#[help]
pub help: Option<()>,
}
#[derive(Diagnostic)]

View File

@ -707,15 +707,25 @@ impl<'a> Parser<'a> {
};
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 suffixes = if self.eat(&token::BinOp(token::Star)) {
None
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
Some(self.parse_delim_comma_seq(Delimiter::Brace, parse_suffix)?.0)
};
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)? };
let deleg = Delegation {
id: DUMMY_NODE_ID,
qself,
path,
rename,
body: body(self)?,
from_glob: false,
};
(ident, ItemKind::Delegation(Box::new(deleg)))
};
@ -1237,7 +1247,11 @@ impl<'a> Parser<'a> {
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
let span = self.psess.source_map().guess_head_span(span);
let descr = kind.descr();
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx });
let help = match kind {
ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => None,
_ => Some(()),
};
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });
None
}

View File

@ -19,6 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
use rustc_expand::base::ResolverExpand;
use rustc_expand::expand::AstFragment;
use rustc_hir::def::{self, *};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@ -1358,6 +1359,14 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.visit_invoc_in_module(item.id);
}
AssocCtxt::Impl => {
let invoc_id = item.id.placeholder_to_expn_id();
if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) {
self.r
.impl_unexpanded_invocations
.entry(self.r.invocation_parent(invoc_id))
.or_default()
.insert(invoc_id);
}
self.visit_invoc(item.id);
}
}
@ -1379,18 +1388,21 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.r.feed_visibility(feed, vis);
}
let ns = match item.kind {
AssocItemKind::Const(..) | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => {
ValueNS
}
AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
};
if ctxt == AssocCtxt::Trait {
let ns = match item.kind {
AssocItemKind::Const(..)
| AssocItemKind::Delegation(..)
| AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
};
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion));
} else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) {
let impl_def_id = self.r.tcx.local_parent(local_def_id);
let key = BindingKey::new(item.ident.normalize_to_macros_2_0(), ns);
self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key);
}
visit::walk_assoc_item(self, item, ctxt);

View File

@ -144,8 +144,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(..) => return visit::walk_item(self, i),
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
ItemKind::DelegationMac(..) => unreachable!(),
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
return self.visit_macro_invoc(i.id);
}
};
let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
@ -294,8 +295,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
AssocItemKind::DelegationMac(..) => unreachable!(),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
return self.visit_macro_invoc(i.id);
}
};
let def = self.create_def(i.id, i.ident.name, def_kind, i.span);

View File

@ -1089,7 +1089,7 @@ pub struct Resolver<'a, 'tcx> {
single_segment_macro_resolutions:
Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
multi_segment_macro_resolutions:
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>,
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>, Namespace)>,
builtin_attrs: Vec<(Ident, ParentScope<'a>)>,
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
/// Derive macros cannot modify the item themselves and have to store the markers in the global
@ -1163,6 +1163,15 @@ pub struct Resolver<'a, 'tcx> {
doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
all_macro_rules: FxHashMap<Symbol, Res>,
/// Invocation ids of all glob delegations.
glob_delegation_invoc_ids: FxHashSet<LocalExpnId>,
/// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations.
/// Needed because glob delegations wait for all other neighboring macros to expand.
impl_unexpanded_invocations: FxHashMap<LocalDefId, FxHashSet<LocalExpnId>>,
/// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations.
/// Needed because glob delegations exclude explicitly defined names.
impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@ -1504,6 +1513,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
delegation_fn_sigs: Default::default(),
glob_delegation_invoc_ids: Default::default(),
impl_unexpanded_invocations: Default::default(),
impl_binding_keys: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);

View File

@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
@ -198,6 +198,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
if let Some(unexpanded_invocations) =
self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion))
{
unexpanded_invocations.remove(&expansion);
}
}
fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
@ -262,15 +267,21 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
}
};
let (path, kind, inner_attr, derives) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, .. } => (
&attr.get_normal_item().path,
MacroKind::Attr,
attr.style == ast::AttrStyle::Inner,
self.arenas.alloc_ast_paths(derives),
),
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None);
let (path, kind) = match invoc.kind {
InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => {
derives = self.arenas.alloc_ast_paths(attr_derives);
inner_attr = attr.style == ast::AttrStyle::Inner;
(&attr.get_normal_item().path, MacroKind::Attr)
}
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang),
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive),
InvocationKind::GlobDelegation { ref item } => {
let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
deleg_impl = Some(self.invocation_parent(invoc_id));
// It is sufficient to consider glob delegation a bang macro for now.
(&deleg.prefix, MacroKind::Bang)
}
};
// Derives are not included when `invocations` are collected, so we have to add them here.
@ -286,10 +297,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
node_id,
force,
soft_custom_inner_attributes_gate(path, invoc),
deleg_impl,
)?;
let span = invoc.span();
let def_id = res.opt_def_id();
let def_id = if deleg_impl.is_some() { None } else { res.opt_def_id() };
invoc_id.set_expn_data(
ext.expn_data(
parent_scope.expansion,
@ -452,6 +464,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
fn registered_tools(&self) -> &RegisteredTools {
self.registered_tools
}
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) {
self.glob_delegation_invoc_ids.insert(invoc_id);
}
fn glob_delegation_suffixes(
&mut self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> {
let target_trait = self.expect_module(trait_def_id);
if !target_trait.unexpanded_invocations.borrow().is_empty() {
return Err(Indeterminate);
}
// FIXME: Instead of waiting try generating all trait methods, and pruning
// the shadowed ones a bit later, e.g. when all macro expansion completes.
// Pros: expansion will be stuck less (but only in exotic cases), the implementation may be
// less hacky.
// Cons: More code is generated just to be deleted later, deleting already created `DefId`s
// may be nontrivial.
if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get(&impl_def_id)
&& !unexpanded_invocations.is_empty()
{
return Err(Indeterminate);
}
let mut idents = Vec::new();
target_trait.for_each_child(self, |this, ident, ns, _binding| {
// FIXME: Adjust hygiene for idents from globs, like for glob imports.
if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
&& overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns))
{
// The name is overridden, do not produce it from the glob delegation.
} else {
idents.push((ident, None));
}
});
Ok(idents)
}
}
impl<'a, 'tcx> Resolver<'a, 'tcx> {
@ -468,15 +519,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
node_id: NodeId,
force: bool,
soft_custom_inner_attributes_gate: bool,
deleg_impl: Option<LocalDefId>,
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
let (ext, res) = match self.resolve_macro_or_delegation_path(
path,
Some(kind),
parent_scope,
true,
force,
deleg_impl,
) {
Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res),
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
Err(Determinacy::Undetermined) => return Err(Indeterminate),
};
// Everything below is irrelevant to glob delegation, take a shortcut.
if deleg_impl.is_some() {
if !matches!(res, Res::Err | Res::Def(DefKind::Trait, _)) {
self.dcx().emit_err(MacroExpectedFound {
span: path.span,
expected: "trait",
article: "a",
found: res.descr(),
macro_path: &pprust::path_to_string(path),
remove_surrounding_derive: None,
add_as_non_derive: None,
});
return Ok((self.dummy_ext(kind), Res::Err));
}
return Ok((ext, res));
}
// Report errors for the resolved macro.
for segment in &path.segments {
if let Some(args) = &segment.args {
@ -605,12 +681,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None)
}
fn resolve_macro_or_delegation_path(
&mut self,
path: &ast::Path,
kind: Option<MacroKind>,
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
deleg_impl: Option<LocalDefId>,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
let path_span = path.span;
let mut path = Segment::from_path(path);
// Possibly apply the macro helper hack
if kind == Some(MacroKind::Bang)
if deleg_impl.is_none()
&& kind == Some(MacroKind::Bang)
&& path.len() == 1
&& path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
{
@ -618,13 +707,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path.insert(0, Segment::from_ident(root));
}
let res = if path.len() > 1 {
let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
let res = if deleg_impl.is_some() || path.len() > 1 {
let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
PathResult::NonModule(..)
| PathResult::Indeterminate
| PathResult::Failed { .. } => Err(Determinacy::Determined),
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
Ok(module.res().unwrap())
}
PathResult::Module(..) => unreachable!(),
};
@ -636,6 +729,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
kind,
*parent_scope,
res.ok(),
ns,
));
}
@ -670,7 +764,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
res
};
res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res))
let res = res?;
let ext = match deleg_impl {
Some(impl_def_id) => match res {
def::Res::Def(DefKind::Trait, def_id) => {
let edition = self.tcx.sess.edition();
Some(Lrc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition)))
}
_ => None,
},
None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()),
};
Ok((ext, res))
}
pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
@ -706,14 +811,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions);
for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions {
// FIXME: Path resolution will ICE if segment IDs present.
for seg in &mut path {
seg.id = None;
}
match self.resolve_path(
&path,
Some(MacroNS),
Some(ns),
&parent_scope,
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
None,
@ -721,6 +826,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
check_consistency(self, &path, path_span, kind, initial_res, res)
}
// This may be a trait for glob delegation expansions.
PathResult::Module(ModuleOrUniformRoot::Module(module)) => check_consistency(
self,
&path,
path_span,
kind,
initial_res,
module.res().unwrap(),
),
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
let mut suggestion = None;
let (span, label, module) =

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::* {
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,11 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {}
struct S;
impl S {
reuse Trait::*; //~ ERROR empty glob delegation is not supported
}
fn main() {}

View File

@ -0,0 +1,8 @@
error: empty glob delegation is not supported
--> $DIR/empty-glob.rs:8:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,12 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {}
struct S;
impl Trait for u8 {
reuse unresolved::*; //~ ERROR failed to resolve: use of undeclared crate or module `unresolved`
reuse S::*; //~ ERROR expected trait, found struct `S`
}
fn main() {}

View File

@ -0,0 +1,15 @@
error: expected trait, found struct `S`
--> $DIR/glob-bad-path.rs:9:11
|
LL | reuse S::*;
| ^ not a trait
error[E0433]: failed to resolve: use of undeclared crate or module `unresolved`
--> $DIR/glob-bad-path.rs:8:11
|
LL | reuse unresolved::*;
| ^^^^^^^^^^ use of undeclared crate or module `unresolved`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0433`.

View File

@ -0,0 +1,33 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait1 {
fn method(&self) -> u8;
}
trait Trait2 {
fn method(&self) -> u8;
}
trait Trait {
fn method(&self) -> u8;
}
impl Trait1 for u8 {
fn method(&self) -> u8 { 0 }
}
impl Trait1 for u16 {
fn method(&self) -> u8 { 1 }
}
impl Trait2 for u8 {
fn method(&self) -> u8 { 2 }
}
impl Trait for u8 {
reuse Trait1::*;
reuse Trait2::*; //~ ERROR duplicate definitions with name `method`
}
impl Trait for u16 {
reuse Trait1::*;
reuse Trait1::*; //~ ERROR duplicate definitions with name `method`
}
fn main() {}

View File

@ -0,0 +1,25 @@
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-glob-conflict.rs:26:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
...
LL | reuse Trait1::*;
| ---------------- previous definition here
LL | reuse Trait2::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-glob-conflict.rs:30:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
...
LL | reuse Trait1::*;
| ---------------- previous definition here
LL | reuse Trait1::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0201`.

View File

@ -0,0 +1,36 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
mod inner {
pub trait TraitFoo {
fn foo(&self) -> u8;
}
pub trait TraitBar {
fn bar(&self) -> u8;
}
impl TraitFoo for u8 {
fn foo(&self) -> u8 { 0 }
}
impl TraitBar for u8 {
fn bar(&self) -> u8 { 1 }
}
}
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
reuse inner::TraitFoo::*;
reuse inner::TraitBar::*;
}
fn main() {
let u = 0u8;
u.foo();
u.bar();
}

View File

@ -0,0 +1,38 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn method(&self);
const CONST: u8;
type Type;
#[allow(non_camel_case_types)]
type method;
}
impl Trait for u8 {
fn method(&self) {}
const CONST: u8 = 0;
type Type = u8;
type method = u8;
}
struct Good(u8);
impl Trait for Good {
reuse Trait::* { &self.0 }
// Explicit definitions for non-delegatable items.
const CONST: u8 = 0;
type Type = u8;
type method = u8;
}
struct Bad(u8);
impl Trait for Bad { //~ ERROR not all trait items implemented, missing: `CONST`, `Type`, `method`
reuse Trait::* { &self.0 }
//~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait`
//~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
//~| ERROR duplicate definitions with name `method`
//~| ERROR expected function, found associated constant `Trait::CONST`
//~| ERROR expected function, found associated type `Trait::Type`
}
fn main() {}

View File

@ -0,0 +1,62 @@
error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait`
--> $DIR/glob-non-fn.rs:30:5
|
LL | const CONST: u8;
| ---------------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
--> $DIR/glob-non-fn.rs:30:5
|
LL | type Type;
| ---------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-non-fn.rs:30:5
|
LL | fn method(&self);
| ----------------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| duplicate definition
| previous definition here
error[E0423]: expected function, found associated constant `Trait::CONST`
--> $DIR/glob-non-fn.rs:30:11
|
LL | reuse Trait::* { &self.0 }
| ^^^^^ not a function
error[E0423]: expected function, found associated type `Trait::Type`
--> $DIR/glob-non-fn.rs:30:11
|
LL | reuse Trait::* { &self.0 }
| ^^^^^
|
= note: can't use a type alias as a constructor
error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method`
--> $DIR/glob-non-fn.rs:29:1
|
LL | const CONST: u8;
| --------------- `CONST` from trait
LL | type Type;
| --------- `Type` from trait
LL | #[allow(non_camel_case_types)]
LL | type method;
| ----------- `method` from trait
...
LL | impl Trait for Bad {
| ^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0046, E0201, E0324, E0423.
For more information about an error, try `rustc --explain E0046`.

View File

@ -0,0 +1,20 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn method() {}
}
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
trait OtherTrait {
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
}
extern {
reuse Trait::*; //~ ERROR delegation is not supported in `extern` blocks
}
fn main() {
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
}

View File

@ -0,0 +1,26 @@
error: delegation is not supported in `extern` blocks
--> $DIR/glob-non-impl.rs:15:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:8:1
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:11:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:19:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -0,0 +1,37 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
struct S(u8);
struct Z(u8);
impl Trait for S {
reuse Trait::* { &self.0 }
fn bar(&self) -> u8 { 2 }
}
impl Trait for Z {
reuse Trait::* { &self.0 }
reuse Trait::bar { &self.0 }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
let z = Z(2);
z.foo();
z.bar();
}

View File

@ -0,0 +1,35 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
struct S(u8);
struct Z(u8);
impl Trait for S {
reuse Trait::* { &self.0 }
}
impl Trait for Z {
reuse <u8 as Trait>::* { &self.0 }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
let z = Z(3);
z.foo();
z.bar();
}

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:ident) => { &$self.0 } }
impl Trait for S {
reuse <u8!() as Trait>::* { self_0!(self) }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
}