Skip to content

tsEnumIsMutable: enum member initializers reading another enum still fold to compile-time values #12151

Description

Describe the bug

With jsc.transform.tsEnumIsMutable: true, reads of non-const enum members are deliberately kept as runtime reads. But an enum member initializer that reads another enum is still folded to the compile-time value by the collection pass, so within one file the option is honored for expression reads and ignored inside enum initializers.

Input code

enum D { A = 1 }
(D as any).A = 5;
enum F { P = D.A, Q }
console.log(D.A, F.P);

with { "jsc": { "transform": { "tsEnumIsMutable": true } } }.

Actual behavior (@swc/core 1.16.1)

var D = /*#__PURE__*/ function(D) {
    D[D["A"] = 1] = "A";
    return D;
}(D || {});
D.A = 5;
var F = /*#__PURE__*/ function(F) {
    F[F["P"] = 1] = "P";
    F[F["Q"] = 2] = "Q";
    return F;
}(F || {});
console.log(D.A, F.P);

console.log(D.A, ...) correctly stays a runtime read and prints 5 — but F.P was folded to 1, even though D.A is 5 by the time F initializes. The emitted file contradicts itself about whether D is mutable.

Expected behavior

Under this option, F.P = D.A should stay a runtime read (F[F["P"] = D.A] = "P"), consistent with how every other read of a non-const enum is treated. (tsc has no equivalent option, so the reference here is the option's own contract, not tsc emit.)

Mechanism: enter_expr_for_inline_enum checks ts_enum_is_mutable && !const_enum.contains(&enum_id) before inlining, but member evaluation in the collection pass resolves through enum_record without consulting the option. The const-initializer path was given the same guard in #12101 (ts_enum_is_mutable_true covers it); the direct member-initializer path predates that PR and is unchanged.

Noted in the #12101 review, reporting separately as promised there.

Version: @swc/core 1.16.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions