Skip to content

Commit a617faf

Browse files
authored
Fixed invalid switch statement lua when default was not the last case (#1016)
* Made switch default case always last * Actually fixed switch statement this time * Added extra default fallthrough test
1 parent d86ef92 commit a617faf

File tree

4 files changed

+369
-300
lines changed

4 files changed

+369
-300
lines changed

src/transformation/visitors/switch.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ export const transformSwitchStatement: FunctionVisitor<ts.SwitchStatement> = (st
1818

1919
let statements: lua.Statement[] = [];
2020

21-
const caseClauses = statement.caseBlock.clauses.filter(ts.isCaseClause);
22-
2321
// Starting from the back, concatenating ifs into one big if/elseif statement
24-
const concatenatedIf = caseClauses.reduceRight((previousCondition, clause, index) => {
22+
const concatenatedIf = statement.caseBlock.clauses.reduceRight((previousCondition, clause, index) => {
23+
if (ts.isDefaultClause(clause)) {
24+
// Skip default clause here (needs to be included to ensure index lines up with index later)
25+
return previousCondition;
26+
}
27+
2528
// If the clause condition holds, go to the correct label
2629
const condition = lua.createBinaryExpression(
2730
switchVariable,
File renamed without changes.

test/unit/conditionals.spec.ts

Lines changed: 0 additions & 297 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as tstl from "../../src";
2-
import { unsupportedForTarget } from "../../src/transformation/utils/diagnostics";
32
import * as util from "../util";
43

54
test.each([0, 1])("if (%p)", inp => {
@@ -52,302 +51,6 @@ test.each([0, 1, 2, 3])("ifelseifelse (%p)", inp => {
5251
`.expectToMatchJsResult();
5352
});
5453

55-
test.each([0, 1, 2, 3])("switch (%p)", inp => {
56-
util.testFunction`
57-
let result: number = -1;
58-
59-
switch (<number>${inp}) {
60-
case 0:
61-
result = 0;
62-
break;
63-
case 1:
64-
result = 1;
65-
break;
66-
case 2:
67-
result = 2;
68-
break;
69-
}
70-
return result;
71-
`.expectToMatchJsResult();
72-
});
73-
74-
test.each([0, 1, 2, 3])("switchdefault (%p)", inp => {
75-
util.testFunction`
76-
let result: number = -1;
77-
78-
switch (<number>${inp}) {
79-
case 0:
80-
result = 0;
81-
break;
82-
case 1:
83-
result = 1;
84-
break;
85-
case 2:
86-
result = 2;
87-
break;
88-
default:
89-
result = -2;
90-
break;
91-
}
92-
return result;
93-
`.expectToMatchJsResult();
94-
});
95-
96-
test.each([0, 0, 2, 3, 4, 5, 7])("switchfallthrough (%p)", inp => {
97-
util.testFunction`
98-
let result: number = -1;
99-
100-
switch (<number>${inp}) {
101-
case 0:
102-
result = 0;
103-
case 1:
104-
result = 1;
105-
break;
106-
case 2:
107-
result = 2;
108-
case 3:
109-
case 4:
110-
result = 4;
111-
break;
112-
case 5:
113-
result = 5;
114-
case 6:
115-
result += 10;
116-
break;
117-
case 7:
118-
result = 7;
119-
default:
120-
result = -2;
121-
break;
122-
}
123-
124-
return result;
125-
`.expectToMatchJsResult();
126-
});
127-
128-
test.each([0, 1, 2, 3])("nestedSwitch (%p)", inp => {
129-
util.testFunction`
130-
let result: number = -1;
131-
132-
switch (${inp} as number) {
133-
case 0:
134-
result = 0;
135-
break;
136-
case 1:
137-
switch(${inp} as number) {
138-
case 0:
139-
result = 0;
140-
break;
141-
case 1:
142-
result = 1;
143-
break;
144-
default:
145-
result = -3;
146-
break;
147-
}
148-
break;
149-
case 2:
150-
result = 2;
151-
break;
152-
default:
153-
result = -2;
154-
break;
155-
}
156-
return result;
157-
`.expectToMatchJsResult();
158-
});
159-
160-
test("switch cases scope", () => {
161-
util.testFunction`
162-
switch (0 as number) {
163-
case 0:
164-
let foo: number | undefined = 1;
165-
case 1:
166-
foo = 2;
167-
case 2:
168-
return foo;
169-
}
170-
`.expectToMatchJsResult();
171-
});
172-
173-
test("variable in nested scope does not interfere with case scope", () => {
174-
util.testFunction`
175-
let foo: number = 0;
176-
switch (foo) {
177-
case 0: {
178-
let foo = 1;
179-
}
180-
181-
case 1:
182-
return foo;
183-
}
184-
`.expectToMatchJsResult();
185-
});
186-
187-
test("switch using variable re-declared in cases", () => {
188-
util.testFunction`
189-
let foo: number = 0;
190-
switch (foo) {
191-
case 0:
192-
let foo = true;
193-
case 1:
194-
return foo;
195-
}
196-
`.expectToMatchJsResult();
197-
});
198-
199-
test.each([0, 1, 2])("switch with block statement scope (%p)", inp => {
200-
util.testFunction`
201-
let result: number = -1;
202-
203-
switch (<number>${inp}) {
204-
case 0: {
205-
let x = 0;
206-
result = 0;
207-
break;
208-
}
209-
case 1: {
210-
let x = 1;
211-
result = x;
212-
}
213-
case 2: {
214-
let x = 2;
215-
result = x;
216-
break;
217-
}
218-
}
219-
return result;
220-
`.expectToMatchJsResult();
221-
});
222-
223-
test.each([0, 1, 2, 3])("switchReturn (%p)", inp => {
224-
util.testFunction`
225-
switch (<number>${inp}) {
226-
case 0:
227-
return 0;
228-
break;
229-
case 1:
230-
return 1;
231-
case 2:
232-
return 2;
233-
break;
234-
}
235-
236-
return -1;
237-
`.expectToMatchJsResult();
238-
});
239-
240-
test.each([0, 1, 2, 3])("switchWithBrackets (%p)", inp => {
241-
util.testFunction`
242-
let result: number = -1;
243-
244-
switch (<number>${inp}) {
245-
case 0: {
246-
result = 0;
247-
break;
248-
}
249-
case 1: {
250-
result = 1;
251-
break;
252-
}
253-
case 2: {
254-
result = 2;
255-
break;
256-
}
257-
}
258-
return result;
259-
`.expectToMatchJsResult();
260-
});
261-
262-
test.each([0, 1, 2, 3])("switchWithBracketsBreakInConditional (%p)", inp => {
263-
util.testFunction`
264-
let result: number = -1;
265-
266-
switch (<number>${inp}) {
267-
case 0: {
268-
result = 0;
269-
break;
270-
}
271-
case 1: {
272-
result = 1;
273-
274-
if (result == 1) break;
275-
}
276-
case 2: {
277-
result = 2;
278-
break;
279-
}
280-
}
281-
return result;
282-
`.expectToMatchJsResult();
283-
});
284-
285-
test.each([0, 1, 2, 3])("switchWithBracketsBreakInInternalLoop (%p)", inp => {
286-
util.testFunction`
287-
let result: number = -1;
288-
289-
switch (${inp} as number) {
290-
case 0: {
291-
result = 0;
292-
293-
for (let i = 0; i < 5; i++) {
294-
result++;
295-
296-
if (i >= 2) {
297-
break;
298-
}
299-
}
300-
}
301-
case 1: {
302-
result++;
303-
break;
304-
}
305-
case 2: {
306-
result = 2;
307-
break;
308-
}
309-
}
310-
return result;
311-
`.expectToMatchJsResult();
312-
});
313-
314-
test("switch uses elseif", () => {
315-
test("array", () => {
316-
util.testFunction`
317-
let result: number = -1;
318-
319-
switch (2 as number) {
320-
case 0: {
321-
result = 200;
322-
break;
323-
}
324-
325-
case 1: {
326-
result = 100;
327-
break;
328-
}
329-
330-
case 2: {
331-
result = 1;
332-
break;
333-
}
334-
}
335-
336-
return result;
337-
`
338-
.expectLuaToMatchSnapshot()
339-
.expectToMatchJsResult();
340-
});
341-
});
342-
343-
test("switch not allowed in 5.1", () => {
344-
util.testFunction`
345-
switch ("abc") {}
346-
`
347-
.setOptions({ luaTarget: tstl.LuaTarget.Lua51 })
348-
.expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]);
349-
});
350-
35154
test.each([
35255
{ input: "true ? 'a' : 'b'" },
35356
{ input: "false ? 'a' : 'b'" },

0 commit comments

Comments
 (0)