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}