Skip to content

Commit 85df23f

Browse files
committed
Make loop errors diagnostics
1 parent 2b9c2a6 commit 85df23f

5 files changed

Lines changed: 25 additions & 33 deletions

File tree

src/transformation/utils/diagnostics.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,7 @@ export const unsupportedForTarget = createDiagnosticFactory(
118118
export const unsupportedProperty = createDiagnosticFactory(
119119
(parentName: string, property: string) => `${parentName}.${property} is unsupported.`
120120
);
121+
122+
export const forOfUnsupportedObjectDestructuring = createDiagnosticFactory(
123+
`Unsupported object destructuring in for...of statement.`
124+
);

src/transformation/utils/errors.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@ export class TranspileError extends Error {
1010
export const InvalidDecoratorContext = (node: ts.Node) =>
1111
new TranspileError(`Decorator function cannot have 'this: void'.`, node);
1212

13-
export const MissingForOfVariables = (node: ts.Node) =>
14-
new TranspileError("Transpiled ForOf variable declaration list contains no declarations.", node);
15-
16-
export const UnsupportedForInVariable = (node: ts.Node) =>
17-
new TranspileError(`Unsupported for-in variable kind.`, node);
18-
1913
export const UndefinedScope = () => new Error("Expected to pop a scope, but found undefined.");
2014

2115
export const UnresolvableRequirePath = (node: ts.Node, reason: string, path?: string) =>
@@ -28,9 +22,6 @@ export const ReferencedBeforeDeclaration = (node: ts.Identifier) =>
2822
node
2923
);
3024

31-
export const UnsupportedObjectDestructuringInForOf = (node: ts.Node) =>
32-
new TranspileError(`Unsupported object destructuring in for...of statement.`, node);
33-
3425
export const InvalidAmbientIdentifierName = (node: ts.Identifier) =>
3526
new TranspileError(
3627
`Invalid ambient identifier name "${node.text}". Ambient identifiers must be valid lua identifiers.`,

src/transformation/visitors/loops/for-in.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as ts from "typescript";
22
import * as lua from "../../../LuaAST";
33
import { FunctionVisitor } from "../../context";
44
import { forbiddenForIn } from "../../utils/diagnostics";
5-
import { UnsupportedForInVariable } from "../../utils/errors";
65
import { isArrayType } from "../../utils/typescript";
76
import { transformIdentifier } from "../identifier";
87
import { transformLoopBody } from "./body";
@@ -38,8 +37,8 @@ export const transformForInStatement: FunctionVisitor<ts.ForInStatement> = (stat
3837
);
3938
body.statements.unshift(initializer);
4039
} else {
41-
// This should never occur
42-
throw UnsupportedForInVariable(statement.initializer);
40+
// TODO:
41+
throw new Error(`Unsupported for...in variable kind: ${ts.SyntaxKind[statement.initializer.kind]}.`);
4342
}
4443

4544
return lua.createForInStatement(body, [iterationVariable], [pairsCall], statement);

src/transformation/visitors/loops/for-of.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import * as lua from "../../../LuaAST";
33
import { assert, cast, castEach } from "../../../utils";
44
import { FunctionVisitor, TransformationContext } from "../../context";
55
import { AnnotationKind, getTypeAnnotations, isForRangeType, isLuaIteratorType } from "../../utils/annotations";
6-
import { invalidForRangeCall, luaIteratorForbiddenUsage } from "../../utils/diagnostics";
7-
import { MissingForOfVariables, UnsupportedObjectDestructuringInForOf } from "../../utils/errors";
6+
import {
7+
forOfUnsupportedObjectDestructuring,
8+
invalidForRangeCall,
9+
luaIteratorForbiddenUsage,
10+
} from "../../utils/diagnostics";
811
import { createUnpackCall } from "../../utils/lua-ast";
912
import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
1013
import { isArrayType, isNumberType } from "../../utils/typescript";
@@ -28,19 +31,17 @@ function transformForOfInitializer(
2831

2932
expression = createUnpackCall(context, expression, initializer);
3033
} else if (ts.isObjectBindingPattern(initializer.declarations[0].name)) {
31-
throw UnsupportedObjectDestructuringInForOf(initializer);
34+
context.diagnostics.push(forOfUnsupportedObjectDestructuring(initializer));
35+
return;
3236
}
3337

34-
const variableStatements = transformVariableDeclaration(context, initializer.declarations[0]);
35-
if (variableStatements[0]) {
36-
// we can safely assume that for vars are not exported and therefore declarationstatenents
37-
return lua.createVariableDeclarationStatement(
38-
(variableStatements[0] as lua.VariableDeclarationStatement).left,
39-
expression
40-
);
41-
} else {
42-
throw MissingForOfVariables(initializer);
43-
}
38+
// we can safely assume that for vars are not exported and therefore VariableDeclarationStatement's
39+
const assignmentStatement = cast(
40+
transformVariableDeclaration(context, initializer.declarations[0])[0],
41+
lua.isVariableDeclarationStatement
42+
);
43+
44+
return lua.createVariableDeclarationStatement(assignmentStatement.left, expression);
4445
} else {
4546
// Assignment to existing variable
4647
let variables: lua.AssignmentLeftHandSideExpression | lua.AssignmentLeftHandSideExpression[];
@@ -56,7 +57,8 @@ function transformForOfInitializer(
5657
return undefined;
5758
}
5859
} else if (ts.isObjectLiteralExpression(initializer)) {
59-
throw UnsupportedObjectDestructuringInForOf(initializer);
60+
context.diagnostics.push(forOfUnsupportedObjectDestructuring(initializer));
61+
return;
6062
} else {
6163
variables = cast(context.transformExpression(initializer), lua.isAssignmentLeftHandSideExpression);
6264
}

test/unit/loops.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as ts from "typescript";
22
import * as tstl from "../../src";
3-
import { UnsupportedObjectDestructuringInForOf } from "../../src/transformation/utils/errors";
43
import * as util from "../util";
54

65
test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("while (%p)", ({ inp, expected }) => {
@@ -487,14 +486,11 @@ test.each([
487486
{ initializer: "{a, b}", vars: "let a: string, b: string;" },
488487
{ initializer: "{a: c, b: d}", vars: "let c: string, d: string;" },
489488
])("forof object destructuring (%p)", ({ initializer, vars }) => {
490-
const code = `
489+
util.testModule`
491490
declare const arr: {a: string, b: string}[];
492491
${vars}
493-
for (${initializer} of arr) {}`;
494-
495-
expect(() => util.transpileString(code)).toThrow(
496-
UnsupportedObjectDestructuringInForOf(ts.createEmptyStatement()).message
497-
);
492+
for (${initializer} of arr) {}
493+
`.expectDiagnosticsToMatchSnapshot();
498494
});
499495

500496
test("forof with array typed as iterable", () => {

0 commit comments

Comments
 (0)