Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3878,12 +3878,17 @@ pub struct Delegation {
pub from_glob: bool,
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub enum DelegationSuffixes {
List(ThinVec<(Ident, Option<Ident>)>),
Glob(Span),
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct DelegationMac {
pub qself: Option<Box<QSelf>>,
pub prefix: Path,
// Some for list delegation, and None for glob delegation.
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
pub suffixes: DelegationSuffixes,
pub body: Option<Box<Block>>,
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ macro_rules! common_visitor_and_walkers {
Defaultness,
Delegation,
DelegationMac,
DelegationSuffixes,
DelimArgs,
DelimSpan,
EnumDef,
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,10 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.prefix,
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
match &deleg.suffixes {
ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
},
&deleg.body,
),
}
Expand Down Expand Up @@ -641,7 +644,10 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.prefix,
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
match &deleg.suffixes {
ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
},
&deleg.body,
),
}
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,26 +1018,32 @@ impl SyntaxExtension {
pub fn glob_delegation(
trait_def_id: DefId,
impl_def_id: LocalDefId,
star_span: Span,
edition: Edition,
) -> SyntaxExtension {
struct GlobDelegationExpanderImpl {
trait_def_id: DefId,
impl_def_id: LocalDefId,
star_span: Span,
}
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) {
match ecx.resolver.glob_delegation_suffixes(
self.trait_def_id,
self.impl_def_id,
self.star_span,
) {
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 };
let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id, star_span };
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Arc::new(expander)), edition)
}

Expand Down Expand Up @@ -1169,6 +1175,7 @@ pub trait ResolverExpand {
&self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
star_span: Span,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;

/// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
use rustc_ast::{
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec,
DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline,
ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind,
TyKind, token,
DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs,
HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId,
PatKind, StmtKind, TyKind, token,
};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::{
Expand Down Expand Up @@ -2294,7 +2294,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
res
}
None if let Some((deleg, item)) = node.delegation() => {
let Some(suffixes) = &deleg.suffixes else {
let DelegationSuffixes::List(suffixes) = &deleg.suffixes else {
let traitless_qself =
matches!(&deleg.qself, Some(qself) if qself.position == 0);
let (item, of_trait) = match node.to_annotatable() {
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ impl<'a> Parser<'a> {
kind: AssocItemKind::DelegationMac(Box::new(DelegationMac {
qself: None,
prefix: of_trait.trait_ref.path.clone(),
suffixes: None,
suffixes: DelegationSuffixes::Glob(whole_reuse_span),
body,
})),
}));
Expand All @@ -855,10 +855,12 @@ impl<'a> Parser<'a> {

Ok(if self.eat_path_sep() {
let suffixes = if self.eat(exp!(Star)) {
None
DelegationSuffixes::Glob(self.prev_token.span)
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0)
DelegationSuffixes::List(
self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0,
)
};

ItemKind::DelegationMac(Box::new(DelegationMac {
Expand Down Expand Up @@ -1492,7 +1494,10 @@ impl<'a> Parser<'a> {
let span = self.psess.source_map().guess_head_span(span);
let descr = kind.descr();
let help = match kind {
ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => false,
ItemKind::DelegationMac(box DelegationMac {
suffixes: DelegationSuffixes::Glob(_),
..
}) => false,
_ => true,
};
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });
Expand Down
26 changes: 21 additions & 5 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2989,7 +2989,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
item.id,
LifetimeBinderKind::Function,
span,
|this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
|this| {
this.resolve_delegation(delegation, item.id, false, &item.attrs, item.span)
},
);
}

Expand Down Expand Up @@ -3335,7 +3337,15 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
item.id,
LifetimeBinderKind::Function,
delegation.path.segments.last().unwrap().ident.span,
|this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
|this| {
this.resolve_delegation(
delegation,
item.id,
false,
&item.attrs,
item.span,
)
},
);
}
AssocItemKind::Type(box TyAlias { generics, .. }) => self
Expand Down Expand Up @@ -3649,7 +3659,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

// Here we don't use `trait_id`, as we can process unresolved trait, however
// in this case we are still in a trait impl, https://github.com/rust-lang/rust/issues/150152
this.resolve_delegation(delegation, item.id, is_in_trait_impl, &item.attrs);
this.resolve_delegation(
delegation,
item.id,
is_in_trait_impl,
&item.attrs,
item.span,
);
},
);
}
Expand Down Expand Up @@ -3805,6 +3821,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
item_id: NodeId,
is_in_trait_impl: bool,
attrs: &[Attribute],
item_span: Span,
) {
self.smart_resolve_path(
delegation.id,
Expand All @@ -3829,8 +3846,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

let Some(body) = &delegation.body else { return };
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
let span = delegation.path.segments.last().unwrap().ident.span;
let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules());
let ident = Ident::new(kw::SelfLower, item_span.normalize_to_macro_rules());
let res = Res::Local(delegation.id);
this.innermost_rib_bindings(ValueNS).insert(ident, res);

Expand Down
23 changes: 15 additions & 8 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use std::mem;
use std::sync::Arc;

use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, NodeId};
use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
Expand Down Expand Up @@ -286,7 +286,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
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));
let DelegationSuffixes::Glob(star_span) = deleg.suffixes else { unreachable!() };
deleg_impl = Some((self.invocation_parent(invoc_id), star_span));
// It is sufficient to consider glob delegation a bang macro for now.
(&deleg.prefix, MacroKind::Bang)
}
Expand Down Expand Up @@ -530,6 +531,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
&self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
star_span: Span,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> {
let target_trait = self.expect_module(trait_def_id);
if !target_trait.unexpanded_invocations.borrow().is_empty() {
Expand All @@ -549,13 +551,13 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {

let mut idents = Vec::new();
target_trait.for_each_child(self, |this, ident, orig_ident_span, 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, ns))
{
// The name is overridden, do not produce it from the glob delegation.
} else {
idents.push((ident.orig(orig_ident_span), None));
// FIXME: Adjust hygiene for idents from globs, like for glob imports.
idents.push((ident.orig(star_span.with_ctxt(orig_ident_span.ctxt())), None));
}
});
Ok(idents)
Expand All @@ -579,7 +581,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
parent_scope: &ParentScope<'ra>,
node_id: NodeId,
force: bool,
deleg_impl: Option<LocalDefId>,
deleg_impl: Option<(LocalDefId, Span)>,
invoc_in_mod_inert_attr: Option<LocalDefId>,
suggestion_span: Option<Span>,
) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
Expand Down Expand Up @@ -755,7 +757,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
kind: MacroKind,
parent_scope: &ParentScope<'ra>,
force: bool,
deleg_impl: Option<LocalDefId>,
deleg_impl: Option<(LocalDefId, Span)>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
Expand Down Expand Up @@ -840,10 +842,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

