oxc_traverse/context/
mod.rs

1use oxc_allocator::{Allocator, Box as ArenaBox, Vec as ArenaVec};
2use oxc_ast::{
3    AstBuilder,
4    ast::{Expression, IdentifierReference, Statement},
5};
6use oxc_semantic::Scoping;
7use oxc_span::{Atom, Span};
8use oxc_syntax::{
9    reference::{ReferenceFlags, ReferenceId},
10    scope::{ScopeFlags, ScopeId},
11    symbol::{SymbolFlags, SymbolId},
12};
13
14use crate::{
15    ancestor::{Ancestor, AncestorType},
16    ast_operations::{GatherNodeParts, get_var_name_from_node},
17};
18
19mod ancestry;
20mod bound_identifier;
21mod maybe_bound_identifier;
22mod reusable;
23mod scoping;
24mod uid;
25use ancestry::PopToken;
26pub use ancestry::TraverseAncestry;
27pub use bound_identifier::BoundIdentifier;
28pub use maybe_bound_identifier::MaybeBoundIdentifier;
29pub use reusable::ReusableTraverseCtx;
30pub use scoping::TraverseScoping;
31
32/// Traverse context.
33///
34/// Passed to all AST visitor functions.
35///
36/// Provides ability to:
37/// * Query parent/ancestor of current node via [`parent`], [`ancestor`], [`ancestors`].
38/// * Get scopes tree and symbols table via [`scoping`] and [`scoping_mut`],
39///   [`ancestor_scopes`].
40/// * Create AST nodes via AST builder [`ast`].
41/// * Allocate into arena via [`alloc`].
42///
43/// # Namespaced APIs
44///
45/// All APIs are provided via 2 routes:
46///
47/// 1. Directly on `TraverseCtx`.
48/// 2. Via "namespaces".
49///
50/// | Direct                   | Namespaced                       |
51/// |--------------------------|----------------------------------|
52/// | `ctx.parent()`           | `ctx.ancestry.parent()`          |
53/// | `ctx.current_scope_id()` | `ctx.scoping.current_scope_id()` |
54/// | `ctx.alloc(thing)`       | `ctx.ast.alloc(thing)`           |
55///
56/// Purpose of the "namespaces" is to support if you want to mutate scope tree or symbol table
57/// while holding an `&Ancestor`, or AST nodes obtained from an `&Ancestor`.
58///
59/// For example, this will not compile because it attempts to borrow `ctx`
60/// immutably and mutably at same time:
61///
62/// ```nocompile
63/// use oxc_ast::ast::*;
64/// use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
65///
66/// struct MyTransform;
67/// impl<'a> Traverse<'a> for MyTransform {
68///     fn enter_unary_expression(&mut self, unary_expr: &mut UnaryExpression<'a>, ctx: &mut TraverseCtx<'a>) {
69///         // `right` is ultimately borrowed from `ctx`
70///         let right = match ctx.parent() {
71///             Ancestor::BinaryExpressionLeft(bin_expr) => bin_expr.right(),
72///             _ => return,
73///         };
74///
75///         // Won't compile! `ctx.scopes_mut()` attempts to mut borrow `ctx`
76///         // while it's already borrowed by `right`.
77///         let scope_tree_mut = ctx.scopes_mut();
78///
79///         // Use `right` later on
80///         dbg!(right);
81///     }
82/// }
83/// ```
84///
85/// You can fix this by using the "namespaced" methods instead.
86/// This works because you can borrow `ctx.ancestry` and `ctx.scoping` simultaneously:
87///
88/// ```
89/// use oxc_ast::ast::*;
90/// use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
91///
92/// struct MyTransform;
93/// impl<'a> Traverse<'a, ()> for MyTransform {
94///     fn enter_unary_expression(&mut self, unary_expr: &mut UnaryExpression<'a>, ctx: &mut TraverseCtx<'a, ()>) {
95///         let right = match ctx.ancestry.parent() {
96///             Ancestor::BinaryExpressionLeft(bin_expr) => bin_expr.right(),
97///             _ => return,
98///         };
99///
100///         let scoping_mut = ctx.scoping.scoping_mut();
101///
102///         dbg!(right);
103///     }
104/// }
105/// ```
106///
107/// [`parent`]: `TraverseCtx::parent`
108/// [`ancestor`]: `TraverseCtx::ancestor`
109/// [`ancestors`]: `TraverseCtx::ancestors`
110/// [`scoping`]: `TraverseCtx::scoping`
111/// [`scoping_mut`]: `TraverseCtx::scoping_mut`
112/// [`ancestor_scopes`]: `TraverseCtx::ancestor_scopes`
113/// [`ast`]: `TraverseCtx::ast`
114/// [`alloc`]: `TraverseCtx::alloc`
115pub struct TraverseCtx<'a, State> {
116    pub state: State,
117    pub ancestry: TraverseAncestry<'a>,
118    pub scoping: TraverseScoping<'a>,
119    pub ast: AstBuilder<'a>,
120}
121
122// Public methods
123impl<'a, State> TraverseCtx<'a, State> {
124    /// Allocate a node in the arena.
125    ///
126    /// Returns a [`Box<'a, T>`](ArenaBox).
127    ///
128    /// Shortcut for `ctx.ast.alloc`.
129    #[inline]
130    pub fn alloc<T>(&self, node: T) -> ArenaBox<'a, T> {
131        self.ast.alloc(node)
132    }
133
134    /// Get parent of current node.
135    ///
136    /// Shortcut for `ctx.ancestry.parent`.
137    #[inline]
138    pub fn parent<'t>(&'t self) -> Ancestor<'a, 't> {
139        self.ancestry.parent()
140    }
141
142    /// Get ancestor of current node.
143    ///
144    /// `level` is number of levels above parent.
145    /// `ancestor(0)` is equivalent to `parent()` (but better to use `parent()` as it's more efficient).
146    ///
147    /// If `level` is out of bounds (above `Program`), returns `Ancestor::None`.
148    ///
149    /// Shortcut for `ctx.ancestry.ancestor`.
150    #[inline]
151    pub fn ancestor<'t>(&'t self, level: usize) -> Ancestor<'a, 't> {
152        self.ancestry.ancestor(level)
153    }
154
155    /// Get iterator over ancestors, starting with parent and working up.
156    ///
157    /// Last `Ancestor` returned will be `Program`. `Ancestor::None` is not included in iteration.
158    ///
159    /// Shortcut for `ctx.ancestry.ancestors`.
160    #[inline]
161    pub fn ancestors<'t>(&'t self) -> impl Iterator<Item = Ancestor<'a, 't>> {
162        self.ancestry.ancestors()
163    }
164
165    /// Get depth in the AST.
166    ///
167    /// Count includes current node. i.e. in `Program`, depth is 1.
168    ///
169    /// Shortcut for `self.ancestry.ancestors_depth`.
170    #[inline]
171    pub fn ancestors_depth(&self) -> usize {
172        self.ancestry.ancestors_depth()
173    }
174
175    /// Get current scope ID.
176    ///
177    /// Shortcut for `ctx.scoping.current_scope_id`.
178    #[inline]
179    pub fn current_scope_id(&self) -> ScopeId {
180        self.scoping.current_scope_id()
181    }
182
183    /// Get current var hoisting scope ID.
184    ///
185    /// Shortcut for `ctx.scoping.current_hoist_scope_id`.
186    #[inline]
187    pub fn current_hoist_scope_id(&self) -> ScopeId {
188        self.scoping.current_hoist_scope_id()
189    }
190
191    /// Get current block scope ID.
192    ///
193    /// Shortcut for `ctx.scoping.current_block_scope_id`.
194    #[inline]
195    pub fn current_block_scope_id(&self) -> ScopeId {
196        self.scoping.current_block_scope_id()
197    }
198
199    /// Get current scope flags.
200    ///
201    /// Shortcut for `ctx.scoping.current_scope_flags`.
202    #[inline]
203    pub fn current_scope_flags(&self) -> ScopeFlags {
204        self.scoping.current_scope_flags()
205    }
206
207    /// Get scopes tree.
208    ///
209    /// Shortcut for `ctx.scoping.scopes`.
210    #[inline]
211    pub fn scoping(&self) -> &Scoping {
212        self.scoping.scoping()
213    }
214
215    /// Get mutable scopes tree.
216    ///
217    /// Shortcut for `ctx.scoping.scopes_mut`.
218    #[inline]
219    pub fn scoping_mut(&mut self) -> &mut Scoping {
220        self.scoping.scoping_mut()
221    }
222
223    /// Get iterator over scopes, starting with current scope and working up.
224    ///
225    /// This is a shortcut for `ctx.scoping.parent_scopes`.
226    #[inline]
227    pub fn ancestor_scopes(&self) -> impl Iterator<Item = ScopeId> + '_ {
228        self.scoping.ancestor_scopes()
229    }
230
231    /// Create new scope as child of provided scope.
232    ///
233    /// `flags` provided are amended to inherit from parent scope's flags.
234    ///
235    /// This is a shortcut for `ctx.scoping.create_child_scope`.
236    #[inline]
237    pub fn create_child_scope(&mut self, parent_id: ScopeId, flags: ScopeFlags) -> ScopeId {
238        self.scoping.create_child_scope(parent_id, flags)
239    }
240
241    /// Create new scope as child of current scope.
242    ///
243    /// `flags` provided are amended to inherit from parent scope's flags.
244    ///
245    /// This is a shortcut for `ctx.scoping.create_child_scope_of_current`.
246    #[inline]
247    pub fn create_child_scope_of_current(&mut self, flags: ScopeFlags) -> ScopeId {
248        self.scoping.create_child_scope_of_current(flags)
249    }
250
251    /// Insert a scope into scope tree below a statement.
252    ///
253    /// Statement must be in current scope.
254    /// New scope is created as child of current scope.
255    /// All child scopes of the statement are reassigned to be children of the new scope.
256    ///
257    /// `flags` provided are amended to inherit from parent scope's flags.
258    ///
259    /// This is a shortcut for `ctx.scoping.insert_scope_below_statement`.
260    #[inline]
261    pub fn insert_scope_below_statement(&mut self, stmt: &Statement, flags: ScopeFlags) -> ScopeId {
262        self.scoping.insert_scope_below_statement(stmt, flags)
263    }
264
265    /// Insert a scope into scope tree below a statement.
266    ///
267    /// Statement must be in provided scope.
268    /// New scope is created as child of the provided scope.
269    /// All child scopes of the statement are reassigned to be children of the new scope.
270    ///
271    /// `flags` provided are amended to inherit from parent scope's flags.
272    ///
273    /// This is a shortcut for `ctx.scoping.insert_scope_below_statement_from_scope_id`.
274    #[inline]
275    pub fn insert_scope_below_statement_from_scope_id(
276        &mut self,
277        stmt: &Statement,
278        scope_id: ScopeId,
279        flags: ScopeFlags,
280    ) -> ScopeId {
281        self.scoping.insert_scope_below_statement_from_scope_id(stmt, scope_id, flags)
282    }
283
284    /// Insert a scope into scope tree below an expression.
285    ///
286    /// Expression must be in current scope.
287    /// New scope is created as child of current scope.
288    /// All child scopes of the expression are reassigned to be children of the new scope.
289    ///
290    /// `flags` provided are amended to inherit from parent scope's flags.
291    ///
292    /// This is a shortcut for `ctx.scoping.insert_scope_below_expression`.
293    #[inline]
294    pub fn insert_scope_below_expression(
295        &mut self,
296        expr: &Expression,
297        flags: ScopeFlags,
298    ) -> ScopeId {
299        self.scoping.insert_scope_below_expression(expr, flags)
300    }
301
302    /// Insert a scope into scope tree below a `Vec` of statements.
303    ///
304    /// Statements must be in current scope.
305    /// New scope is created as child of current scope.
306    /// All child scopes of the statement are reassigned to be children of the new scope.
307    ///
308    /// `flags` provided are amended to inherit from parent scope's flags.
309    ///
310    /// This is a shortcut for `ctx.scoping.insert_scope_below_statements`.
311    pub fn insert_scope_below_statements(
312        &mut self,
313        stmts: &ArenaVec<Statement>,
314        flags: ScopeFlags,
315    ) -> ScopeId {
316        self.scoping.insert_scope_below_statements(stmts, flags)
317    }
318
319    /// Insert a scope between a parent and a child scope.
320    ///
321    /// For example, given the following scopes
322    /// ```ts
323    /// parentScope1: {
324    ///     childScope: { }
325    ///     childScope2: { }
326    /// }
327    /// ```
328    /// and calling this function with `parentScope1` and `childScope`,
329    /// the resulting scopes will be:
330    /// ```ts
331    /// parentScope1: {
332    ///     newScope: {
333    ///         childScope: { }
334    ///     }
335    ///     childScope2: { }
336    /// }
337    /// ```
338    /// This is a shortcut for `ctx.scoping.insert_scope_between`.
339    pub fn insert_scope_between(
340        &mut self,
341        parent_id: ScopeId,
342        child_id: ScopeId,
343        flags: ScopeFlags,
344    ) -> ScopeId {
345        self.scoping.insert_scope_between(parent_id, child_id, flags)
346    }
347
348    /// Remove scope for an expression from the scope chain.
349    ///
350    /// Delete the scope and set parent of its child scopes to its parent scope.
351    /// e.g.:
352    /// * Starting scopes parentage `A -> B`, `B -> C`, `B -> D`.
353    /// * Remove scope `B` from chain.
354    /// * End result: scopes `A -> C`, `A -> D`.
355    ///
356    /// Use this when removing an expression which owns a scope, without removing its children.
357    /// For example when unwrapping `(() => foo)()` to just `foo`.
358    /// `foo` here could be an expression which itself contains scopes.
359    ///
360    /// This is a shortcut for `ctx.scoping.remove_scope_for_expression`.
361    pub fn remove_scope_for_expression(&mut self, scope_id: ScopeId, expr: &Expression) {
362        self.scoping.remove_scope_for_expression(scope_id, expr);
363    }
364
365    /// Generate binding.
366    ///
367    /// Creates a symbol with the provided name and flags and adds it to the specified scope.
368    ///
369    /// This is a shortcut for `ctx.scoping.generate_binding`.
370    pub fn generate_binding(
371        &mut self,
372        name: Atom<'a>,
373        scope_id: ScopeId,
374        flags: SymbolFlags,
375    ) -> BoundIdentifier<'a> {
376        self.scoping.generate_binding(name, scope_id, flags)
377    }
378
379    /// Generate binding in current scope.
380    ///
381    /// Creates a symbol with the provided name and flags and adds it to the current scope.
382    ///
383    /// This is a shortcut for `ctx.scoping.generate_binding_in_current_scope`.
384    pub fn generate_binding_in_current_scope(
385        &mut self,
386        name: Atom<'a>,
387        flags: SymbolFlags,
388    ) -> BoundIdentifier<'a> {
389        self.scoping.generate_binding_in_current_scope(name, flags)
390    }
391
392    /// Generate UID var name.
393    ///
394    /// Finds a unique variable name which does clash with any other variables used in the program.
395    ///
396    /// See [`TraverseScoping::generate_uid_name`] for important information on how UIDs are generated.
397    /// There are some potential "gotchas".
398    ///
399    /// This is a shortcut for `ctx.scoping.generate_uid_name`.
400    pub fn generate_uid_name(&mut self, name: &str) -> Atom<'a> {
401        self.scoping.generate_uid_name(name, self.ast.allocator)
402    }
403
404    /// Generate UID.
405    ///
406    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
407    /// on how UIDs are generated. There are some potential "gotchas".
408    #[inline]
409    pub fn generate_uid(
410        &mut self,
411        name: &str,
412        scope_id: ScopeId,
413        flags: SymbolFlags,
414    ) -> BoundIdentifier<'a> {
415        // Get name for UID
416        let name = self.generate_uid_name(name);
417        let symbol_id = self.scoping.add_binding(&name, scope_id, flags);
418        BoundIdentifier::new(name, symbol_id)
419    }
420
421    /// Generate UID in current scope.
422    ///
423    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
424    /// on how UIDs are generated. There are some potential "gotchas".
425    #[inline]
426    pub fn generate_uid_in_current_scope(
427        &mut self,
428        name: &str,
429        flags: SymbolFlags,
430    ) -> BoundIdentifier<'a> {
431        self.generate_uid(name, self.current_scope_id(), flags)
432    }
433
434    /// Generate UID in root scope.
435    ///
436    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
437    /// on how UIDs are generated. There are some potential "gotchas".
438    #[inline]
439    pub fn generate_uid_in_root_scope(
440        &mut self,
441        name: &str,
442        flags: SymbolFlags,
443    ) -> BoundIdentifier<'a> {
444        self.generate_uid(name, self.scoping().root_scope_id(), flags)
445    }
446
447    /// Generate UID based on node.
448    ///
449    /// Recursively gathers the identifying names of a node, and joins them with `$`.
450    ///
451    /// Based on Babel's `scope.generateUidBasedOnNode` logic.
452    /// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
453    #[inline]
454    pub fn generate_uid_based_on_node<N: GatherNodeParts<'a>>(
455        &mut self,
456        node: &N,
457        scope_id: ScopeId,
458        flags: SymbolFlags,
459    ) -> BoundIdentifier<'a> {
460        let name = get_var_name_from_node(node);
461        self.generate_uid(&name, scope_id, flags)
462    }
463
464    /// Generate UID in current scope based on node.
465    ///
466    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
467    /// on how UIDs are generated. There are some potential "gotchas".
468    #[inline]
469    pub fn generate_uid_in_current_scope_based_on_node<N: GatherNodeParts<'a>>(
470        &mut self,
471        node: &N,
472        flags: SymbolFlags,
473    ) -> BoundIdentifier<'a> {
474        self.generate_uid_based_on_node(node, self.current_scope_id(), flags)
475    }
476
477    /// Generate UID in current hoist scope.
478    ///
479    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
480    /// on how UIDs are generated. There are some potential "gotchas".
481    #[inline]
482    pub fn generate_uid_in_current_hoist_scope(&mut self, name: &str) -> BoundIdentifier<'a> {
483        self.generate_uid(name, self.current_hoist_scope_id(), SymbolFlags::FunctionScopedVariable)
484    }
485
486    /// Generate UID in current hoist scope based on node.
487    ///
488    /// See also comments on [`TraverseScoping::generate_uid_name`] for important information
489    /// on how UIDs are generated. There are some potential "gotchas".
490    #[inline]
491    pub fn generate_uid_in_current_hoist_scope_based_on_node<N: GatherNodeParts<'a>>(
492        &mut self,
493        node: &N,
494    ) -> BoundIdentifier<'a> {
495        let name = get_var_name_from_node(node);
496        self.generate_uid_in_current_hoist_scope(&name)
497    }
498
499    /// Create a reference bound to a `SymbolId`.
500    ///
501    /// This is a shortcut for `ctx.scoping.create_bound_reference`.
502    #[inline]
503    pub fn create_bound_reference(
504        &mut self,
505        symbol_id: SymbolId,
506        flags: ReferenceFlags,
507    ) -> ReferenceId {
508        self.scoping.create_bound_reference(symbol_id, flags)
509    }
510
511    /// Create an `IdentifierReference` bound to a `SymbolId`.
512    pub fn create_bound_ident_reference(
513        &mut self,
514        span: Span,
515        name: Atom<'a>,
516        symbol_id: SymbolId,
517        flags: ReferenceFlags,
518    ) -> IdentifierReference<'a> {
519        let reference_id = self.create_bound_reference(symbol_id, flags);
520        self.ast.identifier_reference_with_reference_id(span, name, reference_id)
521    }
522
523    /// Create an `Expression::Identifier` bound to a `SymbolId`.
524    pub fn create_bound_ident_expr(
525        &mut self,
526        span: Span,
527        name: Atom<'a>,
528        symbol_id: SymbolId,
529        flags: ReferenceFlags,
530    ) -> Expression<'a> {
531        let ident = self.create_bound_ident_reference(span, name, symbol_id, flags);
532        Expression::Identifier(self.ast.alloc(ident))
533    }
534
535    /// Create an unbound reference.
536    ///
537    /// This is a shortcut for `ctx.scoping.create_unbound_reference`.
538    #[inline]
539    pub fn create_unbound_reference(&mut self, name: &str, flags: ReferenceFlags) -> ReferenceId {
540        self.scoping.create_unbound_reference(name, flags)
541    }
542
543    /// Create an unbound `IdentifierReference`.
544    pub fn create_unbound_ident_reference(
545        &mut self,
546        span: Span,
547        name: Atom<'a>,
548        flags: ReferenceFlags,
549    ) -> IdentifierReference<'a> {
550        let reference_id = self.create_unbound_reference(name.as_str(), flags);
551        self.ast.identifier_reference_with_reference_id(span, name, reference_id)
552    }
553
554    /// Create an unbound `Expression::Identifier`.
555    pub fn create_unbound_ident_expr(
556        &mut self,
557        span: Span,
558        name: Atom<'a>,
559        flags: ReferenceFlags,
560    ) -> Expression<'a> {
561        let ident = self.create_unbound_ident_reference(span, name, flags);
562        Expression::Identifier(self.ast.alloc(ident))
563    }
564
565    /// Create a reference optionally bound to a `SymbolId`.
566    ///
567    /// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_reference`
568    /// or `TraverseCtx::create_unbound_reference`.
569    ///
570    /// This is a shortcut for `ctx.scoping.create_reference`.
571    #[inline]
572    pub fn create_reference(
573        &mut self,
574        name: &str,
575        symbol_id: Option<SymbolId>,
576        flags: ReferenceFlags,
577    ) -> ReferenceId {
578        self.scoping.create_reference(name, symbol_id, flags)
579    }
580
581    /// Create an `IdentifierReference` optionally bound to a `SymbolId`.
582    ///
583    /// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_ident_reference`
584    /// or `TraverseCtx::create_unbound_ident_reference`.
585    pub fn create_ident_reference(
586        &mut self,
587        span: Span,
588        name: Atom<'a>,
589        symbol_id: Option<SymbolId>,
590        flags: ReferenceFlags,
591    ) -> IdentifierReference<'a> {
592        if let Some(symbol_id) = symbol_id {
593            self.create_bound_ident_reference(span, name, symbol_id, flags)
594        } else {
595            self.create_unbound_ident_reference(span, name, flags)
596        }
597    }
598
599    /// Create an `Expression::Identifier` optionally bound to a `SymbolId`.
600    ///
601    /// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_ident_expr`
602    /// or `TraverseCtx::create_unbound_ident_expr`.
603    pub fn create_ident_expr(
604        &mut self,
605        span: Span,
606        name: Atom<'a>,
607        symbol_id: Option<SymbolId>,
608        flags: ReferenceFlags,
609    ) -> Expression<'a> {
610        if let Some(symbol_id) = symbol_id {
611            self.create_bound_ident_expr(span, name, symbol_id, flags)
612        } else {
613            self.create_unbound_ident_expr(span, name, flags)
614        }
615    }
616
617    /// Create reference in current scope, looking up binding for `name`,
618    ///
619    /// This is a shortcut for `ctx.scoping.create_reference_in_current_scope`.
620    #[inline]
621    pub fn create_reference_in_current_scope(
622        &mut self,
623        name: &str,
624        flags: ReferenceFlags,
625    ) -> ReferenceId {
626        self.scoping.create_reference_in_current_scope(name, flags)
627    }
628
629    /// Delete a reference.
630    ///
631    /// Provided `name` must match `reference_id`.
632    ///
633    /// This is a shortcut for `ctx.scoping.delete_reference`.
634    pub fn delete_reference(&mut self, reference_id: ReferenceId, name: &str) {
635        self.scoping.delete_reference(reference_id, name);
636    }
637
638    /// Delete reference for an `IdentifierReference`.
639    ///
640    /// This is a shortcut for `ctx.scoping.delete_reference_for_identifier`.
641    pub fn delete_reference_for_identifier(&mut self, ident: &IdentifierReference) {
642        self.scoping.delete_reference_for_identifier(ident);
643    }
644}
645
646// Methods used internally within crate
647impl<'a, State> TraverseCtx<'a, State> {
648    /// Create new traversal context.
649    ///
650    /// # SAFETY
651    /// This function must not be public to maintain soundness of [`TraverseAncestry`].
652    pub(crate) fn new(state: State, scoping: Scoping, allocator: &'a Allocator) -> Self {
653        let ancestry = TraverseAncestry::new();
654        let scoping = TraverseScoping::new(scoping);
655        let ast = AstBuilder::new(allocator);
656        Self { state, ancestry, scoping, ast }
657    }
658
659    /// Shortcut for `self.ancestry.push_stack`, to make `walk_*` methods less verbose.
660    ///
661    /// # SAFETY
662    /// This method must not be public outside this crate, or consumer could break safety invariants.
663    #[inline]
664    pub(crate) fn push_stack(&mut self, ancestor: Ancestor<'a, 'static>) -> PopToken {
665        self.ancestry.push_stack(ancestor)
666    }
667
668    /// Shortcut for `self.ancestry.pop_stack`, to make `walk_*` methods less verbose.
669    ///
670    /// # SAFETY
671    /// See safety constraints of `TraverseAncestry.pop_stack`.
672    /// This method must not be public outside this crate, or consumer could break safety invariants.
673    #[inline]
674    pub(crate) unsafe fn pop_stack(&mut self, token: PopToken) {
675        self.ancestry.pop_stack(token);
676    }
677
678    /// Shortcut for `self.ancestry.retag_stack`, to make `walk_*` methods less verbose.
679    ///
680    /// # SAFETY
681    /// See safety constraints of `TraverseAncestry.retag_stack`.
682    /// This method must not be public outside this crate, or consumer could break safety invariants.
683    #[inline]
684    pub(crate) unsafe fn retag_stack(&mut self, ty: AncestorType) {
685        // SAFETY: Caller muct uphold safety constraints
686        unsafe { self.ancestry.retag_stack(ty) };
687    }
688
689    /// Shortcut for `ctx.scoping.set_current_scope_id`, to make `walk_*` methods less verbose.
690    #[inline]
691    pub(crate) fn set_current_scope_id(&mut self, scope_id: ScopeId) {
692        self.scoping.set_current_scope_id(scope_id);
693    }
694
695    /// Shortcut for `ctx.scoping.set_current_hoist_scope_id`, to make `walk_*` methods less verbose.
696    #[inline]
697    pub(crate) fn set_current_hoist_scope_id(&mut self, scope_id: ScopeId) {
698        self.scoping.set_current_hoist_scope_id(scope_id);
699    }
700
701    /// Shortcut for `ctx.scoping.set_current_block_scope_id`, to make `walk_*` methods less verbose.
702    #[inline]
703    pub(crate) fn set_current_block_scope_id(&mut self, scope_id: ScopeId) {
704        self.scoping.set_current_block_scope_id(scope_id);
705    }
706}