Skip to content

Commit 8e863eb

Browse files
committed
Auto merge of rust-lang#82448 - Aaron1011:merge-hastokens-hasattrs, r=petrochenkov
Combine HasAttrs and HasTokens into AstLike When token-based attribute handling is implemeneted in rust-lang#80689, we will need to access tokens from `HasAttrs` (to perform cfg-stripping), and we will to access attributes from `HasTokens` (to construct a `PreexpTokenStream`). This PR merges the `HasAttrs` and `HasTokens` traits into a new `AstLike` trait. The previous `HasAttrs` impls from `Vec<Attribute>` and `AttrVec` are removed - they aren't attribute targets, so the impls never really made sense.
2 parents 0846043 + fb5fec0 commit 8e863eb

File tree

13 files changed

+264
-206
lines changed

13 files changed

+264
-206
lines changed

compiler/rustc_ast/src/ast.rs

-81
Original file line numberDiff line numberDiff line change
@@ -2912,84 +2912,3 @@ impl TryFrom<ItemKind> for ForeignItemKind {
29122912
}
29132913

29142914
pub type ForeignItem = Item<ForeignItemKind>;
2915-
2916-
pub trait HasTokens {
2917-
/// Called by `Parser::collect_tokens` to store the collected
2918-
/// tokens inside an AST node
2919-
fn finalize_tokens(&mut self, tokens: LazyTokenStream);
2920-
}
2921-
2922-
impl<T: HasTokens + 'static> HasTokens for P<T> {
2923-
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
2924-
(**self).finalize_tokens(tokens);
2925-
}
2926-
}
2927-
2928-
impl<T: HasTokens> HasTokens for Option<T> {
2929-
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
2930-
if let Some(inner) = self {
2931-
inner.finalize_tokens(tokens);
2932-
}
2933-
}
2934-
}
2935-
2936-
impl HasTokens for Attribute {
2937-
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
2938-
match &mut self.kind {
2939-
AttrKind::Normal(_, attr_tokens) => {
2940-
if attr_tokens.is_none() {
2941-
*attr_tokens = Some(tokens);
2942-
}
2943-
}
2944-
AttrKind::DocComment(..) => {
2945-
panic!("Called finalize_tokens on doc comment attr {:?}", self)
2946-
}
2947-
}
2948-
}
2949-
}
2950-
2951-
impl HasTokens for Stmt {
2952-
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
2953-
let stmt_tokens = match self.kind {
2954-
StmtKind::Local(ref mut local) => &mut local.tokens,
2955-
StmtKind::Item(ref mut item) => &mut item.tokens,
2956-
StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => &mut expr.tokens,
2957-
StmtKind::Empty => return,
2958-
StmtKind::MacCall(ref mut mac) => &mut mac.tokens,
2959-
};
2960-
if stmt_tokens.is_none() {
2961-
*stmt_tokens = Some(tokens);
2962-
}
2963-
}
2964-
}
2965-
2966-
macro_rules! derive_has_tokens {
2967-
($($ty:path),*) => { $(
2968-
impl HasTokens for $ty {
2969-
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
2970-
if self.tokens.is_none() {
2971-
self.tokens = Some(tokens);
2972-
}
2973-
}
2974-
}
2975-
)* }
2976-
}
2977-
2978-
derive_has_tokens! {
2979-
Item, Expr, Ty, AttrItem, Visibility, Path, Block, Pat
2980-
}
2981-
2982-
macro_rules! derive_has_attrs_no_tokens {
2983-
($($ty:path),*) => { $(
2984-
impl HasTokens for $ty {
2985-
fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {}
2986-
}
2987-
)* }
2988-
}
2989-
2990-
// These ast nodes only support inert attributes, so they don't
2991-
// store tokens (since nothing can observe them)
2992-
derive_has_attrs_no_tokens! {
2993-
StructField, Arm,
2994-
Field, FieldPat, Variant, Param, GenericParam
2995-
}

