feat(ast)!: remove duplicated VariableDeclarator::kind (#25319)

## Summary

- Removes `VariableDeclarator::kind`.
- Makes `VariableDeclaration::kind` the single source of truth for every declarator in its declaration list.
- Makes contradictory parent and child declaration kinds unrepresentable.

## Breaking Change

The Rust AST changes from:

```rust
pub struct VariableDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub kind: VariableDeclarationKind,
    pub declarations: Vec<'a, VariableDeclarator<'a>>,
    #[ts]
    pub declare: bool,
}

pub struct VariableDeclarator<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    #[estree(skip)]
    pub kind: VariableDeclarationKind,
    #[estree(via = VariableDeclaratorId)]
    pub id: BindingPattern<'a>,
    #[ts]
    #[estree(skip)]
    pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
    pub init: Option<Expression<'a>>,
    #[ts]
    pub definite: bool,
}
```

to:

```rust
pub struct VariableDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub kind: VariableDeclarationKind,
    pub declarations: Vec<'a, VariableDeclarator<'a>>,
    #[ts]
    pub declare: bool,
}

pub struct VariableDeclarator<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    #[estree(via = VariableDeclaratorId)]
    pub id: BindingPattern<'a>,
    #[ts]
    #[estree(skip)]
    pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
    pub init: Option<Expression<'a>>,
    #[ts]
    pub definite: bool,
}
```

## Why?

A variable declaration has one declaration kind shared by every declarator in its declaration list:

```js
const first = 1, second = 2;
```

Previously, the AST stored that kind on both the parent declaration and every child declarator:

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { kind: Const, ... },
        VariableDeclarator { kind: Const, ... },
    ],
}
```

This allowed contradictory ASTs to be constructed:

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { kind: Var, ... },
    ],
}
```

Different consumers read different copies:

- Code generation used `VariableDeclaration::kind`.
- Semantic binding used `VariableDeclarator::kind`.
- Lint rules, transforms, and minifier passes used a mixture of both.

As a result, one AST could be emitted as `const` while its binding was treated as function-scoped `var`.

Transforms also had to keep the copies synchronized manually. For example, const-to-let normalization updated the parent and then looped through every declarator to update each child. Explicit resource management performed similar paired mutations for `using` declarations.

Keeping the kind only on `VariableDeclaration` removes this synchronization requirement and prevents consumers from observing conflicting declaration semantics.

## Declaration forms

The declaration kind now belongs exclusively to the node that owns the declaration list:

```js
let value;
```

```text
VariableDeclaration {
    kind: Let,
    declarations: [
        VariableDeclarator { id: value, ... },
    ],
}
```

Multiple declarators share the same parent kind:

```js
const first = 1, second = 2;
```

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { id: first, ... },
        VariableDeclarator { id: second, ... },
    ],
}
```

## How to migrate

Code that previously read the kind from a declarator:

```rust
if declarator.kind.is_const() {
    // ...
}
```

should now read it from the containing declaration:

```rust
if declaration.kind.is_const() {
    // ...
}
```

Consumers operating through an AST node store should retrieve the parent `VariableDeclaration`:

```rust
let AstKind::VariableDeclaration(declaration) =
    nodes.parent_kind(declarator.node_id())
else {
    unreachable!();
};

