Skip to content

Commit

Permalink
Roll back outer expression skipping
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbranch committed Mar 27, 2024
1 parent 79b5ff1 commit 392976d
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1923,7 +1923,7 @@ export function transformTypeScript(context: TransformationContext) {
),
valueExpression,
);
const outerAssignment = evaluated?.isSyntacticallyString ?
const outerAssignment = typeof evaluated?.value === "string" || evaluated?.isSyntacticallyString ?
innerAssignment :
factory.createAssignment(
factory.createElementAccessExpression(
Expand Down
17 changes: 15 additions & 2 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10661,7 +10661,19 @@ export function createEvaluator({ evaluateElementAccessExpression, evaluateEntit
function evaluate(expr: Expression, location?: Declaration): EvaluatorResult {
let isSyntacticallyString = false;
let resolvedOtherFiles = false;
expr = skipOuterExpressions(expr);
// It's unclear when/whether we should consider skipping other kinds of outer expressions.
// Type assertions intentionally break evaluation when evaluating literal types, such as:
// type T = `one ${"two" as any} three`; // string
// But it's less clear whether such an assertion should break enum member evaluation:
// enum E {
// A = "one" as any
// }
// SatisfiesExpressions and non-null assertions seem to have even less reason to break
// emitting enum members as literals. However, these expressions also break Babel's
// evaluation (but not esbuild's), and the isolatedModules errors we give depend on
// our evaluation results, so we're currently being conservative so as to issue errors
// on code that might break Babel.
expr = skipParentheses(expr);
switch (expr.kind) {
case SyntaxKind.PrefixUnaryExpression:
const result = evaluate((expr as PrefixUnaryExpression).operand, location);
Expand All @@ -10680,8 +10692,8 @@ export function createEvaluator({ evaluateElementAccessExpression, evaluateEntit
case SyntaxKind.BinaryExpression: {
const left = evaluate((expr as BinaryExpression).left, location);
const right = evaluate((expr as BinaryExpression).right, location);
isSyntacticallyString = (left.isSyntacticallyString || right.isSyntacticallyString) && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken;
resolvedOtherFiles = left.resolvedOtherFiles || right.resolvedOtherFiles;
isSyntacticallyString = left.isSyntacticallyString || right.isSyntacticallyString;
if (typeof left.value === "number" && typeof right.value === "number") {
switch ((expr as BinaryExpression).operatorToken.kind) {
case SyntaxKind.BarToken:
Expand Down Expand Up @@ -10721,6 +10733,7 @@ export function createEvaluator({ evaluateElementAccessExpression, evaluateEntit
resolvedOtherFiles,
);
}

break;
}
case SyntaxKind.StringLiteral:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
computedEnumMemberSyntacticallyString.ts(4,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(5,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(6,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(7,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(8,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(10,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(11,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(14,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(9,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(12,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.


==== computedEnumMemberSyntacticallyString.ts (8 errors) ====
==== computedEnumMemberSyntacticallyString.ts (6 errors) ====
const BAR = 2..toFixed(0);

enum Foo {
Expand All @@ -21,12 +19,6 @@ computedEnumMemberSyntacticallyString.ts(14,9): error TS18033: Type 'string' is
C = (`${BAR}`),
~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
D = (`${BAR}}`) as string,
~~~~~~~~~~~~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
E = `${BAR}`!,
~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.

F = BAR,
~~~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ enum Foo {
A = `${BAR}`,
B = "2" + BAR,
C = (`${BAR}`),
D = (`${BAR}}`) as string,
E = `${BAR}`!,

F = BAR,
G = 2 + BAR,
Expand All @@ -26,8 +24,6 @@ var Foo;
Foo["A"] = `${BAR}`;
Foo["B"] = "2" + BAR;
Foo["C"] = (`${BAR}`);
Foo["D"] = (`${BAR}}`);
Foo["E"] = `${BAR}`;
Foo[Foo["F"] = BAR] = "F";
Foo[Foo["G"] = 2 + BAR] = "G";
Foo["H"] = Foo.A;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
computedEnumMemberSyntacticallyString.ts(4,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(5,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(6,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(7,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(8,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(10,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(11,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(14,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(9,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
computedEnumMemberSyntacticallyString.ts(12,9): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.


==== computedEnumMemberSyntacticallyString.ts (8 errors) ====
==== computedEnumMemberSyntacticallyString.ts (6 errors) ====
const BAR = 2..toFixed(0);

enum Foo {
Expand All @@ -21,12 +19,6 @@ computedEnumMemberSyntacticallyString.ts(14,9): error TS18033: Type 'string' is
C = (`${BAR}`),
~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
D = (`${BAR}}`) as string,
~~~~~~~~~~~~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
E = `${BAR}`!,
~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.

F = BAR,
~~~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ enum Foo {
A = `${BAR}`,
B = "2" + BAR,
C = (`${BAR}`),
D = (`${BAR}}`) as string,
E = `${BAR}`!,

F = BAR,
G = 2 + BAR,
Expand All @@ -26,8 +24,6 @@ var Foo;
Foo["A"] = `${BAR}`;
Foo["B"] = "2" + BAR;
Foo["C"] = (`${BAR}`);
Foo["D"] = (`${BAR}}`);
Foo["E"] = `${BAR}`;
Foo[Foo["F"] = BAR] = "F";
Foo[Foo["G"] = 2 + BAR] = "G";
Foo["H"] = Foo.A;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
foo.ts(11,8): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
foo.ts(12,8): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.


==== ./foo.ts (2 errors) ====
import { BAR } from './bar';
const LOCAL = 'LOCAL';

enum Foo {
A = `${BAR}`,

B = LOCAL,
C = B,
D = C + 'BAR',

E1 = (`${BAR}`) as string, // We could recognize these,
~~~~~~~~~~~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
E2 = `${BAR}`!, // but Babel doesn't
~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.

F = BAR,
G = 2 + BAR,

H = A,
I = H + BAR,
J = H
}

==== ./bar.ts (0 errors) ====
export const BAR = 'bar';
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ enum Foo {
C = B,
D = C + 'BAR',

E1 = (`${BAR}`) as string, // We could recognize these,
E2 = `${BAR}`!, // but Babel doesn't

F = BAR,
G = 2 + BAR,

Expand All @@ -33,8 +36,10 @@ var Foo;
Foo["B"] = "LOCAL";
Foo["C"] = "LOCAL";
Foo["D"] = "LOCALBAR";
Foo[Foo["F"] = "bar"] = "F";
Foo[Foo["G"] = "2bar"] = "G";
Foo[Foo["E1"] = (`${BAR}`)] = "E1";
Foo[Foo["E2"] = `${BAR}`] = "E2";
Foo["F"] = "bar";
Foo["G"] = "2bar";
Foo["H"] = "bar";
Foo["I"] = "barbar";
Foo["J"] = "bar";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
foo.ts(11,7): error TS18055: 'Foo.F' has a string type, but must have syntactically recognizable string syntax when 'isolatedModules' is enabled.
foo.ts(12,7): error TS18055: 'Foo.G' has a string type, but must have syntactically recognizable string syntax when 'isolatedModules' is enabled.
foo.ts(11,8): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
foo.ts(12,8): error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
foo.ts(14,7): error TS18055: 'Foo.F' has a string type, but must have syntactically recognizable string syntax when 'isolatedModules' is enabled.
foo.ts(15,7): error TS18055: 'Foo.G' has a string type, but must have syntactically recognizable string syntax when 'isolatedModules' is enabled.


==== ./foo.ts (2 errors) ====
==== ./foo.ts (4 errors) ====
import { BAR } from './bar';
const LOCAL = 'LOCAL';

Expand All @@ -13,6 +15,13 @@ foo.ts(12,7): error TS18055: 'Foo.G' has a string type, but must have syntactica
C = B,
D = C + 'BAR',

E1 = (`${BAR}`) as string, // We could recognize these,
~~~~~~~~~~~~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.
E2 = `${BAR}`!, // but Babel doesn't
~~~~~~~~~
!!! error TS18033: Type 'string' is not assignable to type 'number' as required for computed enum member values.

F = BAR,
~~~
!!! error TS18055: 'Foo.F' has a string type, but must have syntactically recognizable string syntax when 'isolatedModules' is enabled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ enum Foo {
C = B,
D = C + 'BAR',

E1 = (`${BAR}`) as string, // We could recognize these,
E2 = `${BAR}`!, // but Babel doesn't

F = BAR,
G = 2 + BAR,

Expand All @@ -33,8 +36,10 @@ var Foo;
Foo["B"] = "LOCAL";
Foo["C"] = "LOCAL";
Foo["D"] = "LOCALBAR";
Foo[Foo["F"] = "bar"] = "F";
Foo[Foo["G"] = "2bar"] = "G";
Foo[Foo["E1"] = (`${BAR}`)] = "E1";
Foo[Foo["E2"] = `${BAR}`] = "E2";
Foo["F"] = "bar";
Foo["G"] = "2bar";
Foo["H"] = "bar";
Foo["I"] = "barbar";
Foo["J"] = "bar";
Expand Down
2 changes: 0 additions & 2 deletions tests/cases/compiler/computedEnumMemberSyntacticallyString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ enum Foo {
A = `${BAR}`,
B = "2" + BAR,
C = (`${BAR}`),
D = (`${BAR}}`) as string,
E = `${BAR}`!,

F = BAR,
G = 2 + BAR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ enum Foo {
C = B,
D = C + 'BAR',

E1 = (`${BAR}`) as string, // We could recognize these,
E2 = `${BAR}`!, // but Babel doesn't

F = BAR,
G = 2 + BAR,

Expand Down

0 comments on commit 392976d

Please sign in to comment.