mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
delegation: Implement glob delegation
This commit is contained in:
parent
7ac6c2fc68
commit
22d0b1ee18
@ -3158,13 +3158,16 @@ pub struct Delegation {
|
|||||||
pub path: Path,
|
pub path: Path,
|
||||||
pub rename: Option<Ident>,
|
pub rename: Option<Ident>,
|
||||||
pub body: Option<P<Block>>,
|
pub body: Option<P<Block>>,
|
||||||
|
/// The item was expanded from a glob delegation item.
|
||||||
|
pub from_glob: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct DelegationMac {
|
pub struct DelegationMac {
|
||||||
pub qself: Option<P<QSelf>>,
|
pub qself: Option<P<QSelf>>,
|
||||||
pub prefix: Path,
|
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>>,
|
pub body: Option<P<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3291,7 +3294,7 @@ pub enum ItemKind {
|
|||||||
///
|
///
|
||||||
/// 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}`).
|
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
|
||||||
/// Treated similarly to a macro call and expanded early.
|
/// Treated similarly to a macro call and expanded early.
|
||||||
DelegationMac(Box<DelegationMac>),
|
DelegationMac(Box<DelegationMac>),
|
||||||
}
|
}
|
||||||
@ -3372,7 +3375,7 @@ 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.
|
/// An associated list or glob delegation item.
|
||||||
DelegationMac(Box<DelegationMac>),
|
DelegationMac(Box<DelegationMac>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
|
|||||||
}
|
}
|
||||||
ItemKind::MacCall(m) => vis.visit_mac_call(m),
|
ItemKind::MacCall(m) => vis.visit_mac_call(m),
|
||||||
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
|
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_id(id);
|
||||||
vis.visit_qself(qself);
|
vis.visit_qself(qself);
|
||||||
vis.visit_path(path);
|
vis.visit_path(path);
|
||||||
@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
|
|||||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
vis.visit_qself(qself);
|
vis.visit_qself(qself);
|
||||||
vis.visit_path(prefix);
|
vis.visit_path(prefix);
|
||||||
for (ident, rename) in suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
vis.visit_ident(ident);
|
for (ident, rename) in suffixes {
|
||||||
if let Some(rename) = rename {
|
vis.visit_ident(ident);
|
||||||
vis.visit_ident(rename);
|
if let Some(rename) = rename {
|
||||||
|
vis.visit_ident(rename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
|
|||||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||||
}
|
}
|
||||||
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
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_id(id);
|
||||||
visitor.visit_qself(qself);
|
visitor.visit_qself(qself);
|
||||||
visitor.visit_path(path);
|
visitor.visit_path(path);
|
||||||
@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
|
|||||||
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
visitor.visit_qself(qself);
|
visitor.visit_qself(qself);
|
||||||
visitor.visit_path(prefix);
|
visitor.visit_path(prefix);
|
||||||
for (ident, rename) in suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
visitor.visit_ident(ident);
|
for (ident, rename) in suffixes {
|
||||||
if let Some(rename) = rename {
|
visitor.visit_ident(ident);
|
||||||
visitor.visit_ident(rename);
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(rename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
|
@ -398,7 +398,14 @@ impl WalkItemKind for ItemKind {
|
|||||||
}
|
}
|
||||||
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
|
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 {
|
if let Some(qself) = qself {
|
||||||
try_visit!(visitor.visit_ty(&qself.ty));
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
}
|
}
|
||||||
@ -411,10 +418,12 @@ impl WalkItemKind for ItemKind {
|
|||||||
try_visit!(visitor.visit_ty(&qself.ty));
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
}
|
}
|
||||||
try_visit!(visitor.visit_path(prefix, item.id));
|
try_visit!(visitor.visit_path(prefix, item.id));
|
||||||
for (ident, rename) in suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
visitor.visit_ident(*ident);
|
for (ident, rename) in suffixes {
|
||||||
if let Some(rename) = rename {
|
visitor.visit_ident(*ident);
|
||||||
visitor.visit_ident(*rename);
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(*rename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
@ -828,7 +837,14 @@ impl WalkItemKind for AssocItemKind {
|
|||||||
AssocItemKind::MacCall(mac) => {
|
AssocItemKind::MacCall(mac) => {
|
||||||
try_visit!(visitor.visit_mac_call(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 {
|
if let Some(qself) = qself {
|
||||||
try_visit!(visitor.visit_ty(&qself.ty));
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
}
|
}
|
||||||
@ -841,10 +857,12 @@ impl WalkItemKind for AssocItemKind {
|
|||||||
try_visit!(visitor.visit_ty(&qself.ty));
|
try_visit!(visitor.visit_ty(&qself.ty));
|
||||||
}
|
}
|
||||||
try_visit!(visitor.visit_path(prefix, item.id));
|
try_visit!(visitor.visit_path(prefix, item.id));
|
||||||
for (ident, rename) in suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
visitor.visit_ident(*ident);
|
for (ident, rename) in suffixes {
|
||||||
if let Some(rename) = rename {
|
visitor.visit_ident(*ident);
|
||||||
visitor.visit_ident(*rename);
|
if let Some(rename) = rename {
|
||||||
|
visitor.visit_ident(*rename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
|
@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
|
|||||||
use rustc_ast::ModKind;
|
use rustc_ast::ModKind;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
|
||||||
|
enum DelegationKind<'a> {
|
||||||
|
Single,
|
||||||
|
List(&'a [(Ident, Option<Ident>)]),
|
||||||
|
Glob,
|
||||||
|
}
|
||||||
|
|
||||||
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
|
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
|
||||||
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
|
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
|
||||||
}
|
}
|
||||||
@ -387,7 +393,7 @@ impl<'a> State<'a> {
|
|||||||
&item.vis,
|
&item.vis,
|
||||||
&deleg.qself,
|
&deleg.qself,
|
||||||
&deleg.path,
|
&deleg.path,
|
||||||
None,
|
DelegationKind::Single,
|
||||||
&deleg.body,
|
&deleg.body,
|
||||||
),
|
),
|
||||||
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
|
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||||
@ -395,7 +401,7 @@ impl<'a> State<'a> {
|
|||||||
&item.vis,
|
&item.vis,
|
||||||
&deleg.qself,
|
&deleg.qself,
|
||||||
&deleg.prefix,
|
&deleg.prefix,
|
||||||
Some(&deleg.suffixes),
|
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||||
&deleg.body,
|
&deleg.body,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -579,7 +585,7 @@ impl<'a> State<'a> {
|
|||||||
vis,
|
vis,
|
||||||
&deleg.qself,
|
&deleg.qself,
|
||||||
&deleg.path,
|
&deleg.path,
|
||||||
None,
|
DelegationKind::Single,
|
||||||
&deleg.body,
|
&deleg.body,
|
||||||
),
|
),
|
||||||
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
|
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||||
@ -587,20 +593,20 @@ impl<'a> State<'a> {
|
|||||||
vis,
|
vis,
|
||||||
&deleg.qself,
|
&deleg.qself,
|
||||||
&deleg.prefix,
|
&deleg.prefix,
|
||||||
Some(&deleg.suffixes),
|
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||||
&deleg.body,
|
&deleg.body,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
self.ann.post(self, AnnNode::SubItem(id))
|
self.ann.post(self, AnnNode::SubItem(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_delegation(
|
fn print_delegation(
|
||||||
&mut self,
|
&mut self,
|
||||||
attrs: &[ast::Attribute],
|
attrs: &[ast::Attribute],
|
||||||
vis: &ast::Visibility,
|
vis: &ast::Visibility,
|
||||||
qself: &Option<P<ast::QSelf>>,
|
qself: &Option<P<ast::QSelf>>,
|
||||||
path: &ast::Path,
|
path: &ast::Path,
|
||||||
suffixes: Option<&[(Ident, Option<Ident>)]>,
|
kind: DelegationKind<'_>,
|
||||||
body: &Option<P<ast::Block>>,
|
body: &Option<P<ast::Block>>,
|
||||||
) {
|
) {
|
||||||
if body.is_some() {
|
if body.is_some() {
|
||||||
@ -614,21 +620,28 @@ impl<'a> State<'a> {
|
|||||||
} else {
|
} else {
|
||||||
self.print_path(path, false, 0);
|
self.print_path(path, false, 0);
|
||||||
}
|
}
|
||||||
if let Some(suffixes) = suffixes {
|
match kind {
|
||||||
self.word("::");
|
DelegationKind::Single => {}
|
||||||
self.word("{");
|
DelegationKind::List(suffixes) => {
|
||||||
for (i, (ident, rename)) in suffixes.iter().enumerate() {
|
self.word("::");
|
||||||
self.print_ident(*ident);
|
self.word("{");
|
||||||
if let Some(rename) = rename {
|
for (i, (ident, rename)) in suffixes.iter().enumerate() {
|
||||||
self.nbsp();
|
self.print_ident(*ident);
|
||||||
self.word_nbsp("as");
|
if let Some(rename) = rename {
|
||||||
self.print_ident(*rename);
|
self.nbsp();
|
||||||
}
|
self.word_nbsp("as");
|
||||||
if i != suffixes.len() - 1 {
|
self.print_ident(*rename);
|
||||||
self.word_space(",");
|
}
|
||||||
|
if i != suffixes.len() - 1 {
|
||||||
|
self.word_space(",");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.word("}");
|
||||||
|
}
|
||||||
|
DelegationKind::Glob => {
|
||||||
|
self.word("::");
|
||||||
|
self.word("*");
|
||||||
}
|
}
|
||||||
self.word("}");
|
|
||||||
}
|
}
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
|
@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
|
|||||||
.label = duplicate binding
|
.label = duplicate binding
|
||||||
.label2 = previous binding
|
.label2 = previous binding
|
||||||
|
|
||||||
expand_empty_delegation_list =
|
expand_empty_delegation_mac =
|
||||||
empty list delegation is not supported
|
empty {$kind} delegation is not supported
|
||||||
|
|
||||||
expand_expected_paren_or_brace =
|
expand_expected_paren_or_brace =
|
||||||
expected `(` or `{"{"}`, found `{$token}`
|
expected `(` or `{"{"}`, found `{$token}`
|
||||||
@ -58,6 +58,9 @@ expand_feature_removed =
|
|||||||
.label = feature has been removed
|
.label = feature has been removed
|
||||||
.reason = {$reason}
|
.reason = {$reason}
|
||||||
|
|
||||||
|
expand_glob_delegation_outside_impls =
|
||||||
|
glob delegation is only supported in impls
|
||||||
|
|
||||||
expand_helper_attribute_name_invalid =
|
expand_helper_attribute_name_invalid =
|
||||||
`{$name}` cannot be a name of derive helper attribute
|
`{$name}` cannot be a name of derive helper attribute
|
||||||
|
|
||||||
|
@ -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
|
// Use a macro because forwarding to a simple function has type system issues
|
||||||
macro_rules! make_stmts_default {
|
macro_rules! make_stmts_default {
|
||||||
($me:expr) => {
|
($me:expr) => {
|
||||||
@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
|
|||||||
/// The produced AST fragment is appended to the input AST fragment.
|
/// The produced AST fragment is appended to the input AST fragment.
|
||||||
Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
|
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.
|
/// 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.
|
/// Returns which kind of macro calls this syntax extension.
|
||||||
pub fn macro_kind(&self) -> MacroKind {
|
pub fn macro_kind(&self) -> MacroKind {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
|
SyntaxExtensionKind::Bang(..)
|
||||||
|
| SyntaxExtensionKind::LegacyBang(..)
|
||||||
|
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
|
||||||
SyntaxExtensionKind::Attr(..)
|
SyntaxExtensionKind::Attr(..)
|
||||||
| SyntaxExtensionKind::LegacyAttr(..)
|
| SyntaxExtensionKind::LegacyAttr(..)
|
||||||
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
|
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
|
||||||
@ -922,6 +931,32 @@ impl SyntaxExtension {
|
|||||||
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
|
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(
|
pub fn expn_data(
|
||||||
&self,
|
&self,
|
||||||
parent: LocalExpnId,
|
parent: LocalExpnId,
|
||||||
@ -1030,6 +1065,16 @@ pub trait ResolverExpand {
|
|||||||
|
|
||||||
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
|
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
|
||||||
fn registered_tools(&self) -> &RegisteredTools;
|
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 {
|
pub trait LintStoreExpand {
|
||||||
|
@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(expand_empty_delegation_list)]
|
#[diag(expand_empty_delegation_mac)]
|
||||||
pub(crate) struct EmptyDelegationList {
|
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]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::base::*;
|
use crate::base::*;
|
||||||
use crate::config::StripUnconfigured;
|
use crate::config::StripUnconfigured;
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
|
EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached,
|
||||||
RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
|
RemoveExprNotSupported, 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};
|
||||||
@ -343,6 +343,9 @@ pub enum InvocationKind {
|
|||||||
is_const: bool,
|
is_const: bool,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
},
|
},
|
||||||
|
GlobDelegation {
|
||||||
|
item: P<ast::AssocItem>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvocationKind {
|
impl InvocationKind {
|
||||||
@ -370,6 +373,7 @@ impl Invocation {
|
|||||||
InvocationKind::Bang { span, .. } => *span,
|
InvocationKind::Bang { span, .. } => *span,
|
||||||
InvocationKind::Attr { attr, .. } => attr.span,
|
InvocationKind::Attr { attr, .. } => attr.span,
|
||||||
InvocationKind::Derive { path, .. } => path.span,
|
InvocationKind::Derive { path, .. } => path.span,
|
||||||
|
InvocationKind::GlobDelegation { item } => item.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,6 +382,7 @@ impl Invocation {
|
|||||||
InvocationKind::Bang { span, .. } => span,
|
InvocationKind::Bang { span, .. } => span,
|
||||||
InvocationKind::Attr { attr, .. } => &mut attr.span,
|
InvocationKind::Attr { attr, .. } => &mut attr.span,
|
||||||
InvocationKind::Derive { path, .. } => &mut path.span,
|
InvocationKind::Derive { path, .. } => &mut path.span,
|
||||||
|
InvocationKind::GlobDelegation { item } => &mut item.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,6 +805,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => 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) {
|
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
|
||||||
@ -1126,7 +1161,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||||||
_ => unreachable!(),
|
_ => 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 {
|
match &self.kind {
|
||||||
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
|
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -1270,7 +1305,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
|
|||||||
_ => unreachable!(),
|
_ => 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 {
|
match &self.wrapped.kind {
|
||||||
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -1311,7 +1346,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
|
|||||||
_ => unreachable!(),
|
_ => 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 {
|
match &self.wrapped.kind {
|
||||||
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -1487,7 +1522,7 @@ 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>)> {
|
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
StmtKind::Item(item) => match &item.kind {
|
StmtKind::Item(item) => match &item.kind {
|
||||||
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
|
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> {
|
struct InvocationCollector<'a, 'b> {
|
||||||
cx: &'a mut ExtCtxt<'b>,
|
cx: &'a mut ExtCtxt<'b>,
|
||||||
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
|
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 {
|
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
||||||
let expn_id = LocalExpnId::fresh_empty();
|
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();
|
let vis = kind.placeholder_visibility();
|
||||||
self.invocations.push((
|
self.invocations.push((
|
||||||
Invocation {
|
Invocation {
|
||||||
@ -1734,6 +1812,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
self.collect(kind, InvocationKind::Attr { attr, pos, item, derives })
|
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
|
/// 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
|
/// 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).
|
/// 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);
|
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
None if let Some((deleg, item)) = node.delegation_list() => {
|
None if let Some((deleg, item)) = node.delegation() => {
|
||||||
if deleg.suffixes.is_empty() {
|
let Some(suffixes) = &deleg.suffixes else {
|
||||||
// Report an error for now, to avoid keeping stem for resolution and
|
let item = match node.to_annotatable() {
|
||||||
// stability checks.
|
Annotatable::ImplItem(item) => item,
|
||||||
self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
|
ann @ (Annotatable::Item(_)
|
||||||
}
|
| Annotatable::TraitItem(_)
|
||||||
|
| Annotatable::Stmt(_)) => {
|
||||||
Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
|
let span = ann.span();
|
||||||
let mut path = deleg.prefix.clone();
|
self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
|
||||||
path.segments.push(ast::PathSegment {
|
return Default::default();
|
||||||
ident,
|
}
|
||||||
id: ast::DUMMY_NODE_ID,
|
_ => unreachable!(),
|
||||||
args: None,
|
};
|
||||||
});
|
return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>();
|
||||||
|
};
|
||||||
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,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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))
|
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>()
|
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 => {
|
None => {
|
||||||
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
|
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
|
||||||
}
|
}
|
||||||
|
@ -2699,12 +2699,13 @@ pub(crate) struct SingleColonImportPath {
|
|||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_bad_item_kind)]
|
#[diag(parse_bad_item_kind)]
|
||||||
#[help]
|
|
||||||
pub(crate) struct BadItemKind {
|
pub(crate) struct BadItemKind {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub descr: &'static str,
|
pub descr: &'static str,
|
||||||
pub ctx: &'static str,
|
pub ctx: &'static str,
|
||||||
|
#[help]
|
||||||
|
pub help: Option<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
@ -707,15 +707,25 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (ident, item_kind) = if self.eat(&token::PathSep) {
|
let (ident, item_kind) = if self.eat(&token::PathSep) {
|
||||||
let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
|
let suffixes = if self.eat(&token::BinOp(token::Star)) {
|
||||||
Ok((p.parse_path_segment_ident()?, rename(p)?))
|
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)? };
|
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
|
||||||
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
|
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
|
||||||
} else {
|
} else {
|
||||||
let rename = rename(self)?;
|
let rename = rename(self)?;
|
||||||
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
|
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)))
|
(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()`)
|
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
|
||||||
let span = self.psess.source_map().guess_head_span(span);
|
let span = self.psess.source_map().guess_head_span(span);
|
||||||
let descr = kind.descr();
|
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
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_expand::base::ResolverExpand;
|
||||||
use rustc_expand::expand::AstFragment;
|
use rustc_expand::expand::AstFragment;
|
||||||
use rustc_hir::def::{self, *};
|
use rustc_hir::def::{self, *};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
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);
|
self.visit_invoc_in_module(item.id);
|
||||||
}
|
}
|
||||||
AssocCtxt::Impl => {
|
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);
|
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);
|
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 {
|
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 parent = self.parent_scope.module;
|
||||||
let expansion = self.parent_scope.expansion;
|
let expansion = self.parent_scope.expansion;
|
||||||
self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, 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);
|
visit::walk_assoc_item(self, item, ctxt);
|
||||||
|
@ -144,8 +144,9 @@ 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(..) | ItemKind::DelegationMac(..) => {
|
||||||
ItemKind::DelegationMac(..) => unreachable!(),
|
return self.visit_macro_invoc(i.id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
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);
|
||||||
|
|
||||||
@ -294,8 +295,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||||||
AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
|
AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
|
||||||
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(..) | AssocItemKind::DelegationMac(..) => {
|
||||||
AssocItemKind::DelegationMac(..) => unreachable!(),
|
return self.visit_macro_invoc(i.id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
|
@ -3281,17 +3281,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||||||
}
|
}
|
||||||
self.visit_path(&delegation.path, delegation.id);
|
self.visit_path(&delegation.path, delegation.id);
|
||||||
if let Some(body) = &delegation.body {
|
if let Some(body) = &delegation.body {
|
||||||
// `PatBoundCtx` is not necessary in this context
|
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
|
||||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
// `PatBoundCtx` is not necessary in this context
|
||||||
|
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||||
|
|
||||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||||
self.fresh_binding(
|
this.fresh_binding(
|
||||||
Ident::new(kw::SelfLower, span),
|
Ident::new(kw::SelfLower, span),
|
||||||
delegation.id,
|
delegation.id,
|
||||||
PatternSource::FnParam,
|
PatternSource::FnParam,
|
||||||
&mut bindings,
|
&mut bindings,
|
||||||
);
|
);
|
||||||
self.visit_block(body);
|
this.visit_block(body);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1089,7 +1089,7 @@ pub struct Resolver<'a, 'tcx> {
|
|||||||
single_segment_macro_resolutions:
|
single_segment_macro_resolutions:
|
||||||
Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
|
Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
|
||||||
multi_segment_macro_resolutions:
|
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>)>,
|
builtin_attrs: Vec<(Ident, ParentScope<'a>)>,
|
||||||
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
|
/// `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
|
/// 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_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
|
||||||
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
|
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
|
||||||
all_macro_rules: FxHashMap<Symbol, Res>,
|
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.
|
/// 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(),
|
doc_link_traits_in_scope: Default::default(),
|
||||||
all_macro_rules: Default::default(),
|
all_macro_rules: Default::default(),
|
||||||
delegation_fn_sigs: 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);
|
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
||||||
|
@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
|
|||||||
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
|
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
|
||||||
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
|
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
|
||||||
use crate::Namespace::*;
|
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::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
||||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
||||||
use rustc_ast::expand::StrippedCfgItem;
|
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);
|
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
|
||||||
|
|
||||||
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
|
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) {
|
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 {
|
let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None);
|
||||||
InvocationKind::Attr { ref attr, ref derives, .. } => (
|
let (path, kind) = match invoc.kind {
|
||||||
&attr.get_normal_item().path,
|
InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => {
|
||||||
MacroKind::Attr,
|
derives = self.arenas.alloc_ast_paths(attr_derives);
|
||||||
attr.style == ast::AttrStyle::Inner,
|
inner_attr = attr.style == ast::AttrStyle::Inner;
|
||||||
self.arenas.alloc_ast_paths(derives),
|
(&attr.get_normal_item().path, MacroKind::Attr)
|
||||||
),
|
}
|
||||||
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
|
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang),
|
||||||
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
|
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.
|
// 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,
|
node_id,
|
||||||
force,
|
force,
|
||||||
soft_custom_inner_attributes_gate(path, invoc),
|
soft_custom_inner_attributes_gate(path, invoc),
|
||||||
|
deleg_impl,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let span = invoc.span();
|
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(
|
invoc_id.set_expn_data(
|
||||||
ext.expn_data(
|
ext.expn_data(
|
||||||
parent_scope.expansion,
|
parent_scope.expansion,
|
||||||
@ -452,6 +464,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
|
|||||||
fn registered_tools(&self) -> &RegisteredTools {
|
fn registered_tools(&self) -> &RegisteredTools {
|
||||||
self.registered_tools
|
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> {
|
impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
@ -468,15 +519,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
force: bool,
|
force: bool,
|
||||||
soft_custom_inner_attributes_gate: bool,
|
soft_custom_inner_attributes_gate: bool,
|
||||||
|
deleg_impl: Option<LocalDefId>,
|
||||||
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
|
) -> 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((Some(ext), res)) => (ext, res),
|
||||||
Ok((None, res)) => (self.dummy_ext(kind), res),
|
Ok((None, res)) => (self.dummy_ext(kind), res),
|
||||||
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
|
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
|
||||||
Err(Determinacy::Undetermined) => return Err(Indeterminate),
|
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.
|
// Report errors for the resolved macro.
|
||||||
for segment in &path.segments {
|
for segment in &path.segments {
|
||||||
if let Some(args) = &segment.args {
|
if let Some(args) = &segment.args {
|
||||||
@ -605,12 +681,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
parent_scope: &ParentScope<'a>,
|
parent_scope: &ParentScope<'a>,
|
||||||
trace: bool,
|
trace: bool,
|
||||||
force: 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> {
|
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
|
||||||
let path_span = path.span;
|
let path_span = path.span;
|
||||||
let mut path = Segment::from_path(path);
|
let mut path = Segment::from_path(path);
|
||||||
|
|
||||||
// Possibly apply the macro helper hack
|
// Possibly apply the macro helper hack
|
||||||
if kind == Some(MacroKind::Bang)
|
if deleg_impl.is_none()
|
||||||
|
&& kind == Some(MacroKind::Bang)
|
||||||
&& path.len() == 1
|
&& path.len() == 1
|
||||||
&& path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
|
&& 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));
|
path.insert(0, Segment::from_ident(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = if path.len() > 1 {
|
let res = if deleg_impl.is_some() || path.len() > 1 {
|
||||||
let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
|
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::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
|
||||||
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
||||||
PathResult::NonModule(..)
|
PathResult::NonModule(..)
|
||||||
| PathResult::Indeterminate
|
| PathResult::Indeterminate
|
||||||
| PathResult::Failed { .. } => Err(Determinacy::Determined),
|
| PathResult::Failed { .. } => Err(Determinacy::Determined),
|
||||||
|
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||||
|
Ok(module.res().unwrap())
|
||||||
|
}
|
||||||
PathResult::Module(..) => unreachable!(),
|
PathResult::Module(..) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -636,6 +729,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
kind,
|
kind,
|
||||||
*parent_scope,
|
*parent_scope,
|
||||||
res.ok(),
|
res.ok(),
|
||||||
|
ns,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,7 +764,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
res
|
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) {
|
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);
|
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.
|
// FIXME: Path resolution will ICE if segment IDs present.
|
||||||
for seg in &mut path {
|
for seg in &mut path {
|
||||||
seg.id = None;
|
seg.id = None;
|
||||||
}
|
}
|
||||||
match self.resolve_path(
|
match self.resolve_path(
|
||||||
&path,
|
&path,
|
||||||
Some(MacroNS),
|
Some(ns),
|
||||||
&parent_scope,
|
&parent_scope,
|
||||||
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
|
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
|
||||||
None,
|
None,
|
||||||
@ -721,6 +826,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
|
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
|
||||||
check_consistency(self, &path, path_span, kind, initial_res, 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 { .. }) => {
|
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
|
||||||
let mut suggestion = None;
|
let mut suggestion = None;
|
||||||
let (span, label, module) =
|
let (span, label, module) =
|
||||||
|
32
tests/ui/delegation/body-identity-glob.rs
Normal file
32
tests/ui/delegation/body-identity-glob.rs
Normal 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();
|
||||||
|
}
|
11
tests/ui/delegation/empty-glob.rs
Normal file
11
tests/ui/delegation/empty-glob.rs
Normal 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() {}
|
8
tests/ui/delegation/empty-glob.stderr
Normal file
8
tests/ui/delegation/empty-glob.stderr
Normal 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
|
||||||
|
|
12
tests/ui/delegation/glob-bad-path.rs
Normal file
12
tests/ui/delegation/glob-bad-path.rs
Normal 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() {}
|
15
tests/ui/delegation/glob-bad-path.stderr
Normal file
15
tests/ui/delegation/glob-bad-path.stderr
Normal 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`.
|
33
tests/ui/delegation/glob-glob-conflict.rs
Normal file
33
tests/ui/delegation/glob-glob-conflict.rs
Normal 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() {}
|
25
tests/ui/delegation/glob-glob-conflict.stderr
Normal file
25
tests/ui/delegation/glob-glob-conflict.stderr
Normal 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`.
|
36
tests/ui/delegation/glob-glob.rs
Normal file
36
tests/ui/delegation/glob-glob.rs
Normal 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();
|
||||||
|
}
|
38
tests/ui/delegation/glob-non-fn.rs
Normal file
38
tests/ui/delegation/glob-non-fn.rs
Normal 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() {}
|
62
tests/ui/delegation/glob-non-fn.stderr
Normal file
62
tests/ui/delegation/glob-non-fn.stderr
Normal 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`.
|
20
tests/ui/delegation/glob-non-impl.rs
Normal file
20
tests/ui/delegation/glob-non-impl.rs
Normal 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
|
||||||
|
}
|
26
tests/ui/delegation/glob-non-impl.stderr
Normal file
26
tests/ui/delegation/glob-non-impl.stderr
Normal 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
|
||||||
|
|
37
tests/ui/delegation/glob-override.rs
Normal file
37
tests/ui/delegation/glob-override.rs
Normal 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();
|
||||||
|
}
|
35
tests/ui/delegation/glob.rs
Normal file
35
tests/ui/delegation/glob.rs
Normal 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();
|
||||||
|
}
|
26
tests/ui/delegation/macro-inside-glob.rs
Normal file
26
tests/ui/delegation/macro-inside-glob.rs
Normal 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();
|
||||||
|
}
|
@ -14,9 +14,9 @@ struct S(u8);
|
|||||||
|
|
||||||
// Macro expansion works inside delegation items.
|
// Macro expansion works inside delegation items.
|
||||||
macro_rules! u8 { () => { u8 } }
|
macro_rules! u8 { () => { u8 } }
|
||||||
macro_rules! self_0 { () => { &self.0 } }
|
macro_rules! self_0 { ($self:ident) => { &$self.0 } }
|
||||||
impl Trait for S {
|
impl Trait for S {
|
||||||
reuse <u8!() as Trait>::{foo, bar} { self_0!() }
|
reuse <u8!() as Trait>::{foo, bar} { self_0!(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user