let kind = declaration.kind;
```

Common migrations:

| Previous representation | New representation |
| --- | --- |
| `declarator.kind` | Containing `declaration.kind` |
| Match `VariableDeclarator::kind` during semantic binding | Read the parent `VariableDeclaration` from ancestry |
| Pass `kind` to `VariableDeclarator::new` | Remove the `kind` argument |
| Update parent and every child kind | Update only `VariableDeclaration::kind` |
| Recover kind after detaching a declarator | Capture or pass the parent kind before detaching it |
| Inspect a symbol’s declarator kind in lint rules | Resolve its parent declaration through the node store |

When constructing declarators, use the generated kindless `VariableDeclarator` builders and place them inside a `VariableDeclaration` carrying the required kind.

fixes https://github.com/oxc-project/backlog/issues/237
This commit is contained in:
camc314 committed 2026-08-05 16:31:46 +00:00
1 parent 4abff11c80
commit 6be314f226
73 files changed
+228 -326

No files matched your search

+1 -1
View File
@@ -1650,7 +1650,7 @@ function deserializeVariableDeclarator(pos) {
type: "VariableDeclarator",
id: null,
init: null,
definite: deserializeBool(pos + 13),
definite: deserializeBool(pos + 12),
start: (start = deserializeI32(pos)),
end: (end = deserializeI32(pos + 4)),
range: [start, end],
-2
View File
@@ -1216,8 +1216,6 @@ pub enum VariableDeclarationKind {
pub struct VariableDeclarator<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
#[estree(skip)]
pub kind: VariableDeclarationKind,
#[estree(via = VariableDeclaratorId)]
pub id: BindingPattern<'a>,
#[ts]
@@ -412,13 +412,12 @@ const _: () = {
assert!(size_of::<VariableDeclarationKind>() == 1);
assert!(align_of::<VariableDeclarationKind>() == 1);
// Padding: 2 bytes
// Padding: 3 bytes
assert!(size_of::<VariableDeclarator>() == 56);
assert!(align_of::<VariableDeclarator>() == 8);
assert!(offset_of!(VariableDeclarator, span) == 0);
assert!(offset_of!(VariableDeclarator, node_id) == 8);
assert!(offset_of!(VariableDeclarator, kind) == 12);
assert!(offset_of!(VariableDeclarator, definite) == 13);
assert!(offset_of!(VariableDeclarator, definite) == 12);
assert!(offset_of!(VariableDeclarator, id) == 16);
assert!(offset_of!(VariableDeclarator, type_annotation) == 32);
assert!(offset_of!(VariableDeclarator, init) == 40);
@@ -2250,13 +2249,12 @@ const _: () = if cfg!(target_family = "wasm") || align_of::<u64>() == 8 {
assert!(size_of::<VariableDeclarationKind>() == 1);
assert!(align_of::<VariableDeclarationKind>() == 1);
// Padding: 2 bytes
// Padding: 3 bytes
assert!(size_of::<VariableDeclarator>() == 36);
assert!(align_of::<VariableDeclarator>() == 4);
assert!(offset_of!(VariableDeclarator, span) == 0);
assert!(offset_of!(VariableDeclarator, node_id) == 8);
assert!(offset_of!(VariableDeclarator, kind) == 12);
assert!(offset_of!(VariableDeclarator, definite) == 13);
assert!(offset_of!(VariableDeclarator, definite) == 12);
assert!(offset_of!(VariableDeclarator, id) == 16);
assert!(offset_of!(VariableDeclarator, type_annotation) == 24);
assert!(offset_of!(VariableDeclarator, init) == 28);
@@ -10008,7 +10008,6 @@ impl<'a> VariableDeclarator<'a> {
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `kind`
/// * `id`
/// * `type_annotation`
/// * `init`
@@ -10016,7 +10015,6 @@ impl<'a> VariableDeclarator<'a> {
#[inline]
pub fn new(
span: Span,
kind: VariableDeclarationKind,
id: BindingPattern<'a>,
type_annotation: Option<ArenaBox<'a, TSTypeAnnotation<'a>>>,
init: Option<Expression<'a>>,
@@ -10027,7 +10025,6 @@ impl<'a> VariableDeclarator<'a> {
VariableDeclarator {
node_id: Cell::new(builder.node_id()),
span,
kind,
id,
type_annotation,
init,
@@ -1570,7 +1570,6 @@ impl<'new_alloc> CloneIn<'new_alloc> for VariableDeclarator<'_> {
VariableDeclarator {
node_id: CloneIn::clone_in_impl(&self.node_id, with_semantic_ids, allocator),
span: CloneIn::clone_in_impl(&self.span, with_semantic_ids, allocator),
kind: CloneIn::clone_in_impl(&self.kind, with_semantic_ids, allocator),
id: CloneIn::clone_in_impl(&self.id, with_semantic_ids, allocator),
type_annotation: CloneIn::clone_in_impl(
&self.type_annotation,
@@ -779,8 +779,7 @@ impl ContentEq for VariableDeclarationKind {
impl ContentEq for VariableDeclarator<'_> {
fn content_eq(&self, other: &Self) -> bool {
ContentEq::content_eq(&self.kind, &other.kind)
&& ContentEq::content_eq(&self.id, &other.id)
ContentEq::content_eq(&self.id, &other.id)
&& ContentEq::content_eq(&self.type_annotation, &other.type_annotation)
&& ContentEq::content_eq(&self.init, &other.init)
&& ContentEq::content_eq(&self.definite, &other.definite)
@@ -767,7 +767,6 @@ impl<'a> Dummy<'a> for VariableDeclarator<'a> {
Self {
node_id: Dummy::dummy(allocator),
span: Dummy::dummy(allocator),
kind: Dummy::dummy(allocator),
id: Dummy::dummy(allocator),
type_annotation: Dummy::dummy(allocator),
init: Dummy::dummy(allocator),
@@ -247,7 +247,7 @@ pub static STRUCTS: phf::Map<&'static str, StructDetails> = ::phf::Map {
(
"VariableDeclarator",
StructDetails {
field_order: Some(&[1, 0, 2, 4, 5, 6, 3]),
field_order: Some(&[1, 0, 3, 4, 5, 2]),
is_node: true,
is_transparent: false,
},
@@ -3326,11 +3326,6 @@ impl<'a> AstNode<'a, VariableDeclarator<'a>> {
self.inner.node_id()
}
#[inline]
pub fn kind(&self) -> VariableDeclarationKind {
self.inner.kind
}
#[inline]
pub fn id(&self) -> &AstNode<'a, BindingPattern<'a>> {
let following_span_start = self
@@ -27,7 +27,7 @@ impl<'a> IsolatedDeclarations<'a> {
} else {
let declarations = ArenaVec::from_iter_in(
decl.declarations.iter().filter_map(|declarator| {
self.transform_variable_declarator(declarator, check_binding)
self.transform_variable_declarator(declarator, decl.kind, check_binding)
}),
self,
);
@@ -46,6 +46,7 @@ impl<'a> IsolatedDeclarations<'a> {
pub(crate) fn transform_variable_declarator(
&self,
decl: &VariableDeclarator<'a>,
kind: VariableDeclarationKind,
check_binding: bool,
) -> Option<VariableDeclarator<'a>> {
if decl.id.is_destructuring_pattern() {
@@ -69,16 +70,14 @@ impl<'a> IsolatedDeclarations<'a> {
if decl.type_annotation.is_none() {
if let Some(init_expr) = &decl.init {
// if kind is const and it doesn't need to infer type from expression
if decl.kind.is_const() && !Self::is_need_to_infer_type_from_expression(init_expr) {
if kind.is_const() && !Self::is_need_to_infer_type_from_expression(init_expr) {
if let Expression::TemplateLiteral(lit) = init_expr {
init =
self.transform_template_to_string(lit).map(Expression::StringLiteral);
} else {
init = Some(init_expr.clone_in(self.allocator()));
}
} else if !decl.kind.is_const()
|| !matches!(init_expr, Expression::TemplateLiteral(_))
{
} else if !kind.is_const() || !matches!(init_expr, Expression::TemplateLiteral(_)) {
// otherwise, we need to infer type from expression
binding_type = self.infer_type_from_expression(init_expr);
}
@@ -101,15 +100,7 @@ impl<'a> IsolatedDeclarations<'a> {
let type_annotation =
binding_type.map(|ts_type| TSTypeAnnotation::boxed(SPAN, ts_type, self));
Some(VariableDeclarator::new(
decl.span,
decl.kind,
id,
type_annotation,
init,
decl.definite,
self,
))
Some(VariableDeclarator::new(decl.span, id, type_annotation, init, decl.definite, self))
}
fn transform_ts_module_block(
+1 -1
View File
@@ -348,7 +348,7 @@ impl<'a> IsolatedDeclarations<'a> {
}
if let Some(new_declarator) =
self.transform_variable_declarator(declarator, true)
self.transform_variable_declarator(declarator, declaration.kind, true)
{
self.scope.visit_variable_declarator(&new_declarator);
transformed_variable_declarator.insert(declarator.span, new_declarator);
@@ -125,8 +125,7 @@ impl<'a> IsolatedDeclarations<'a> {
self.error(default_export_inferred(expr.span()));
}
let declaration =
VariableDeclarator::new(SPAN, kind, id, type_annotation, None, false, self);
let declaration = VariableDeclarator::new(SPAN, id, type_annotation, None, false, self);
let variable_statement = Statement::new_variable_declaration(
decl_span,
+12
View File
@@ -22,6 +22,18 @@ use crate::{
utils::{get_function_nearest_jsdoc_node, is_regexp_callee},
};
/// Get the declaration kind for a variable declarator from its parent declaration.
pub fn variable_declaration_kind(
declarator: &VariableDeclarator<'_>,
ctx: &LintContext<'_>,
) -> VariableDeclarationKind {
let AstKind::VariableDeclaration(declaration) = ctx.nodes().parent_kind(declarator.node_id())
else {
unreachable!();
};
declaration.kind
}
/// Test if an AST node is a boolean value that never changes. Specifically we
/// test for:
/// 1. Literal booleans (`true` or `false`)
@@ -139,6 +139,7 @@ impl Rule for InitDeclarations {
return;
}
}
let declaration_is_const = decl.kind == VariableDeclarationKind::Const;
for v in &decl.declarations {
let BindingPattern::BindingIdentifier(identifier) = &v.id else {
continue;
@@ -166,7 +167,7 @@ impl Rule for InitDeclarations {
));
}
AlwaysNever::Never if is_initialized && !config.ignore_for_loop_init => {
if matches!(&v.kind, VariableDeclarationKind::Const) {
if declaration_is_const {
continue;
}
ctx.diagnostic(init_declarations_diagnostic(
@@ -5,7 +5,7 @@ use oxc_macros::declare_oxc_lint;
use oxc_semantic::{AstNode, SymbolId};
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
use crate::{ast_util::variable_declaration_kind, context::LintContext, rule::Rule};
fn no_const_assign_diagnostic(name: &str, decl_span: Span, assign_span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected re-assignment of `const` variable {name}."))
@@ -60,11 +60,10 @@ declare_oxc_lint!(
impl Rule for NoConstAssign {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::VariableDeclarator(decl) if decl.kind.is_const() || decl.kind.is_using() => {
decl.id.bound_names(&mut |ident| check_symbol_id(ident.symbol_id(), ctx));
}
_ => {}
let AstKind::VariableDeclarator(decl) = node.kind() else { return };
let kind = variable_declaration_kind(decl, ctx);
if kind.is_const() || kind.is_using() {
decl.id.bound_names(&mut |ident| check_symbol_id(ident.symbol_id(), ctx));
}
}
}
@@ -10,7 +10,7 @@ use oxc_syntax::operator::UnaryOperator;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{AstNode, context::LintContext, rule::Rule};
use crate::{AstNode, ast_util::variable_declaration_kind, context::LintContext, rule::Rule};
enum NoMagicNumberReportReason {
MustUseConst,
@@ -325,7 +325,7 @@ impl Rule for NoMagicNumbers {
let parent_kind = nodes.parent_kind(config.node.id());
let span = config.node.kind().span();
let Some(reason) = self.get_report_reason(&parent_kind) else {
let Some(reason) = self.get_report_reason(&parent_kind, ctx) else {
return;
};
@@ -517,11 +517,14 @@ impl NoMagicNumbers {
fn get_report_reason<'a>(
&self,
parent_kind: &'a AstKind<'a>,
parent_kind: &AstKind<'a>,
ctx: &LintContext<'a>,
) -> Option<NoMagicNumberReportReason> {
match parent_kind {
AstKind::VariableDeclarator(declarator) => {
if self.enforce_const && declarator.kind != VariableDeclarationKind::Const {
if self.enforce_const
&& variable_declaration_kind(declarator, ctx) != VariableDeclarationKind::Const
{
return Some(NoMagicNumberReportReason::MustUseConst);
}
@@ -59,14 +59,14 @@ impl Rule for NoUnassignedVars {
let AstKind::VariableDeclarator(declarator) = node.kind() else {
return;
};
if declarator.init.is_some() || declarator.kind.is_const() {
if declarator.init.is_some() {
return;
}
let parent_node = ctx.nodes().parent_node(node.id());
let AstKind::VariableDeclaration(parent) = parent_node.kind() else {
return;
};
if parent.declare {
if parent.kind.is_const() || parent.declare {
return;
}
let grand_parent = ctx.nodes().parent_node(parent_node.id());
@@ -15,6 +15,7 @@ use oxc_span::Span;
use crate::{
AstNode,
ast_util::variable_declaration_kind,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
@@ -243,7 +244,7 @@ fn binding_context(ctx: &LintContext, id: NodeId) -> BindingContext {
};
}
AstKind::VariableDeclarator(declarator) => {
return if declarator.kind.is_using() {
return if variable_declaration_kind(declarator, ctx).is_using() {
BindingContext::Using
} else {
destructure_context.unwrap_or(BindingContext::Plain)
@@ -5,7 +5,8 @@ use oxc_semantic::{NodeId, Semantic};
use super::{NoUnusedVars, Symbol, options::ArgsOption};
use crate::{
ModuleRecord,
LintContext, ModuleRecord,
ast_util::variable_declaration_kind,
rules::eslint::no_unused_vars::binding_pattern::{BindingContext, HasAnyUsedBinding},
};
@@ -165,8 +166,10 @@ impl NoUnusedVars {
&self,
symbol: &Symbol<'_, 'a>,
decl: &VariableDeclarator<'a>,
ctx: &LintContext<'a>,
) -> bool {
if decl.kind.is_var() && self.vars.is_local() && symbol.is_root() {
if variable_declaration_kind(decl, ctx).is_var() && self.vars.is_local() && symbol.is_root()
{
return true;
}
@@ -175,7 +178,7 @@ impl NoUnusedVars {
return true;
}
if self.ignore_using_declarations && decl.kind.is_using() {
if self.ignore_using_declarations && variable_declaration_kind(decl, ctx).is_using() {
return true;
}
@@ -302,7 +302,7 @@ impl NoUnusedVars {
}
}
AstKind::VariableDeclarator(decl) => {
if self.is_allowed_variable_declaration(symbol, decl) {
if self.is_allowed_variable_declaration(symbol, decl, ctx) {
return;
}
let report = match symbol.references().rev().find(|r| r.is_write()) {
@@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize};
use crate::{
AstNode,
ast_util::variable_declaration_kind,
context::LintContext,
rule::{Rule, TupleRuleConfig},
};
@@ -255,7 +256,7 @@ impl Rule for PreferDestructuring {
// Skip `using` and `await using` declarations - destructuring doesn't apply to them
if matches!(
declarator.kind,
variable_declaration_kind(declarator, ctx),
VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing
) {
return;
@@ -14,6 +14,7 @@ use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
use crate::{
AstNode,
ast_util::get_declaration_of_variable,
ast_util::variable_declaration_kind,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
utils::is_regexp_callee,
@@ -326,7 +327,7 @@ fn resolve_const_initializer<'a>(
let declaration = get_declaration_of_variable(ident, ctx.semantic())?;
let AstKind::VariableDeclarator(decl) = declaration.kind() else { return None };
if !decl.kind.is_const() || !decl.id.is_binding_identifier() {
if !variable_declaration_kind(decl, ctx).is_const() || !decl.id.is_binding_identifier() {
return None;
}
@@ -6,7 +6,10 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use crate::{AstNode, ast_util::is_method_call, context::LintContext, rule::Rule};
use crate::{
AstNode, ast_util::is_method_call, ast_util::variable_declaration_kind, context::LintContext,
rule::Rule,
};
fn bad_char_at_comparison_diagnostic(
character_access: Span,
@@ -140,13 +143,15 @@ fn is_definitely_string(expr: &Expression, ctx: &LintContext) -> bool {
let declaration =
ctx.nodes().get_node(ctx.scoping().symbol_declaration(symbol_id)).kind();
declaration.as_variable_declarator().is_some_and(is_definitely_string_declarator)
declaration
.as_variable_declarator()
.is_some_and(|declarator| is_definitely_string_declarator(declarator, ctx))
}
_ => false,
}
}
fn is_definitely_string_declarator(declarator: &VariableDeclarator) -> bool {
fn is_definitely_string_declarator(declarator: &VariableDeclarator, ctx: &LintContext) -> bool {
if declarator
.type_annotation
.as_ref()
@@ -155,7 +160,9 @@ fn is_definitely_string_declarator(declarator: &VariableDeclarator) -> bool {
return true;
}
if !declarator.kind.is_const() || !declarator.id.is_binding_identifier() {
if !variable_declaration_kind(declarator, ctx).is_const()
|| !declarator.id.is_binding_identifier()
{
return false;
}
@@ -31,6 +31,7 @@ use oxc_syntax::scope::ScopeFlags;
use crate::{
AstNode,
ast_util::variable_declaration_kind,
ast_util::{
get_declaration_from_reference_id, get_declaration_of_variable, get_enclosing_function,
},
@@ -1130,7 +1131,7 @@ fn is_stable_value<'a, 'b>(
}
// if the variables is a constant, and the initializer is a literal, then it's a stable value. (excluding regex literals)
if declaration.kind == VariableDeclarationKind::Const
if variable_declaration_kind(declaration, ctx) == VariableDeclarationKind::Const
&& (matches!(
init.get_inner_expression(),
Expression::BooleanLiteral(_)
@@ -7,7 +7,7 @@ use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNode;
use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule};
use crate::{ast_util::variable_declaration_kind, context::LintContext, rule::Rule};
#[derive(Debug, Default, Clone)]
pub struct ConsistentExistenceIndexCheck;
@@ -97,7 +97,9 @@ impl Rule for ConsistentExistenceIndexCheck {
let node = ctx.nodes().get_node(declaration_node_id);
if let AstKind::VariableDeclarator(variables_declarator) = node.kind() {
if variables_declarator.kind != VariableDeclarationKind::Const {
if variable_declaration_kind(variables_declarator, ctx)
!= VariableDeclarationKind::Const
{
return;
}
@@ -8,6 +8,7 @@ use oxc_span::{GetSpan, Span};
use crate::{
AstNode,
ast_util::variable_declaration_kind,
ast_util::{get_declaration_of_variable, is_method_call},
context::LintContext,
rule::Rule,
@@ -133,7 +134,9 @@ fn get_const_variable_initializer<'a>(
return None;
};
if !decl.kind.is_const() || !is_same_binding_identifier(&decl.id, ident) {
if !variable_declaration_kind(decl, ctx).is_const()
|| !is_same_binding_identifier(&decl.id, ident)
{
return None;
}
@@ -227,10 +227,11 @@ impl Rule for NoUselessUndefined {
AstKind::VariableDeclarator(variable_declarator) => {
let grand_parent_node = ctx.nodes().parent_node(parent_node.id());
let grand_parent_node_kind = grand_parent_node.kind();
let AstKind::VariableDeclaration(_) = grand_parent_node_kind else {
let AstKind::VariableDeclaration(declaration) = grand_parent_node_kind
else {
return;
};
if variable_declarator.kind == VariableDeclarationKind::Const {
if declaration.kind == VariableDeclarationKind::Const {
return;
}
if is_has_function_return_type(parent_node, ctx) {
@@ -11,6 +11,7 @@ use oxc_span::Span;
use crate::{
AstNode,
ast_util::variable_declaration_kind,
ast_util::{get_symbol_id_of_variable, is_method_call},
context::LintContext,
rule::Rule,
@@ -160,7 +161,7 @@ fn const_variable_initializer_kind(
let AstKind::VariableDeclarator(declarator) = node.kind() else {
return None;
};
if !declarator.kind.is_const() {
if !variable_declaration_kind(declarator, ctx).is_const() {
return None;
}
let init = declarator.init.as_ref()?.get_inner_expression();
@@ -17,6 +17,7 @@ use oxc_span::{GetSpan, Span};
use crate::{
AstNode,
ast_util::variable_declaration_kind,
context::LintContext,
fixer::{RuleFix, RuleFixer},
rule::Rule,
@@ -583,7 +584,7 @@ fn is_obviously_non_array_receiver(expr: &Expression, ctx: &LintContext) -> bool
let AstKind::VariableDeclarator(declarator) = ctx.symbol_declaration(symbol_id).kind() else {
return false;
};
if declarator.kind != VariableDeclarationKind::Const {
if variable_declaration_kind(declarator, ctx) != VariableDeclarationKind::Const {
return false;
}
declarator
@@ -11,7 +11,7 @@ use oxc_syntax::node::NodeId;
use oxc_syntax::symbol::SymbolId;
use rustc_hash::FxHashSet;
use crate::{context::LintContext, rule::Rule};
use crate::{ast_util::variable_declaration_kind, context::LintContext, rule::Rule};
const PATH_MODULES: [&str; 2] = ["path", "node:path"];
const URL_MODULES: [&str; 2] = ["url", "node:url"];
@@ -329,7 +329,7 @@ fn check_variable_declarator(
ctx: &LintContext<'_>,
visited: &mut FxHashSet<SymbolId>,
) -> bool {
if !variable_declarator.kind.is_const() {
if !variable_declaration_kind(variable_declarator, ctx).is_const() {
return false;
}
@@ -392,7 +392,9 @@ fn iterate_problems_from_filename(
}
let AstKind::VariableDeclarator(parent) = ctx.nodes().kind(parent_id) else { return };
if !parent.kind.is_const() || parent.init.as_ref().is_none_or(|init| init.span() != node_span) {
if !variable_declaration_kind(parent, ctx).is_const()
|| parent.init.as_ref().is_none_or(|init| init.span() != node_span)
{
return;
}
@@ -8,7 +8,10 @@ use oxc_macros::declare_oxc_lint;
use oxc_semantic::ScopeId;
use oxc_span::Span;
use crate::{AstNode, ast_util::is_method_call, context::LintContext, rule::Rule};
use crate::{
AstNode, ast_util::is_method_call, ast_util::variable_declaration_kind, context::LintContext,
rule::Rule,
};
const ARRAY_METHODS_RETURNS_ARRAY: [&str; 15] = [
"concat",
@@ -133,7 +136,7 @@ impl Rule for PreferSetHas {
return;
};
if declarator.kind == VariableDeclarationKind::Var {
if variable_declaration_kind(declarator, ctx) == VariableDeclarationKind::Var {
return;
}
@@ -8,6 +8,7 @@ use oxc_span::{GetSpan, Span};
use crate::{
AstNode,
ast_util::variable_declaration_kind,
ast_util::{get_declaration_of_variable, is_method_call},
context::LintContext,
fixer::Fix,
@@ -149,7 +150,7 @@ fn is_set<'a>(maybe_set: &Expression<'a>, ctx: &LintContext<'a>) -> bool {
return false;
};
if !var_decl.kind.is_const() {
if !variable_declaration_kind(var_decl, ctx).is_const() {
return false;
}
@@ -6,7 +6,10 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use crate::{AstNode, ast_util::is_method_call, context::LintContext, rule::Rule};
use crate::{
AstNode, ast_util::is_method_call, ast_util::variable_declaration_kind, context::LintContext,
rule::Rule,
};
fn prefer_top_level_await_over_promise_chain_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Prefer top-level await over using a promise chain.").with_label(span)
@@ -159,7 +162,7 @@ impl Rule for PreferTopLevelAwait {
match declaration.kind() {
AstKind::VariableDeclarator(var_decl)
if var_decl.kind == VariableDeclarationKind::Const =>
if variable_declaration_kind(var_decl, ctx) == VariableDeclarationKind::Const =>
{
let Some(init) = &var_decl.init else { return };
@@ -9,7 +9,10 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use crate::{AstNode, context::LintContext, frameworks::FrameworkOptions, rule::Rule};
use crate::{
AstNode, ast_util::variable_declaration_kind, context::LintContext,
frameworks::FrameworkOptions, rule::Rule,
};
fn multiple_arguments_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected multiple arguments.")
@@ -165,7 +168,7 @@ fn get_identifier_resolved_reference<'a>(
};
// `const` variable can not be overridden
if declarator.kind == VariableDeclarationKind::Const {
if variable_declaration_kind(declarator, ctx) == VariableDeclarationKind::Const {
return declarator.init.as_ref();
}
@@ -7,7 +7,10 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use crate::{AstNode, context::LintContext, frameworks::FrameworkOptions, rule::Rule};
use crate::{
AstNode, ast_util::variable_declaration_kind, context::LintContext,
frameworks::FrameworkOptions, rule::Rule,
};
fn referencing_locally_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("`defineOptions` is referencing locally declared variables.")
@@ -205,7 +208,7 @@ fn is_non_local_reference(
| AstKind::ImportNamespaceSpecifier(_) => true,
AstKind::VariableDeclarator(declarator) => {
// `const x = <literal>` is statically resolvable, so allowed
declarator.kind.is_const()
variable_declaration_kind(declarator, ctx).is_const()
&& declarator.init.as_ref().is_some_and(is_literal_expression)
}
_ => false,
@@ -9,7 +9,10 @@ use oxc_ast_visit::{VisitJs, walk_js};
use oxc_semantic::ScopeFlags;
use oxc_span::Span;
use crate::{ast_util::get_declaration_from_reference_id, context::LintContext};
use crate::{
ast_util::get_declaration_from_reference_id, ast_util::variable_declaration_kind,
context::LintContext,
};
/// Finds `this` expressions without traversing into nested functions.
pub struct ThisExpressionFinder {
@@ -73,7 +76,7 @@ pub fn is_this_alias(ident: &IdentifierReference, ctx: &LintContext<'_>) -> bool
_ => None,
})
.filter(|var| {
var.kind == VariableDeclarationKind::Const
variable_declaration_kind(var, ctx) == VariableDeclarationKind::Const
&& matches!(&var.id, BindingPattern::BindingIdentifier(_))
})
.and_then(|var| var.init.as_ref())
@@ -5211,7 +5211,6 @@ impl<'a, 't> GetAddress for VariableDeclarationWithoutDeclarations<'a, 't> {
pub(crate) const OFFSET_VARIABLE_DECLARATOR_NODE_ID: usize =
offset_of!(VariableDeclarator, node_id);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_SPAN: usize = offset_of!(VariableDeclarator, span);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_KIND: usize = offset_of!(VariableDeclarator, kind);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_ID: usize = offset_of!(VariableDeclarator, id);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_TYPE_ANNOTATION: usize =
offset_of!(VariableDeclarator, type_annotation);
@@ -5239,14 +5238,6 @@ impl<'a, 't> VariableDeclaratorWithoutId<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn type_annotation(self) -> &'t Option<ArenaBox<'a, TSTypeAnnotation<'a>>> {
unsafe {
@@ -5296,14 +5287,6 @@ impl<'a, 't> VariableDeclaratorWithoutTypeAnnotation<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn id(self) -> &'t BindingPattern<'a> {
unsafe {
@@ -5353,14 +5336,6 @@ impl<'a, 't> VariableDeclaratorWithoutInit<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn id(self) -> &'t BindingPattern<'a> {
unsafe {
+1 -1
View File
@@ -80,7 +80,7 @@ impl<'a> KeepVar<'a> {
)
},
);
VariableDeclarator::new(span, kind, id, None, None, false, builder)
VariableDeclarator::new(span, id, None, None, false, builder)
}),
builder,
);
+6 -2
View File
@@ -11,6 +11,10 @@ use super::PeepholeOptimizations;
impl<'a> PeepholeOptimizations {
pub fn init_symbol_value(decl: &VariableDeclarator<'a>, ctx: &mut TraverseCtx<'a>) {
let Ancestor::VariableDeclarationDeclarations(declaration) = ctx.parent() else {
unreachable!();
};
let declaration_kind = *declaration.kind();
let BindingPattern::BindingIdentifier(ident) = &decl.id else { return };
let Some(symbol_id) = ident.symbol_id.get() else { return };
// Evaluate the initializer's constant once; reuse it for the value-context
@@ -23,11 +27,11 @@ impl<'a> PeepholeOptimizations {
// `SymbolValue::boolean_falsy`).
let falsy_init = init_constant.as_ref().is_some_and(Self::is_falsy_constant);
let declaration_in_body_statement_list =
!decl.kind.is_var() || Self::is_declaration_in_body_statement_list(ctx);
!declaration_kind.is_var() || Self::is_declaration_in_body_statement_list(ctx);
let value = if Self::is_for_statement_init(ctx) {
// for-statement initializers have their value set by the for statement itself.
None
} else if decl.kind.is_var()
} else if declaration_kind.is_var()
&& !Self::is_hoisted_var_inlineable(
decl,
symbol_id,
@@ -436,7 +436,10 @@ impl<'a> PeepholeOptimizations {
// If `join_vars` is off, but there are unused declarators ... just join them to make our code simpler.
if !ctx.options().join_vars
&& var_decl.declarations.iter().all(|d| !Self::should_remove_unused_declarator(d, ctx))
&& var_decl
.declarations
.iter()
.all(|d| !Self::should_remove_unused_declarator(d, var_decl.kind, ctx))
{
result.push(Statement::VariableDeclaration(var_decl));
return;
@@ -449,7 +452,7 @@ impl<'a> PeepholeOptimizations {
}
let VariableDeclaration { span, kind, declarations, declare, .. } = var_decl.unbox();
for mut decl in declarations {
if Self::should_remove_unused_declarator(&decl, ctx) {
if Self::should_remove_unused_declarator(&decl, kind, ctx) {
// `init` is `mut` because `remove_unused_expression` rewrites
// it in place (peeling pure-call wrappers, etc). It is taken
// out first because it may survive as an expression statement
@@ -595,13 +598,14 @@ impl<'a> PeepholeOptimizations {
if !matches!(&var_decl.kind, VariableDeclarationKind::Var | VariableDeclarationKind::Let) {
return false;
}
let declaration_kind = var_decl.kind;
for decl in var_decl.declarations.iter_mut().rev() {
let BindingPattern::BindingIdentifier(kind) = &decl.id else {
break;
};
if kind.name == id.name {
if decl.init.is_none()
&& (decl.kind == VariableDeclarationKind::Var
&& (declaration_kind == VariableDeclarationKind::Var
|| assign_expr.right.is_literal_value(true, ctx))
{
// "var a; a = b();" => "var a = b();"
@@ -623,7 +627,7 @@ impl<'a> PeepholeOptimizations {
}
// should not move assignment above other variables for let
// this could cause TDZ errors (e.g. `let a, b; b = a;`)
if decl.kind == VariableDeclarationKind::Let {
if declaration_kind == VariableDeclarationKind::Let {
break;
}
}
@@ -1014,10 +1018,11 @@ impl<'a> PeepholeOptimizations {
if let Some(init) = &mut for_stmt.init {
match init {
ForStatementInit::VariableDeclaration(var_decl) => {
let declaration_kind = var_decl.kind;
if let Some(first_decl) = var_decl.declarations.first_mut()
&& let Some(first_decl_init) = first_decl.init.as_mut()
{
let is_block_scoped_decl = !first_decl.kind.is_var();
let is_block_scoped_decl = !declaration_kind.is_var();
Self::substitute_single_use_symbol_in_statement(
first_decl_init,
result,
@@ -1039,13 +1044,14 @@ impl<'a> PeepholeOptimizations {
}
if let Some(ForStatementInit::VariableDeclaration(var_decl)) = &mut for_stmt.init {
let declaration_kind = var_decl.kind;
let old_len = var_decl.declarations.len();
var_decl.declarations.retain_mut(|decl| {
let should_keep = !Self::should_remove_unused_declarator(decl, ctx)
|| decl
.init
.as_ref()
.is_some_and(|init| Self::has_side_effects_or_preserved_iife(init, ctx));
let should_keep =
!Self::should_remove_unused_declarator(decl, declaration_kind, ctx)
|| decl.init.as_ref().is_some_and(|init| {
Self::has_side_effects_or_preserved_iife(init, ctx)
});
if !should_keep {
// Same leak hazard as `remove_unused_variable_declaration`:
// the `retain` silently drops the declarator, so its refs
@@ -289,9 +289,6 @@ impl<'a> Normalize {
if all_declarations_are_only_read {
// mark all declarations as `let`
decl.kind = VariableDeclarationKind::Let;
for decl in &mut decl.declarations {
decl.kind = VariableDeclarationKind::Let;
}
}
}
}
@@ -86,13 +86,14 @@ impl<'a> PeepholeOptimizations {
pub fn should_remove_unused_declarator(
decl: &VariableDeclarator<'a>,
kind: VariableDeclarationKind,
ctx: &TraverseCtx<'a>,
) -> bool {
if !Self::can_remove_unused_declarators(ctx) {
return false;
}
// Unsafe to remove `using`, unable to statically determine usage of [Symbol.dispose].
if decl.kind.is_using() {
if kind.is_using() {
return false;
}
match &decl.id {
@@ -143,13 +144,14 @@ impl<'a> PeepholeOptimizations {
if !Self::can_remove_unused_declarators(ctx) {
return Some(stmt);
}
let kind = var_decl.kind;
var_decl.declarations.retain(|decl| {
debug_assert!(
decl.init.is_none(),
"callers must pass KeepVar output (init-less declarators); a declarator \
with an init would need a `drop_*` walk for its references"
);
!Self::should_remove_unused_declarator(decl, ctx)
!Self::should_remove_unused_declarator(decl, kind, ctx)
});
if var_decl.declarations.is_empty() {
return None;
@@ -170,7 +170,7 @@ impl<'a> PeepholeOptimizations {
ctx: &mut TraverseCtx<'a>,
) {
for declarator in &mut decl.declarations {
Self::compress_variable_declarator(declarator, ctx);
Self::compress_variable_declarator(declarator, decl.kind, ctx);
}
}
@@ -995,8 +995,7 @@ impl<'a> PeepholeOptimizations {
base_arr
};
let new_decl =
VariableDeclarator::new(SPAN, var_init.kind, r_id_pat, None, Some(arr), false, ctx);
let new_decl = VariableDeclarator::new(SPAN, r_id_pat, None, Some(arr), false, ctx);
// The old declarators (`e`, `a`, and `r`'s original init) are
// replaced wholesale — walk them so refs inside (e.g. `e` in
// `Array(e > 1 ? e - 1 : 0)`) reach `PassChanges`. The moved-out
@@ -1055,10 +1054,14 @@ impl<'a> PeepholeOptimizations {
}
}
fn compress_variable_declarator(decl: &mut VariableDeclarator<'a>, ctx: &mut TraverseCtx<'a>) {
fn compress_variable_declarator(
decl: &mut VariableDeclarator<'a>,
kind: VariableDeclarationKind,
ctx: &mut TraverseCtx<'a>,
) {
// Destructuring Pattern has error throwing side effect.
if matches!(
decl.kind,
kind,
VariableDeclarationKind::Const
| VariableDeclarationKind::Using
| VariableDeclarationKind::AwaitUsing
@@ -1066,7 +1069,7 @@ impl<'a> PeepholeOptimizations {
{
return;
}
if !decl.kind.is_var()
if !kind.is_var()
&& decl.init.as_ref().is_some_and(|init| ctx.is_expression_undefined(init))
&& let Some(old) = decl.init.take()
{
@@ -1880,7 +1883,10 @@ impl<'a> PeepholeOptimizations {
return false;
}
// `using` runs `[Symbol.dispose]` at scope exit.
if decl.kind().is_using() {
let Ancestor::VariableDeclarationDeclarations(declaration) = ctx.ancestor(1) else {
unreachable!();
};
if declaration.kind().is_using() {
return false;
}
let BindingPattern::BindingIdentifier(ident) = decl.id() else {
+10 -7
View File
@@ -134,7 +134,6 @@ impl<'a, C: Config> ParserImpl<'a, C> {
let init = self.eat(Kind::Eq).then(|| self.parse_assignment_expression_or_higher());
let decl = VariableDeclarator::new(
self.end_span(start),
kind,
id,
type_annotation,
init,
@@ -143,13 +142,13 @@ impl<'a, C: Config> ParserImpl<'a, C> {
);
if self.ctx.has_ambient()
&& let Some(init) = &decl.init
&& !decl.kind.is_using()
&& !(decl.kind.is_const() && decl.type_annotation.is_none())
&& !kind.is_using()
&& !(kind.is_const() && decl.type_annotation.is_none())
{
self.error(diagnostics::initializers_not_allowed_in_ambient_contexts(init.span()));
}
if decl_parent == VariableDeclarationParent::Statement {
self.check_missing_initializer(&decl);
self.check_missing_initializer(&decl, kind);
}
if let Some(definite_start) = definite_start {
let span = Span::sized(definite_start, 1);
@@ -164,14 +163,18 @@ impl<'a, C: Config> ParserImpl<'a, C> {
decl
}
pub(crate) fn check_missing_initializer(&mut self, decl: &VariableDeclarator<'a>) {
pub(crate) fn check_missing_initializer(
&mut self,
decl: &VariableDeclarator<'a>,
kind: VariableDeclarationKind,
) {
if decl.init.is_none() && !self.ctx.has_ambient() {
if !matches!(decl.id, BindingPattern::BindingIdentifier(_)) {
self.error(diagnostics::invalid_destructuring_declaration(decl.id.span()));
} else if decl.kind == VariableDeclarationKind::Const {
} else if kind == VariableDeclarationKind::Const {
// It is a Syntax Error if Initializer is not present and IsConstantDeclaration of the LexicalDeclaration containing this LexicalBinding is true.
self.error(diagnostics::missing_initializer_in_const(decl.id.span()));
} else if decl.kind.is_using() {
} else if kind.is_using() {
self.error(diagnostics::using_declarations_must_be_initialized(decl.id.span()));
}
}
+1 -1
View File
@@ -591,7 +591,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
self.expect(Kind::Semicolon);
if let Some(ForStatementInit::VariableDeclaration(decl)) = &init {
for d in &decl.declarations {
self.check_missing_initializer(d);
self.check_missing_initializer(d, decl.kind);
}
}
let test = if matches!(self.cur_kind(), Kind::Semicolon | Kind::RParen) {
@@ -2261,7 +2261,6 @@ fn ox_build_gated_const_decl<'a>(
) -> Statement<'a> {
let declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Const,
BindingPattern::new_binding_identifier(SPAN, ox_atom(ast, name), ast),
None,
Some(gating_expression.clone_in_with_semantic_ids(ast.allocator())),
@@ -2806,15 +2805,8 @@ fn ox_add_imports_to_program<'a>(
false,
ast,
);
let declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Const,
object_pattern,
None,
Some(require_call),
false,
ast,
);
let declarator =
VariableDeclarator::new(SPAN, object_pattern, None, Some(require_call), false, ast);
let decl = VariableDeclaration::boxed(
SPAN,
VariableDeclarationKind::Const,
@@ -127,7 +127,6 @@ pub fn codegen_function<'a>(
);
let declarator = oxc_ast::ast::VariableDeclarator::new(
SPAN,
oxc_ast::ast::VariableDeclarationKind::Const,
oxc_ast::ast::BindingPattern::new_binding_identifier(
SPAN,
ox_str(ast, &cache_name),
@@ -720,7 +719,6 @@ fn ox_codegen_reactive_scope<'a>(
if !cx.has_declared(decl.identifier) {
let declarator = oxc_ast::ast::VariableDeclarator::new(
SPAN,
oxc::VariableDeclarationKind::Let,
oxc_ast::ast::BindingPattern::new_binding_identifier(
SPAN,
ox_str(&cx.ast, &name),
@@ -1073,15 +1071,7 @@ fn ox_codegen_for_in<'a>(
let right = ox_codegen_instruction_value_to_expression(cx, &iterable_collection.value)?;
let body = ox_codegen_block_statement(cx, loop_block)?;
let body = oxc::Statement::BlockStatement(body);
let declarator = oxc_ast::ast::VariableDeclarator::new(
SPAN,
var_decl_kind,
lval,
None,
None,
false,
&cx.ast,
);
let declarator = oxc_ast::ast::VariableDeclarator::new(SPAN, lval, None, None, false, &cx.ast);
let decl =
oxc_ast::ast::VariableDeclaration::boxed(SPAN, var_decl_kind, [declarator], false, &cx.ast);
let left = oxc::ForStatementLeft::VariableDeclaration(decl);
@@ -1125,15 +1115,7 @@ fn ox_codegen_for_of<'a>(
let right = ox_codegen_place_to_expression(cx, collection)?;
let body = ox_codegen_block_statement(cx, loop_block)?;
let body = oxc::Statement::BlockStatement(body);
let declarator = oxc_ast::ast::VariableDeclarator::new(
SPAN,
var_decl_kind,
lval,
None,
None,
false,
&cx.ast,
);
let declarator = oxc_ast::ast::VariableDeclarator::new(SPAN, lval, None, None, false, &cx.ast);
let decl =
oxc_ast::ast::VariableDeclaration::boxed(SPAN, var_decl_kind, [declarator], false, &cx.ast);
let left = oxc::ForStatementLeft::VariableDeclaration(decl);
@@ -1484,8 +1466,7 @@ fn ox_make_var_decl<'a>(
id: oxc::BindingPattern<'a>,
init: Option<oxc::Expression<'a>>,
) -> oxc::Statement<'a> {
let declarator =
oxc_ast::ast::VariableDeclarator::new(SPAN, kind, id, None, init, false, &cx.ast);
let declarator = oxc_ast::ast::VariableDeclarator::new(SPAN, id, None, init, false, &cx.ast);
oxc::Statement::VariableDeclaration(oxc_ast::ast::VariableDeclaration::boxed(
SPAN,
kind,
+7 -6
View File
@@ -17,12 +17,13 @@ pub trait Binder<'a> {
impl<'a> Binder<'a> for VariableDeclarator<'a> {
fn bind(&self, builder: &mut SemanticBuilder<'a>) {
let is_declare = matches!(
builder.ancestry().parent_kind(),
AstKind::VariableDeclaration(decl) if decl.declare
);
let AstKind::VariableDeclaration(declaration) = builder.ancestry().parent_kind() else {
unreachable!();
};
let kind = declaration.kind;
let is_declare = declaration.declare;
let (mut includes, excludes) = match self.kind {
let (mut includes, excludes) = match kind {
VariableDeclarationKind::Const
| VariableDeclarationKind::Using
| VariableDeclarationKind::AwaitUsing => (
@@ -41,7 +42,7 @@ impl<'a> Binder<'a> for VariableDeclarator<'a> {
includes |= SymbolFlags::Ambient;
}
if self.kind.is_lexical() {
if kind.is_lexical() {
self.id.bound_names(&mut |ident| {
let symbol_id = builder.declare_symbol(ident.span, ident.name, includes, excludes);
ident.symbol_id.set(Some(symbol_id));
@@ -254,7 +254,7 @@ pub fn check_binding_identifier(ident: &BindingIdentifier, ctx: &SemanticBuilder
// * It is a Syntax Error if the BoundNames of BindingList contains "let".
for node_kind in ctx.ancestry().ancestor_kinds() {
match node_kind {
AstKind::VariableDeclarator(decl) => {
AstKind::VariableDeclaration(decl) => {
if decl.kind.is_lexical() {
ctx.error(diagnostics::invalid_let_declaration(
decl.kind.as_str(),
@@ -616,7 +616,10 @@ pub fn check_variable_declarator_redeclaration(
decl: &VariableDeclarator,
ctx: &SemanticBuilder<'_>,
) {
if decl.kind != VariableDeclarationKind::Var {
let AstKind::VariableDeclaration(declaration) = ctx.ancestry().parent_kind() else {
unreachable!();
};
if declaration.kind != VariableDeclarationKind::Var {
return;
}
+9 -4
View File
@@ -320,10 +320,15 @@ mod tests {
.get_binding(semantic.scoping().root_scope_id(), static_ident!("a"))
.unwrap();
let decl = semantic.symbol_declaration(top_level_a);
match decl.kind() {
AstKind::VariableDeclarator(decl) => {
assert_eq!(decl.kind, VariableDeclarationKind::Let);
let declarator_node = semantic.symbol_declaration(top_level_a);
match declarator_node.kind() {
AstKind::VariableDeclarator(_) => {
let AstKind::VariableDeclaration(declaration) =
semantic.nodes().parent_kind(declarator_node.id())
else {
unreachable!();
};
assert_eq!(declaration.kind, VariableDeclarationKind::Let);
}
kind => panic!("Expected VariableDeclarator for 'let', got {kind:?}"),
}
@@ -1012,7 +1012,6 @@ impl<'a> ArrowFunctionConverter<'a> {
);
VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
binding.create_binding_pattern(ctx),
None,
Some(init),
@@ -1189,7 +1188,6 @@ impl<'a> ArrowFunctionConverter<'a> {
Some(VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
arguments_var.create_binding_pattern(ctx),
None,
Some(init),
@@ -1250,7 +1248,6 @@ impl<'a> ArrowFunctionConverter<'a> {
Self::adjust_binding_scope(target_scope_id, &this_var, ctx);
let variable_declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
this_var.create_binding_pattern(ctx),
None,
init,
@@ -192,7 +192,7 @@ impl<'a> ModuleImportsStore<'a> {
let var_kind = VariableDeclarationKind::Var;
let decl = {
let init = Expression::new_call_expression(SPAN, callee, None, args, false, ctx);
let decl = VariableDeclarator::new(SPAN, var_kind, id, None, Some(init), false, ctx);
let decl = VariableDeclarator::new(SPAN, id, None, Some(init), false, ctx);
[decl]
};
Statement::new_variable_declaration(SPAN, var_kind, decl, false, ctx)
@@ -146,15 +146,7 @@ impl<'a> VarDeclarationsStore<'a> {
init: Option<Expression<'a>>,
ast: &AstBuilder<'a>,
) {
let declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
ident,
None,
init,
false,
ast,
);
let declarator = VariableDeclarator::new(SPAN, ident, None, init, false, ast);
self.insert_var_declarator(declarator, ast);
}
@@ -166,15 +158,7 @@ impl<'a> VarDeclarationsStore<'a> {
init: Option<Expression<'a>>,
ast: &AstBuilder<'a>,
) {
let declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Let,
ident,
None,
init,
false,
ast,
);
let declarator = VariableDeclarator::new(SPAN, ident, None, init, false, ast);
self.insert_let_declarator(declarator, ast);
}
@@ -1015,7 +1015,6 @@ impl<'a> LegacyDecorator<'a> {
);
let declarator = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Let,
binding.create_spanned_binding_pattern(binding_span, ctx),
None,
Some(initializer),
@@ -798,7 +798,6 @@ impl<'a> AsyncGeneratorExecutor<'a> {
let declarations = ArenaVec::from_value_in(
VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
bound_ident.create_binding_pattern(ctx),
None,
Some(init),
@@ -122,9 +122,10 @@ impl<'a> AsyncGeneratorFunctions<'a> {
let assignment_statement = match &mut stmt.left {
ForStatementLeft::VariableDeclaration(variable) => {
// for await (let i of test)
let kind = variable.kind;
let mut declarator = variable.declarations.pop().unwrap();
declarator.init = Some(step_value);
Statement::new_variable_declaration(SPAN, declarator.kind, [declarator], false, ctx)
Statement::new_variable_declaration(SPAN, kind, [declarator], false, ctx)
}
left @ match_assignment_target!(ForStatementLeft) => {
// for await (i of test), for await ({ i } of test)
@@ -228,7 +229,6 @@ impl<'a> AsyncGeneratorFunctions<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
iterator_abrupt_completion.create_binding_pattern(ctx),
None,
Some(Expression::new_boolean_literal(SPAN, false, ctx)),
@@ -243,7 +243,6 @@ impl<'a> AsyncGeneratorFunctions<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
iterator_had_error_key.create_binding_pattern(ctx),
None,
Some(Expression::new_boolean_literal(SPAN, false, ctx)),
@@ -258,7 +257,6 @@ impl<'a> AsyncGeneratorFunctions<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
iterator_error_key.create_binding_pattern(ctx),
None,
None,
@@ -284,7 +282,6 @@ impl<'a> AsyncGeneratorFunctions<'a> {
[
VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
iterator_key.create_binding_pattern(ctx),
None,
Some(iterator),
@@ -293,7 +290,6 @@ impl<'a> AsyncGeneratorFunctions<'a> {
),
VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
step_key.create_binding_pattern(ctx),
None,
None,
@@ -216,7 +216,7 @@ impl<'a> ObjectRestSpread<'a> {
let mut new_decls = vec![];
if let Some(id) = reference_builder.binding.take() {
new_decls.push(VariableDeclarator::new(SPAN, state.kind, id, None, None, false, ctx));
new_decls.push(VariableDeclarator::new(SPAN, id, None, None, false, ctx));
}
let data = Self::walk_assignment_target(&mut assign_expr.left, &mut new_decls, state, ctx);
@@ -457,8 +457,7 @@ impl<'a> ObjectRestSpread<'a> {
}
let bound_identifier = ctx.generate_uid_in_current_hoist_scope("ref");
let id = bound_identifier.create_binding_pattern(ctx);
let kind = VariableDeclarationKind::Var;
decls.push(VariableDeclarator::new(SPAN, kind, id, None, None, false, ctx));
decls.push(VariableDeclarator::new(SPAN, id, None, None, false, ctx));
exprs.push(Expression::new_assignment_expression(
SPAN,
AssignmentOperator::Assign,
@@ -636,7 +635,7 @@ impl<'a> ObjectRestSpread<'a> {
if decl.kind.is_var() { ctx.current_hoist_scope_id() } else { scope_id };
Self::replace_rest_element(
declarator.kind,
decl.kind,
&mut declarator.id,
&mut block.body,
old_scope_id,
@@ -674,10 +673,8 @@ impl<'a> ObjectRestSpread<'a> {
let bound_identifier = ctx.generate_uid("ref", ctx.current_hoist_scope_id(), flags);
let id = bound_identifier.create_binding_pattern(ctx);
let kind = VariableDeclarationKind::Var;
let declarations = ArenaVec::from_value_in(
VariableDeclarator::new(SPAN, kind, id, None, None, false, ctx),
ctx,
);
let declarations =
ArenaVec::from_value_in(VariableDeclarator::new(SPAN, id, None, None, false, ctx), ctx);
let decl = VariableDeclaration::boxed(SPAN, kind, declarations, false, ctx);
*left = ForStatementLeft::VariableDeclaration(decl);
Self::try_replace_statement_with_block(body, scope_id, ctx);
@@ -799,7 +796,7 @@ impl<'a> ObjectRestSpread<'a> {
});
let init = bound_identifier.create_read_expression(ctx);
let declarations = ArenaVec::from_value_in(
VariableDeclarator::new(SPAN, kind, id, None, Some(init), false, ctx),
VariableDeclarator::new(SPAN, id, None, Some(init), false, ctx),
ctx,
);
VariableDeclaration::boxed(SPAN, kind, declarations, false, ctx)
@@ -819,7 +816,7 @@ impl<'a> ObjectRestSpread<'a> {
if variable_declarator.init.is_some()
&& Self::has_nested_object_rest(&variable_declarator.id)
{
let decls = self.transform_variable_declarator(variable_declarator, ctx);
let decls = self.transform_variable_declarator(variable_declarator, decl.kind, ctx);
new_decls.push((i, decls));
}
}
@@ -836,6 +833,7 @@ impl<'a> ObjectRestSpread<'a> {
fn transform_variable_declarator(
&mut self,
decl: &mut VariableDeclarator<'a>,
kind: VariableDeclarationKind,
ctx: &mut TraverseCtx<'a>,
) -> ArenaVec<'a, VariableDeclarator<'a>> {
// It is syntax error or inside for loop if missing initializer in destructuring pattern.
@@ -845,7 +843,7 @@ impl<'a> ObjectRestSpread<'a> {
// `for (var {...x} = {};;);` and `for (let {...x} = {};;);`
// TODO: improve this by getting the value only once.
let mut scope_id = ctx.current_scope_id();
let mut symbol_flags = kind_to_symbol_flags(decl.kind);
let mut symbol_flags = kind_to_symbol_flags(kind);
let symbols = ctx.scoping();
decl.id.bound_names(&mut |ident| {
let symbol_id = ident.symbol_id();
@@ -853,7 +851,7 @@ impl<'a> ObjectRestSpread<'a> {
symbol_flags.insert(symbols.symbol_flags(symbol_id));
});
let state = State::new(decl.kind, symbol_flags, scope_id);
let state = State::new(kind, symbol_flags, scope_id);
let mut new_decls = vec![];
let mut reference_builder = ReferenceBuilder::new(init, symbol_flags, scope_id, false, ctx);
@@ -863,7 +861,6 @@ impl<'a> ObjectRestSpread<'a> {
if let Some(id) = reference_builder.binding.take() {
let decl = VariableDeclarator::new(
SPAN,
state.kind,
id,
None,
Some(reference_builder.create_read_expression(ctx)),
@@ -919,15 +916,8 @@ impl<'a> ObjectRestSpread<'a> {
ctx,
);
if let BindingPatternOrAssignmentTarget::BindingPattern(lhs) = lhs {
let decl = VariableDeclarator::new(
lhs.span(),
decl.kind,
lhs,
None,
Some(rhs),
false,
ctx,
);
let decl =
VariableDeclarator::new(lhs.span(), lhs, None, Some(rhs), false, ctx);
temp_decls.push(decl);
}
}
@@ -945,7 +935,6 @@ impl<'a> ObjectRestSpread<'a> {
mem::swap(&mut binding_pattern, &mut decl.id);
let decl = VariableDeclarator::new(
decl.span,
decl.kind,
binding_pattern,
None,
Some(reference_builder.create_read_expression(ctx)),
@@ -989,10 +978,9 @@ impl<'a> ObjectRestSpread<'a> {
let id = mem::replace(pat, bound_identifier.create_binding_pattern(ctx));
let init = bound_identifier.create_read_expression(ctx);
let mut decl =
VariableDeclarator::new(SPAN, state.kind, id, None, Some(init), false, ctx);
let mut decl = VariableDeclarator::new(SPAN, id, None, Some(init), false, ctx);
let mut decls = self
.transform_variable_declarator(&mut decl, ctx)
.transform_variable_declarator(&mut decl, state.kind, ctx)
.into_iter()
.collect::<Vec<_>>();
decls.extend(data);
@@ -1058,15 +1046,7 @@ impl<'a> ObjectRestSpread<'a> {
let p = bound_identifier.create_binding_pattern(ctx);
let mut lhs = bound_identifier.create_read_expression(ctx);
mem::swap(&mut lhs, expr);
new_decls.push(VariableDeclarator::new(
SPAN,
state.kind,
p,
None,
Some(lhs),
false,
ctx,
));
new_decls.push(VariableDeclarator::new(SPAN, p, None, Some(lhs), false, ctx));
Some(ArrayExpressionElement::from(bound_identifier.create_read_expression(ctx)))
}
}
@@ -1160,10 +1140,8 @@ impl<'a> SpreadPair<'a> {
"excluded",
SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable,
);
let kind = VariableDeclarationKind::Const;
let declarator = VariableDeclarator::new(
SPAN,
kind,
bound_identifier.create_binding_pattern(ctx),
None,
Some(key_expression),
@@ -341,7 +341,6 @@ impl<'a> ClassProperties<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
super_binding.create_binding_pattern(ctx),
None,
Some(super_func),
@@ -18,7 +18,6 @@ pub(super) fn create_variable_declaration<'a>(
let kind = VariableDeclarationKind::Var;
let declarator = VariableDeclarator::new(
SPAN,
kind,
binding.create_binding_pattern(ctx),
None,
Some(init),
@@ -84,7 +84,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
decl.kind = VariableDeclarationKind::Const;
let variable_declarator = decl.declarations.first_mut().unwrap();
variable_declarator.kind = VariableDeclarationKind::Const;
let variable_declarator_binding_ident =
variable_declarator.id.get_binding_identifier().unwrap();
@@ -107,7 +106,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
variable_decl_kind,
[VariableDeclarator::new(
SPAN,
variable_decl_kind,
binding_pattern,
None,
Some(temp_id.create_read_expression(ctx)),
@@ -432,7 +430,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
span,
VariableDeclarationKind::Var,
var_id.create_spanned_binding_pattern(span, ctx),
None,
Some(expr),
@@ -524,10 +521,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
var_decl.kind = VariableDeclarationKind::Var;
let mut export_specifiers = ArenaVec::new_in(ctx);
for decl in &mut var_decl.declarations {
decl.kind = VariableDeclarationKind::Var;
}
var_decl.bound_names(&mut |ident| {
*ctx.scoping_mut().symbol_flags_mut(ident.symbol_id()) =
SymbolFlags::FunctionScopedVariable;
@@ -570,7 +563,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
var_declaration.kind = VariableDeclarationKind::Var;
for decl in &mut var_declaration.declarations {
decl.kind = VariableDeclarationKind::Var;
decl.id.bound_names(&mut |c| {
*ctx.scoping_mut().symbol_flags_mut(c.symbol_id()) =
SymbolFlags::FunctionScopedVariable;
@@ -749,7 +741,6 @@ impl<'a> ExplicitResourceManagement<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
using_ctx.create_binding_pattern(ctx),
None,
Some(Expression::new_call_expression(
@@ -884,7 +875,6 @@ impl<'a> ExplicitResourceManagement<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
using_ctx.create_binding_pattern(ctx),
None,
Some(Expression::new_call_expression(SPAN, callee, None, [], false, ctx)),
@@ -1015,7 +1005,6 @@ impl<'a> ExplicitResourceManagement<'a> {
VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
binding.create_spanned_binding_pattern(original_span, ctx),
None,
Some(class_expr),
+1 -9
View File
@@ -195,15 +195,7 @@ impl<'a> JsxSource<'a> {
let id = filename_var.create_binding_pattern(ctx);
let source_path = Str::from_str_in(&ctx.state.source_path.to_string_lossy(), ctx);
let init = Expression::new_string_literal(SPAN, source_path, None, ctx);
let decl = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
id,
None,
Some(init),
false,
ctx,
);
let decl = VariableDeclarator::new(SPAN, id, None, Some(init), false, ctx);
Some(decl)
}
@@ -177,7 +177,6 @@ impl<'a> Traverse<'a, TransformState<'a>> for ReactRefresh<'a> {
let calls = self.registrations.iter().map(|(binding, persistent_id)| {
variable_declarator_items.push(VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
binding.create_binding_pattern(ctx),
None,
None,
@@ -231,7 +231,6 @@ impl<'a> TaggedTemplateTransform {
let variable = VariableDeclarator::new(
SPAN,
VariableDeclarationKind::Var,
binding.create_binding_pattern(ctx),
None,
None,
@@ -295,15 +295,8 @@ impl<'a> TypeScriptEnum {
enum_symbol_id,
ctx,
);
let decl = VariableDeclarator::new(
span,
kind,
binding,
None,
Some(call_expression),
false,
ctx,
);
let decl =
VariableDeclarator::new(span, binding, None, Some(call_expression), false, ctx);
[decl]
};
let variable_declaration =
@@ -177,7 +177,7 @@ impl<'a> TypeScriptModule {
)
}
};
let decl = VariableDeclarator::new(SPAN, kind, binding, None, Some(init), false, ctx);
let decl = VariableDeclarator::new(SPAN, binding, None, Some(init), false, ctx);
Some(Declaration::new_variable_declaration(SPAN, kind, [decl], false, ctx))
}
@@ -254,11 +254,11 @@ impl<'a> TypeScriptNamespace {
}
}
Declaration::VariableDeclaration(var_decl) => {
var_decl.declarations.iter().for_each(|decl| {
if !decl.kind.is_const() {
if !var_decl.kind.is_const() {
var_decl.declarations.iter().for_each(|decl| {
ctx.state.error(namespace_exporting_non_const(decl.span));
}
});
});
}
let stmts =
Self::handle_variable_declaration(var_decl, &uid_binding, ctx);
new_stmts.extend(stmts);
@@ -338,7 +338,7 @@ impl<'a> TypeScriptNamespace {
let kind = VariableDeclarationKind::Let;
let decl = {
let pattern = binding.create_spanned_binding_pattern(binding_span, ctx);
VariableDeclarator::new(span, kind, pattern, None, None, false, ctx)
VariableDeclarator::new(span, pattern, None, None, false, ctx)
};
Declaration::new_variable_declaration(span, kind, [decl], false, ctx)
}
@@ -763,7 +763,7 @@ impl<'a> ModuleRunnerTransform<'a> {
let init = Expression::new_await_expression(SPAN, call, ctx);
let kind = VariableDeclarationKind::Const;
let declarator = VariableDeclarator::new(SPAN, kind, pattern, None, Some(init), false, ctx);
let declarator = VariableDeclarator::new(SPAN, pattern, None, Some(init), false, ctx);
let declaration =
Declaration::new_variable_declaration(span, kind, [declarator], false, ctx);
Statement::from(declaration)
@@ -888,8 +888,7 @@ impl<'a> ModuleRunnerTransform<'a> {
);
let pattern = binding.create_binding_pattern(ctx);
let kind = VariableDeclarationKind::Const;
let declarator =
VariableDeclarator::new(SPAN, kind, pattern, None, Some(right), false, ctx);
let declarator = VariableDeclarator::new(SPAN, pattern, None, Some(right), false, ctx);
let declaration =
Declaration::new_variable_declaration(span, kind, [declarator], false, ctx);
Statement::from(declaration)
@@ -5211,7 +5211,6 @@ impl<'a, 't> GetAddress for VariableDeclarationWithoutDeclarations<'a, 't> {
pub(crate) const OFFSET_VARIABLE_DECLARATOR_NODE_ID: usize =
offset_of!(VariableDeclarator, node_id);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_SPAN: usize = offset_of!(VariableDeclarator, span);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_KIND: usize = offset_of!(VariableDeclarator, kind);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_ID: usize = offset_of!(VariableDeclarator, id);
pub(crate) const OFFSET_VARIABLE_DECLARATOR_TYPE_ANNOTATION: usize =
offset_of!(VariableDeclarator, type_annotation);
@@ -5239,14 +5238,6 @@ impl<'a, 't> VariableDeclaratorWithoutId<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn type_annotation(self) -> &'t Option<ArenaBox<'a, TSTypeAnnotation<'a>>> {
unsafe {
@@ -5296,14 +5287,6 @@ impl<'a, 't> VariableDeclaratorWithoutTypeAnnotation<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn id(self) -> &'t BindingPattern<'a> {
unsafe {
@@ -5353,14 +5336,6 @@ impl<'a, 't> VariableDeclaratorWithoutInit<'a, 't> {
unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_SPAN) as *const Span) }
}
#[inline]
pub fn kind(self) -> &'t VariableDeclarationKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATOR_KIND)
as *const VariableDeclarationKind)
}
}
#[inline]
pub fn id(self) -> &'t BindingPattern<'a> {
unsafe {
@@ -1365,7 +1365,7 @@ function deserializeVariableDeclarator(pos) {
type: "VariableDeclarator",
id: null,
init: null,
definite: deserializeBool(pos + 13),
definite: deserializeBool(pos + 12),
start: deserializeI32(pos),
end: deserializeI32(pos + 4),
},
@@ -1488,7 +1488,7 @@ function deserializeVariableDeclarator(pos) {
type: "VariableDeclarator",
id: null,
init: null,
definite: deserializeBool(pos + 13),
definite: deserializeBool(pos + 12),
start: deserializeI32(pos),
end: deserializeI32(pos + 4),
parent,
@@ -1493,7 +1493,7 @@ function deserializeVariableDeclarator(pos) {
type: "VariableDeclarator",
id: null,
init: null,
definite: deserializeBool(pos + 13),
definite: deserializeBool(pos + 12),
start: (start = deserializeI32(pos)),
end: (end = deserializeI32(pos + 4)),
range: [start, end],
@@ -1615,7 +1615,7 @@ function deserializeVariableDeclarator(pos) {
type: "VariableDeclarator",
id: null,
init: null,
definite: deserializeBool(pos + 13),
definite: deserializeBool(pos + 12),
start: (start = deserializeI32(pos)),
end: (end = deserializeI32(pos + 4)),
range: [start, end],
@@ -3000,7 +3000,7 @@ export class VariableDeclarator {
get definite() {
const internal = this.#internal;
return constructBool(internal.pos + 13, internal.ast);
return constructBool(internal.pos + 12, internal.ast);
}
toJSON() {