oxc-project / oxc-project/backlog

AST: Represent for-in/of Declaration Heads with a Single Declarator

Open
#236 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
No language data
Stars
7
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Summary

Replace the general VariableDeclaration used in for-in and for-of left-hand sides with a declaration-head node that contains exactly one VariableDeclarator.

The grammar permits one binding in these loop heads. A vector is appropriate for ordinary variable statements and classic for initializers, but it makes zero or multiple declarators representable in for-in/for-of.

Motivation

Valid loop declaration heads contain one declarator:

for (const key in object) {}
for (let value of iterable) {}
for await (const value of asyncIterable) {}
for (const [key, value] of entries) {}

The current ForStatementLeft::VariableDeclaration reuses:

pub declarations: Vec<'a, VariableDeclarator<'a>>

It can represent invalid states such as:

  • declarations.is_empty();
  • two or more declarators in one for-in/for-of head;
  • consumers indexing declarations[0] based on a parser-maintained convention.

The single binding may itself be a destructuring pattern, so cardinality cannot be inferred by counting identifiers. It should be encoded at the declarator level.

Initializer legality is related but distinct. JavaScript's legacy var grammar, TypeScript recovery, and early errors may require preserving an initializer on the single declarator. This issue should enforce cardinality without prematurely encoding every contextual initializer rule.

Current AST Shape

pub struct ForInStatement<'a> {
    pub left: ForStatementLeft<'a>,
    pub right: Expression<'a>,
    pub body: Statement<'a>,
    // ...
}

pub struct ForOfStatement<'a> {
    pub r#await: bool,
    pub left: ForStatementLeft<'a>,
    pub right: Expression<'a>,
    pub body: Statement<'a>,
    // ...
}

pub enum ForStatementLeft<'a> {
    VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 16,
    INHERIT(AssignmentTarget<'a>),
}

pub struct VariableDeclaration<'a> {
    pub kind: VariableDeclarationKind,
    pub declarations: Vec<'a, VariableDeclarator<'a>>,
    pub declare: bool,
    // ...
}

declare and a general declaration list are not meaningful properties of a loop declaration head.

Proposed AST Shape

pub enum ForStatementLeft<'a> {
    VariableDeclaration(Box<'a, ForStatementDeclaration<'a>>) = 16,
    INHERIT(AssignmentTarget<'a>),
}

pub struct ForStatementDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub kind: VariableDeclarationKind,
    pub declaration: VariableDeclarator<'a>,
}

The singular declaration retains the existing binding pattern, optional TypeScript annotation, and optional initializer while parser/semantic checks decide which combinations are permitted for for-in, for-of, for await, var, let, and const.

Syntax Mapping

Source form Current representation Proposed representation
for (const x of xs) {} General declaration with one-element vector ForStatementDeclaration { kind: Const, declaration: x }
for (let k in obj) {} General declaration with one-element vector ForStatementDeclaration { kind: Let, declaration: k }
for (const [k, v] of entries) {} One vector item containing a pattern One singular declarator containing the same pattern
for (x of xs) {} Inherited assignment target Unchanged assignment-target variant
Zero or multiple declaration items Constructible through builders/mutation Not representable

Guaranteed Invariants

  • Every declaration-form for-in/for-of head contains exactly one declarator.
  • Destructuring remains a single declarator regardless of bound-name count.
  • Loop declaration heads cannot carry a declaration-list-only declare flag.
  • ESTree compatibility is preserved with a synthesized one-element array.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating ForStatementLeft, VariableDeclaration, and the parser and consumer entry points that construct or inspect declaration-form for-in/for-of heads. Trace how destructuring, TypeScript annotations, initializers, and ESTree compatibility are handled; the work is done when these heads enforce one declarator without exposing declaration-list-only state.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.