compiler/rustc_ast/src/ast_like.rs

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
use super::ptr::P;
2+
use super::tokenstream::LazyTokenStream;
3+
use super::{Arm, Field, FieldPat, GenericParam, Param, StructField, Variant};
4+
use super::{AssocItem, Expr, ForeignItem, Item, Local};
5+
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
6+
use super::{AttrVec, Attribute, Stmt, StmtKind};
7+
8+
/// An `AstLike` represents an AST node (or some wrapper around
9+
/// and AST node) which stores some combination of attributes
10+
/// and tokens.
11+
pub trait AstLike: Sized {
12+
fn attrs(&self) -> &[Attribute];
13+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
14+
/// Called by `Parser::collect_tokens` to store the collected
15+
/// tokens inside an AST node
16+
fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {
17+
// This default impl makes this trait easier to implement
18+
// in tools like `rust-analyzer`
19+
panic!("`finalize_tokens` is not supported!")
20+
}
21+
}
22+
23+
impl<T: AstLike + 'static> AstLike for P<T> {
24+
fn attrs(&self) -> &[Attribute] {
25+
(**self).attrs()
26+
}
27+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
28+
(**self).visit_attrs(f);
29+
}
30+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
31+
(**self).finalize_tokens(tokens)
32+
}
33+
}
34+
35+
fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
36+
crate::mut_visit::visit_clobber(attrs, |attrs| {
37+
let mut vec = attrs.into();
38+
f(&mut vec);
39+
vec.into()
40+
});
41+
}
42+
43+
impl AstLike for StmtKind {
44+
fn attrs(&self) -> &[Attribute] {
45+
match *self {
46+
StmtKind::Local(ref local) => local.attrs(),
47+
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
48+
StmtKind::Item(ref item) => item.attrs(),
49+
StmtKind::Empty => &[],
50+
StmtKind::MacCall(ref mac) => &*mac.attrs,
51+
}
52+
}
53+
54+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
55+
match self {
56+
StmtKind::Local(local) => local.visit_attrs(f),
57+
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
58+
StmtKind::Item(item) => item.visit_attrs(f),
59+
StmtKind::Empty => {}
60+
StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
61+
}
62+
}
63+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
64+
let stmt_tokens = match self {
65+
StmtKind::Local(ref mut local) => &mut local.tokens,
66+
StmtKind::Item(ref mut item) => &mut item.tokens,
67+
StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => &mut expr.tokens,
68+
StmtKind::Empty => return,
69+
StmtKind::MacCall(ref mut mac) => &mut mac.tokens,
70+
};
71+
if stmt_tokens.is_none() {
72+
*stmt_tokens = Some(tokens);
73+
}
74+
}
75+
}
76+
77+
impl AstLike for Stmt {
78+
fn attrs(&self) -> &[Attribute] {
79+
self.kind.attrs()
80+
}
81+
82+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
83+
self.kind.visit_attrs(f);
84+
}
85+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
86+
self.kind.finalize_tokens(tokens)
87+
}
88+
}
89+
90+
impl AstLike for Attribute {
91+
fn attrs(&self) -> &[Attribute] {
92+
&[]
93+
}
94+
fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
95+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
96+
match &mut self.kind {
97+
AttrKind::Normal(_, attr_tokens) => {
98+
if attr_tokens.is_none() {
99+
*attr_tokens = Some(tokens);
100+
}
101+
}
102+
AttrKind::DocComment(..) => {
103+
panic!("Called finalize_tokens on doc comment attr {:?}", self)
104+
}
105+
}
106+
}
107+
}
108+
109+
impl<T: AstLike> AstLike for Option<T> {
110+
fn attrs(&self) -> &[Attribute] {
111+
self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
112+
}
113+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
114+
if let Some(inner) = self.as_mut() {
115+
inner.visit_attrs(f);
116+
}
117+
}
118+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
119+
if let Some(inner) = self {
120+
inner.finalize_tokens(tokens);
121+
}
122+
}
123+
}
124+
125+
/// Helper trait for the macros below. Abstracts over
126+
/// the two types of attribute fields that AST nodes
127+
/// may have (`Vec<Attribute>` or `AttrVec`)
128+
trait VecOrAttrVec {
129+
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
130+
}
131+
132+
impl VecOrAttrVec for Vec<Attribute> {
133+
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
134+
f(self)
135+
}
136+
}
137+
138+
impl VecOrAttrVec for AttrVec {
139+
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
140+
visit_attrvec(self, f)
141+
}
142+
}
143+
144+
macro_rules! derive_has_tokens_and_attrs {
145+
($($ty:path),*) => { $(
146+
impl AstLike for $ty {
147+
fn attrs(&self) -> &[Attribute] {
148+
&self.attrs
149+
}
150+
151+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
152+
VecOrAttrVec::visit(&mut self.attrs, f)
153+
}
154+
155+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
156+
if self.tokens.is_none() {
157+
self.tokens = Some(tokens);
158+
}
159+
160+
}
161+
}
162+
)* }
163+
}
164+
165+
macro_rules! derive_has_attrs_no_tokens {
166+
($($ty:path),*) => { $(
167+
impl AstLike for $ty {
168+
fn attrs(&self) -> &[Attribute] {
169+
&self.attrs
170+
}
171+
172+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
173+
VecOrAttrVec::visit(&mut self.attrs, f)
174+
}
175+
176+
fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {}
177+
}
178+
)* }
179+
}
180+
181+
macro_rules! derive_has_tokens_no_attrs {
182+
($($ty:path),*) => { $(
183+
impl AstLike for $ty {
184+
fn attrs(&self) -> &[Attribute] {
185+
&[]
186+
}
187+
188+
fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {
189+
}
190+
191+
fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
192+
if self.tokens.is_none() {
193+
self.tokens = Some(tokens);
194+
}
195+
196+
}
197+
}
198+
)* }
199+
}
200+
201+
// These AST nodes support both inert and active
202+
// attributes, so they also have tokens.
203+
derive_has_tokens_and_attrs! {
204+
Item, Expr, Local, AssocItem, ForeignItem
205+
}
206+
207+
// These ast nodes only support inert attributes, so they don't
208+
// store tokens (since nothing can observe them)
209+
derive_has_attrs_no_tokens! {
210+
StructField, Arm,
211+
Field, FieldPat, Variant, Param, GenericParam
212+
}
213+
214+
// These AST nodes don't support attributes, but can
215+
// be captured by a `macro_rules!` matcher. Therefore,
216+
// they need to store tokens.
217+
derive_has_tokens_no_attrs! {
218+
Ty, Block, AttrItem, Pat, Path, Visibility
219+
}

0 commit comments

Comments
 (0)