let res = res?;
let ext = match deleg_impl {
Some(impl_def_id) => match res {
Some((impl_def_id, star_span)) => match res {
def::Res::Def(DefKind::Trait, def_id) => {
let edition = self.tcx.sess.edition();
Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition)))
Some(Arc::new(SyntaxExtension::glob_delegation(
def_id,
impl_def_id,
star_span,
edition,
)))
}
_ => None,
},
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/delegation/impl-reuse-negative-traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

trait Trait {
fn foo(&self);
//~^ ERROR negative impls cannot have any items [E0749]
}

struct S;
Expand All @@ -15,5 +14,6 @@ impl Trait for S {
struct F(S);

reuse impl !Trait for F { &self.0 }
//~^ ERROR negative impls cannot have any items

fn main() {}
6 changes: 3 additions & 3 deletions tests/ui/delegation/impl-reuse-negative-traits.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0749]: negative impls cannot have any items
--> $DIR/impl-reuse-negative-traits.rs:6:8
--> $DIR/impl-reuse-negative-traits.rs:16:1
|
LL | fn foo(&self);
| ^^^
LL | reuse impl !Trait for F { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

Expand Down
25 changes: 0 additions & 25 deletions tests/ui/delegation/impl-reuse-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,19 +173,6 @@ mod macros {
macro_rules! m { () => { M } }
reuse impl Trait for m!() { self_0_ref!(self) }

struct S1(u8);
macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
one_line_reuse!(self);

struct S2(u8);
macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
one_line_reuse_expr!(self.0);

struct S3(u8);
macro_rules! s3 { () => { S3 } }
macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
one_line_reuse_expr2!(self.0);

fn f() {
let s = S(1);
s.foo();
Expand All @@ -194,18 +181,6 @@ mod macros {
let m = M(41);
m.foo();
m.bar();

let s1 = S1(2);
s1.foo();
s1.bar();

let s2 = S2(4);
s2.foo();
s2.bar();

let s3 = S3(5);
s3.foo();
s3.bar();
}
}

Expand Down
39 changes: 39 additions & 0 deletions tests/ui/delegation/impl-reuse-self-hygiene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]

trait Trait {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}

// impl Trait for u8 {}
// struct S(u8);

// macro_rules! self_0_ref { ($self:ident) => { &$self.0 } }

// reuse impl Trait for S { self_0_ref!(self) }

// struct M(u8);
// macro_rules! m { () => { M } }
// reuse impl Trait for m!() { self_0_ref!(self) }

struct S1(u8);
macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
//~^ ERROR expected value, found module `self`
//~| ERROR expected value, found module `self`
one_line_reuse!(self);

struct S2(u8);
macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
one_line_reuse_expr!(self.0);
//~^ ERROR expected value, found module `self`
//~| ERROR expected value, found module `self`

struct S3(u8);
macro_rules! s3 { () => { S3 } }
macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
one_line_reuse_expr2!(self.0);
//~^ ERROR expected value, found module `self`
//~| ERROR expected value, found module `self`

fn main() {}
Loading
Loading