-
-
Notifications
You must be signed in to change notification settings - Fork 471
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(transformer/class-properties): fix
ScopeId
s in instance prop in…
…itializers (#7823) Code in instance property initializers moves from class body into constructor, or a `_super` function. Update parent `ScopeId`s for first level scopes in initializers.
- Loading branch information
1 parent
e70deb9
commit 25bb6da
Showing
5 changed files
with
86 additions
and
260 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
crates/oxc_transformer/src/es2022/class_properties/instance_prop_init.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
//! ES2022: Class Properties | ||
//! Transform of instance property initializers. | ||
use std::cell::Cell; | ||
|
||
use oxc_ast::{ast::*, visit::VisitMut}; | ||
use oxc_syntax::scope::{ScopeFlags, ScopeId}; | ||
use oxc_traverse::TraverseCtx; | ||
|
||
use super::ClassProperties; | ||
|
||
impl<'a, 'ctx> ClassProperties<'a, 'ctx> { | ||
/// Transform instance property initializer. | ||
/// | ||
/// Instance property initializers move from the class body into either class constructor, | ||
/// or a `_super` function. Change parent scope of first-level scopes in initializer to reflect this. | ||
pub(super) fn transform_instance_initializer( | ||
&mut self, | ||
value: &mut Expression<'a>, | ||
ctx: &mut TraverseCtx<'a>, | ||
) { | ||
let mut updater = InstanceInitializerVisitor::new(self, ctx); | ||
updater.visit_expression(value); | ||
} | ||
} | ||
|
||
/// Visitor to change parent scope of first-level scopes in instance property initializer. | ||
struct InstanceInitializerVisitor<'a, 'v> { | ||
/// Incremented when entering a scope, decremented when exiting it. | ||
/// Parent `ScopeId` should be updated when `scope_depth == 0`. | ||
scope_depth: u32, | ||
/// Parent scope | ||
parent_scope_id: ScopeId, | ||
/// `TraverseCtx` object. | ||
ctx: &'v mut TraverseCtx<'a>, | ||
} | ||
|
||
impl<'a, 'v> InstanceInitializerVisitor<'a, 'v> { | ||
fn new( | ||
class_properties: &'v mut ClassProperties<'a, '_>, | ||
ctx: &'v mut TraverseCtx<'a>, | ||
) -> Self { | ||
let parent_scope_id = class_properties.instance_inits_scope_id; | ||
Self { scope_depth: 0, parent_scope_id, ctx } | ||
} | ||
} | ||
|
||
impl<'a, 'v> VisitMut<'a> for InstanceInitializerVisitor<'a, 'v> { | ||
/// Update parent scope for first level of scopes. | ||
/// Convert scope to sloppy mode if `self.make_sloppy_mode == true`. | ||
fn enter_scope(&mut self, _flags: ScopeFlags, scope_id: &Cell<Option<ScopeId>>) { | ||
let scope_id = scope_id.get().unwrap(); | ||
|
||
// TODO: Not necessary to do this check for all scopes. | ||
// In JS, only `Function`, `ArrowFunctionExpression` or `Class` can be the first-level scope, | ||
// as all other types which have a scope are statements or `StaticBlock` which would need to be | ||
// inside a function or class. But some TS types with scopes could be first level via | ||
// e.g. `TaggedTemplateExpression::type_parameters`, which contains `TSType`. | ||
// Not sure if that matters though, as they'll be stripped out anyway by TS transform. | ||
if self.scope_depth == 0 { | ||
self.reparent_scope(scope_id); | ||
} | ||
self.scope_depth += 1; | ||
} | ||
|
||
fn leave_scope(&mut self) { | ||
self.scope_depth -= 1; | ||
} | ||
} | ||
|
||
impl<'a, 'v> InstanceInitializerVisitor<'a, 'v> { | ||
/// Update parent of scope to scope above class. | ||
fn reparent_scope(&mut self, scope_id: ScopeId) { | ||
self.ctx.scopes_mut().change_parent_id(scope_id, Some(self.parent_scope_id)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.