]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast/src/ast_traits.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_ast / src / ast_traits.rs
CommitLineData
04454e1e
FG
1//! A set of traits implemented for various AST nodes,
2//! typically those used in AST fragments during macro expansion.
3//! The traits are not implemented exhaustively, only when actually necessary.
4
5use crate::ptr::P;
6use crate::token::Nonterminal;
7use crate::tokenstream::LazyTokenStream;
8use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
9use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
10use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
11use crate::{AttrVec, Attribute, Stmt, StmtKind};
12
13use rustc_span::Span;
14
15use std::fmt;
16use std::marker::PhantomData;
17
18/// A utility trait to reduce boilerplate.
19/// Standard `Deref(Mut)` cannot be reused due to coherence.
20pub trait AstDeref {
21 type Target;
22 fn ast_deref(&self) -> &Self::Target;
23 fn ast_deref_mut(&mut self) -> &mut Self::Target;
24}
25
26macro_rules! impl_not_ast_deref {
27 ($($T:ty),+ $(,)?) => {
28 $(
29 impl !AstDeref for $T {}
30 )+
31 };
32}
33
34impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt);
35
36impl<T> AstDeref for P<T> {
37 type Target = T;
38 fn ast_deref(&self) -> &Self::Target {
39 self
40 }
41 fn ast_deref_mut(&mut self) -> &mut Self::Target {
42 self
43 }
44}
45
46/// A trait for AST nodes having an ID.
47pub trait HasNodeId {
48 fn node_id(&self) -> NodeId;
49 fn node_id_mut(&mut self) -> &mut NodeId;
50}
51
52macro_rules! impl_has_node_id {
53 ($($T:ty),+ $(,)?) => {
54 $(
55 impl HasNodeId for $T {
56 fn node_id(&self) -> NodeId {
57 self.id
58 }
59 fn node_id_mut(&mut self) -> &mut NodeId {
60 &mut self.id
61 }
62 }
63 )+
64 };
65}
66
67impl_has_node_id!(
68 Arm,
69 AssocItem,
70 Crate,
71 Expr,
72 ExprField,
73 FieldDef,
74 ForeignItem,
75 GenericParam,
76 Item,
77 Param,
78 Pat,
79 PatField,
80 Stmt,
81 Ty,
82 Variant,
83);
84
85impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T {
86 fn node_id(&self) -> NodeId {
87 self.ast_deref().node_id()
88 }
89 fn node_id_mut(&mut self) -> &mut NodeId {
90 self.ast_deref_mut().node_id_mut()
91 }
92}
93
94/// A trait for AST nodes having a span.
95pub trait HasSpan {
96 fn span(&self) -> Span;
97}
98
99macro_rules! impl_has_span {
100 ($($T:ty),+ $(,)?) => {
101 $(
102 impl HasSpan for $T {
103 fn span(&self) -> Span {
104 self.span
105 }
106 }
107 )+
108 };
109}
110
111impl_has_span!(AssocItem, Expr, ForeignItem, Item, Stmt);
112
113impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
114 fn span(&self) -> Span {
115 self.ast_deref().span()
116 }
117}
118
119/// A trait for AST nodes having (or not having) collected tokens.
120pub trait HasTokens {
121 fn tokens(&self) -> Option<&LazyTokenStream>;
122 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
123}
124
125macro_rules! impl_has_tokens {
126 ($($T:ty),+ $(,)?) => {
127 $(
128 impl HasTokens for $T {
129 fn tokens(&self) -> Option<&LazyTokenStream> {
130 self.tokens.as_ref()
131 }
132 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
133 Some(&mut self.tokens)
134 }
135 }
136 )+
137 };
138}
139
140macro_rules! impl_has_tokens_none {
141 ($($T:ty),+ $(,)?) => {
142 $(
143 impl HasTokens for $T {
144 fn tokens(&self) -> Option<&LazyTokenStream> {
145 None
146 }
147 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
148 None
149 }
150 }
151 )+
152 };
153}
154
155impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility);
156impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
157
158impl<T: AstDeref<Target: HasTokens>> HasTokens for T {
159 fn tokens(&self) -> Option<&LazyTokenStream> {
160 self.ast_deref().tokens()
161 }
162 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
163 self.ast_deref_mut().tokens_mut()
164 }
165}
166
167impl<T: HasTokens> HasTokens for Option<T> {
168 fn tokens(&self) -> Option<&LazyTokenStream> {
169 self.as_ref().and_then(|inner| inner.tokens())
170 }
171 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
172 self.as_mut().and_then(|inner| inner.tokens_mut())
173 }
174}
175
176impl HasTokens for StmtKind {
177 fn tokens(&self) -> Option<&LazyTokenStream> {
178 match self {
179 StmtKind::Local(local) => local.tokens.as_ref(),
180 StmtKind::Item(item) => item.tokens(),
181 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
182 StmtKind::Empty => return None,
183 StmtKind::MacCall(mac) => mac.tokens.as_ref(),
184 }
185 }
186 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
187 match self {
188 StmtKind::Local(local) => Some(&mut local.tokens),
189 StmtKind::Item(item) => item.tokens_mut(),
190 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
191 StmtKind::Empty => return None,
192 StmtKind::MacCall(mac) => Some(&mut mac.tokens),
193 }
194 }
195}
196
197impl HasTokens for Stmt {
198 fn tokens(&self) -> Option<&LazyTokenStream> {
199 self.kind.tokens()
200 }
201 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
202 self.kind.tokens_mut()
203 }
204}
205
206impl HasTokens for Attribute {
207 fn tokens(&self) -> Option<&LazyTokenStream> {
208 match &self.kind {
209 AttrKind::Normal(_, tokens) => tokens.as_ref(),
210 kind @ AttrKind::DocComment(..) => {
211 panic!("Called tokens on doc comment attr {:?}", kind)
212 }
213 }
214 }
215 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
216 Some(match &mut self.kind {
217 AttrKind::Normal(_, tokens) => tokens,
218 kind @ AttrKind::DocComment(..) => {
219 panic!("Called tokens_mut on doc comment attr {:?}", kind)
220 }
221 })
222 }
223}
224
225impl HasTokens for Nonterminal {
226 fn tokens(&self) -> Option<&LazyTokenStream> {
227 match self {
228 Nonterminal::NtItem(item) => item.tokens(),
229 Nonterminal::NtStmt(stmt) => stmt.tokens(),
230 Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
231 Nonterminal::NtPat(pat) => pat.tokens(),
232 Nonterminal::NtTy(ty) => ty.tokens(),
233 Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
234 Nonterminal::NtPath(path) => path.tokens(),
235 Nonterminal::NtVis(vis) => vis.tokens(),
236 Nonterminal::NtBlock(block) => block.tokens(),
237 Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
238 }
239 }
240 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
241 match self {
242 Nonterminal::NtItem(item) => item.tokens_mut(),
243 Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
244 Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
245 Nonterminal::NtPat(pat) => pat.tokens_mut(),
246 Nonterminal::NtTy(ty) => ty.tokens_mut(),
247 Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
248 Nonterminal::NtPath(path) => path.tokens_mut(),
249 Nonterminal::NtVis(vis) => vis.tokens_mut(),
250 Nonterminal::NtBlock(block) => block.tokens_mut(),
251 Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
252 }
253 }
254}
255
256/// A trait for AST nodes having (or not having) attributes.
257pub trait HasAttrs {
258 /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
259 /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
260 /// considered 'custom' attributes.
261 ///
262 /// If this is `false`, then this `HasAttrs` definitely does
263 /// not support 'custom' inner attributes, which enables some optimizations
264 /// during token collection.
265 const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
266 fn attrs(&self) -> &[Attribute];
267 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
268}
269
270macro_rules! impl_has_attrs {
271 (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => {
272 $(
273 impl HasAttrs for $T {
274 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
275
276 fn attrs(&self) -> &[Attribute] {
277 &self.attrs
278 }
279
280 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
281 VecOrAttrVec::visit(&mut self.attrs, f)
282 }
283 }
284 )+
285 };
286}
287
288macro_rules! impl_has_attrs_none {
289 ($($T:ty),+ $(,)?) => {
290 $(
291 impl HasAttrs for $T {
292 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
293 fn attrs(&self) -> &[Attribute] {
294 &[]
295 }
296 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
297 }
298 )+
299 };
300}
301
302impl_has_attrs!(
303 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true,
304 AssocItem,
305 ForeignItem,
306 Item,
307);
308impl_has_attrs!(
309 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false,
310 Arm,
311 Crate,
312 Expr,
313 ExprField,
314 FieldDef,
315 GenericParam,
316 Param,
317 PatField,
318 Variant,
319);
320impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
321
322impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
323 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS;
324 fn attrs(&self) -> &[Attribute] {
325 self.ast_deref().attrs()
326 }
327 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
328 self.ast_deref_mut().visit_attrs(f)
329 }
330}
331
332impl<T: HasAttrs> HasAttrs for Option<T> {
333 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
334 fn attrs(&self) -> &[Attribute] {
335 self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
336 }
337 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
338 if let Some(inner) = self.as_mut() {
339 inner.visit_attrs(f);
340 }
341 }
342}
343
344impl HasAttrs for StmtKind {
345 // This might be a `StmtKind::Item`, which contains
346 // an item that supports inner attrs.
347 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
348
349 fn attrs(&self) -> &[Attribute] {
350 match self {
351 StmtKind::Local(local) => &local.attrs,
352 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
353 StmtKind::Item(item) => item.attrs(),
354 StmtKind::Empty => &[],
355 StmtKind::MacCall(mac) => &mac.attrs,
356 }
357 }
358
359 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
360 match self {
361 StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f),
362 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
363 StmtKind::Item(item) => item.visit_attrs(f),
364 StmtKind::Empty => {}
365 StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
366 }
367 }
368}
369
370impl HasAttrs for Stmt {
371 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
372 fn attrs(&self) -> &[Attribute] {
373 self.kind.attrs()
374 }
375 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
376 self.kind.visit_attrs(f);
377 }
378}
379
380/// Helper trait for the impls above. Abstracts over
381/// the two types of attribute fields that AST nodes
382/// may have (`Vec<Attribute>` or `AttrVec`).
383trait VecOrAttrVec {
384 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
385}
386
387impl VecOrAttrVec for Vec<Attribute> {
388 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
389 f(self)
390 }
391}
392
393impl VecOrAttrVec for AttrVec {
394 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
395 visit_attrvec(self, f)
396 }
397}
398
399fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
400 crate::mut_visit::visit_clobber(attrs, |attrs| {
401 let mut vec = attrs.into();
402 f(&mut vec);
403 vec.into()
404 });
405}
406
407/// A newtype around an AST node that implements the traits above if the node implements them.
408pub struct AstNodeWrapper<Wrapped, Tag> {
409 pub wrapped: Wrapped,
410 pub tag: PhantomData<Tag>,
411}
412
413impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
414 pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
415 AstNodeWrapper { wrapped, tag: Default::default() }
416 }
417}
418
419impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
420 type Target = Wrapped;
421 fn ast_deref(&self) -> &Self::Target {
422 &self.wrapped
423 }
424 fn ast_deref_mut(&mut self) -> &mut Self::Target {
425 &mut self.wrapped
426 }
427}
428
429impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 f.debug_struct("AstNodeWrapper")
432 .field("wrapped", &self.wrapped)
433 .field("tag", &self.tag)
434 .finish()
435 }
436}