From 21f11d8e961a837841672ed88755f730a705f4cd Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 21 Dec 2018 19:06:42 +0100 Subject: [PATCH 01/20] simplify ternary transpilation --- src/Transpiler.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 28ddadcaf..9e5599991 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -981,9 +981,7 @@ export abstract class LuaTranspiler { const condition = this.transpileExpression(node.condition); const val1 = this.transpileExpression(node.whenTrue); const val2 = this.transpileExpression(node.whenFalse); - - return this.transpileLuaLibFunction(LuaLibFeature.Ternary, condition, - `function() return ${val1} end`, `function() return ${val2} end`); + return `((${condition}) and {${val1}} or {${val2}})[1]`; } public transpileBinaryAssignmentExpression( From e633f8db6846ef00f0c0f945136b06875080f86a Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 21 Dec 2018 19:41:41 +0100 Subject: [PATCH 02/20] remove ternary from lualib --- src/lualib/Ternary.ts | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/lualib/Ternary.ts diff --git a/src/lualib/Ternary.ts b/src/lualib/Ternary.ts deleted file mode 100644 index f1331f4f4..000000000 --- a/src/lualib/Ternary.ts +++ /dev/null @@ -1,7 +0,0 @@ -function __TS__Ternary(condition: boolean, cb1: () => T, cb2: () => T): T { - if (condition) { - return cb1(); - } else { - return cb2(); - } -} From 7de0541f7b03dd34de72543bc63fa1ab0e84a0e3 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 21 Dec 2018 19:42:26 +0100 Subject: [PATCH 03/20] remove reference to ternary --- src/Transpiler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 9e5599991..dd3db5fbb 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -38,7 +38,6 @@ export enum LuaLibFeature { Set = "Set", StringReplace = "StringReplace", StringSplit = "StringSplit", - Ternary = "Ternary", } export enum LuaLibImportKind { From 7c6bc02777859008eb1b64c29db81b6b6c124846 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Sat, 22 Dec 2018 15:15:01 +0100 Subject: [PATCH 04/20] replace boxing with IIFE --- src/Transpiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index dd3db5fbb..28b50e476 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -980,7 +980,7 @@ export abstract class LuaTranspiler { const condition = this.transpileExpression(node.condition); const val1 = this.transpileExpression(node.whenTrue); const val2 = this.transpileExpression(node.whenFalse); - return `((${condition}) and {${val1}} or {${val2}})[1]`; + return `((${condition}) and function() return ${val1}; end or function() return ${val2}; end)()`; } public transpileBinaryAssignmentExpression( From e652aa79e88d793eb4912ca7fc6b9b2adfeade83 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Sat, 22 Dec 2018 15:23:35 +0100 Subject: [PATCH 05/20] use boxing ternary in luajit transpiler --- src/targets/Transpiler.JIT.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/targets/Transpiler.JIT.ts b/src/targets/Transpiler.JIT.ts index a23e3a8e2..f509fdf15 100644 --- a/src/targets/Transpiler.JIT.ts +++ b/src/targets/Transpiler.JIT.ts @@ -44,4 +44,12 @@ export class LuaTranspilerJIT extends LuaTranspiler52 { public transpileSpreadElement(node: ts.SpreadElement): string { return "unpack(" + this.transpileExpression(node.expression) + ")"; } + + /** @override */ + public transpileConditionalExpression(node: ts.ConditionalExpression, brackets?: boolean): string { + const condition = this.transpileExpression(node.condition); + const val1 = this.transpileExpression(node.whenTrue); + const val2 = this.transpileExpression(node.whenFalse); + return `((${condition}) and {${val1}} or {${val2}})[1]`; + } } From 971d087b5e48065366666216ec9c7f854b968749 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Sat, 22 Dec 2018 17:07:48 +0100 Subject: [PATCH 06/20] add transpilation tests for ternary --- test/unit/expressions.spec.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 6f9c2ba30..94c4cd62c 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -192,6 +192,18 @@ export class ExpressionTests { Expect(util.transpileString("undefined")).toBe("nil;"); } + @TestCase(LuaTarget.Lua51, "true?false:true", false) + @TestCase(LuaTarget.Lua51, "false?false:true", true) + @TestCase(LuaTarget.LuaJIT, "true?false:true", false) + @TestCase(LuaTarget.LuaJIT, "false?false:true", true) + @Test("Ternary operator") + public ternaryOperator(target: LuaTarget, input: string, expected: any): void { + const lua = `return ` + + util.transpileString(input, { luaTarget: target }); + const result = util.executeLua(lua); + Expect(result).toBe(expected); + } + @TestCase("inst.field", 8) @TestCase("inst.field + 3", 8 + 3) @TestCase("inst.field * 3", 8 * 3) @@ -260,7 +272,7 @@ export class ExpressionTests { @TestCase("inst.superBaseField", 4) @Test("Inherited accessors") public inheritedAccessors(expression: string, expected: any): void { - const source = `class MyBaseClass {` + const source = `class MyBaseClass {` + ` public _baseField: number;` + ` public get baseField(): number { return this._baseField + 6; }` + ` public set baseField(v: number) { this._baseField = v; }` @@ -269,13 +281,13 @@ export class ExpressionTests { + ` public _field: number;` + ` public get field(): number { return this._field + 4; }` + ` public set field(v: number) { this._field = v; }` - + `}` + + `}` + `class MySuperClass extends MyClass {` + ` public _superField: number;` + ` public get superField(): number { return this._superField + 2; }` + ` public set superField(v: number) { this._superField = v; }` + ` public get superBaseField() { return this.baseField - 3; }` - + `}` + + `}` + `var inst = new MySuperClass();` + `inst.baseField = 1;` + `inst.field = 2;` From d6fd15fc86c82181f0f2b5b8c3a9795548b6492d Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 28 Dec 2018 12:46:58 +0100 Subject: [PATCH 07/20] transpile unprotected ternary for non falsible whenTrue type --- src/TSHelper.ts | 14 ++++++++++++++ src/Transpiler.ts | 14 ++++++++++++-- src/targets/Transpiler.JIT.ts | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index c9b464154..2d384657d 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -316,4 +316,18 @@ export class TSHelper { return defaultArrayPropertyNames.has(methodName); } + public static isNonFalsible(type: ts.Type): boolean { + const falsibleFlags = ts.TypeFlags.Boolean + | ts.TypeFlags.BooleanLiteral + | ts.TypeFlags.Undefined + | ts.TypeFlags.Any; + + if (type.flags & falsibleFlags) { + return false; + } else if (type.isLiteral()) { + return true; + } + + return false; + } } diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 28b50e476..f876e4140 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -728,7 +728,7 @@ export abstract class LuaTranspiler { return this.transpileBinaryExpression(node as ts.BinaryExpression, brackets); case ts.SyntaxKind.ConditionalExpression: // Add brackets to preserve ordering - return this.transpileConditionalExpression(node as ts.ConditionalExpression, brackets); + return this.transpileConditionalExpression(node as ts.ConditionalExpression); case ts.SyntaxKind.CallExpression: return this.transpileCallExpression(node as ts.CallExpression); case ts.SyntaxKind.PropertyAccessExpression: @@ -976,13 +976,23 @@ export abstract class LuaTranspiler { return parts.join(".."); } - public transpileConditionalExpression(node: ts.ConditionalExpression, brackets?: boolean): string { + public transpileProtectedConditionalExpression(node: ts.ConditionalExpression): string { const condition = this.transpileExpression(node.condition); const val1 = this.transpileExpression(node.whenTrue); const val2 = this.transpileExpression(node.whenFalse); return `((${condition}) and function() return ${val1}; end or function() return ${val2}; end)()`; } + public transpileConditionalExpression(node: ts.ConditionalExpression): string { + if (tsHelper.isNonFalsible(this.checker.getTypeAtLocation(node.whenTrue))) { + const condition = this.transpileExpression(node.condition); + const val1 = this.transpileExpression(node.whenTrue); + const val2 = this.transpileExpression(node.whenFalse); + return `((${condition}) and (${val1}) or (${val2}))`; + } + return this.transpileProtectedConditionalExpression(node); + } + public transpileBinaryAssignmentExpression( assignee: ts.Expression, lhs: ts.Expression, diff --git a/src/targets/Transpiler.JIT.ts b/src/targets/Transpiler.JIT.ts index f509fdf15..466be79a5 100644 --- a/src/targets/Transpiler.JIT.ts +++ b/src/targets/Transpiler.JIT.ts @@ -46,7 +46,7 @@ export class LuaTranspilerJIT extends LuaTranspiler52 { } /** @override */ - public transpileConditionalExpression(node: ts.ConditionalExpression, brackets?: boolean): string { + public transpileProtectedConditionalExpression(node: ts.ConditionalExpression): string { const condition = this.transpileExpression(node.condition); const val1 = this.transpileExpression(node.whenTrue); const val2 = this.transpileExpression(node.whenFalse); From 11a77572d5a279ffc86e83619c75fa6f3aeddb81 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 28 Dec 2018 12:50:30 +0100 Subject: [PATCH 08/20] resolve merge conflict --- src/TSHelper.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 1ffccd70e..2b4e053dc 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -441,7 +441,6 @@ export class TSHelper { public static isDefaultArrayPropertyName(methodName: string): boolean { return defaultArrayPropertyNames.has(methodName); } -<<<<<<< HEAD public static isNonFalsible(type: ts.Type): boolean { const falsibleFlags = ts.TypeFlags.Boolean @@ -457,6 +456,4 @@ export class TSHelper { return false; } -======= ->>>>>>> b84936491d6b039a8eadd1a7a4c26fee3fb98486 } From d45b970781ff95dbcbd34691e3cdcc858c937b56 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 28 Dec 2018 13:05:55 +0100 Subject: [PATCH 09/20] add test for undefined whenTrue --- test/unit/expressions.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 94c4cd62c..b77ed6253 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -194,8 +194,10 @@ export class ExpressionTests { @TestCase(LuaTarget.Lua51, "true?false:true", false) @TestCase(LuaTarget.Lua51, "false?false:true", true) + @TestCase(LuaTarget.Lua51, "true?undefined:true", undefined) @TestCase(LuaTarget.LuaJIT, "true?false:true", false) @TestCase(LuaTarget.LuaJIT, "false?false:true", true) + @TestCase(LuaTarget.LuaJIT, "true?undefined:true", undefined) @Test("Ternary operator") public ternaryOperator(target: LuaTarget, input: string, expected: any): void { const lua = `return ` From 5d132da7683647ed4589d20f95b6645ccfcf5a09 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:07:16 +0100 Subject: [PATCH 10/20] add test for literal and non-literal values --- test/unit/expressions.spec.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index b77ed6253..a0c210636 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -192,16 +192,22 @@ export class ExpressionTests { Expect(util.transpileString("undefined")).toBe("nil;"); } - @TestCase(LuaTarget.Lua51, "true?false:true", false) - @TestCase(LuaTarget.Lua51, "false?false:true", true) - @TestCase(LuaTarget.Lua51, "true?undefined:true", undefined) - @TestCase(LuaTarget.LuaJIT, "true?false:true", false) - @TestCase(LuaTarget.LuaJIT, "false?false:true", true) - @TestCase(LuaTarget.LuaJIT, "true?undefined:true", undefined) + @TestCase("true ? false : true", false) + @TestCase("false ? false : true", true) + @TestCase("true ? false : true", false, LuaTarget.Lua51) + @TestCase("false ? false : true", true, LuaTarget.Lua51) + @TestCase("true ? undefined : true", undefined, LuaTarget.Lua51) + @TestCase("true ? false : true", false, LuaTarget.LuaJIT) + @TestCase("false ? false : true", true, LuaTarget.LuaJIT) + @TestCase("true ? undefined : true", undefined, LuaTarget.LuaJIT) + @TestCase("true ? literalValue : variableValue", "literal") + @TestCase("true ? variableValue : literalValue", undefined) @Test("Ternary operator") - public ternaryOperator(target: LuaTarget, input: string, expected: any): void { - const lua = `return ` - + util.transpileString(input, { luaTarget: target }); + public ternaryOperator(input: string, expected: any, target?: LuaTarget): void { + const source = `const literalValue = 'literal';` + + `let variableValue:string;` + + `return ${input};`; + const lua = util.transpileString(source, { luaTarget: target }); const result = util.executeLua(lua); Expect(result).toBe(expected); } From 1a4784605a0af2645834de7f2ec38b1185901eeb Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:07:39 +0100 Subject: [PATCH 11/20] add support for strictNullChecks --- src/TSHelper.ts | 8 ++++---- src/Transpiler.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index ae3015099..5982a4baf 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -454,7 +454,7 @@ export class TSHelper { return defaultArrayPropertyNames.has(methodName); } - public static isNonFalsible(type: ts.Type): boolean { + public static isNonFalsible(type: ts.Type, strictNullChecks: boolean): boolean { const falsibleFlags = ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined @@ -462,10 +462,10 @@ export class TSHelper { if (type.flags & falsibleFlags) { return false; - } else if (type.isLiteral()) { - return true; + } else if (!strictNullChecks && !type.isLiteral()) { + return false; } - return false; + return true; } } diff --git a/src/Transpiler.ts b/src/Transpiler.ts index d0cb55340..84f0a24db 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -1038,7 +1038,7 @@ export abstract class LuaTranspiler { } public transpileConditionalExpression(node: ts.ConditionalExpression): string { - if (tsHelper.isNonFalsible(this.checker.getTypeAtLocation(node.whenTrue))) { + if (tsHelper.isNonFalsible(this.checker.getTypeAtLocation(node.whenTrue), this.options.strictNullChecks)) { const condition = this.transpileExpression(node.condition); const val1 = this.transpileExpression(node.whenTrue); const val2 = this.transpileExpression(node.whenFalse); From a67cbbca6977e28a73115f8e20373fa4d550704c Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:30:49 +0100 Subject: [PATCH 12/20] handle union types --- src/TSHelper.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 5982a4baf..400483560 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -455,7 +455,8 @@ export class TSHelper { } public static isNonFalsible(type: ts.Type, strictNullChecks: boolean): boolean { - const falsibleFlags = ts.TypeFlags.Boolean + const falsibleFlags = ts.TypeFlags.PossiblyFalsy + | ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined | ts.TypeFlags.Any; @@ -464,6 +465,12 @@ export class TSHelper { return false; } else if (!strictNullChecks && !type.isLiteral()) { return false; + } else if (type.isUnion()) { + for (const subType of type.types) { + if (!this.isNonFalsible(subType, strictNullChecks)) { + return false; + } + } } return true; From 0792270c24941d6ca0210740375ef580715fc85e Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:31:13 +0100 Subject: [PATCH 13/20] add tests for strictNullChecks --- test/unit/expressions.spec.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index a0c210636..cc101c118 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,4 +1,4 @@ -import { Expect, Test, TestCase } from "alsatian"; +import { Expect, Test, TestCase, FocusTest } from "alsatian"; import { TranspileError } from "../../src/Errors"; import { LuaTarget } from "../../src/Transpiler"; @@ -192,22 +192,29 @@ export class ExpressionTests { Expect(util.transpileString("undefined")).toBe("nil;"); } + @FocusTest @TestCase("true ? false : true", false) @TestCase("false ? false : true", true) - @TestCase("true ? false : true", false, LuaTarget.Lua51) - @TestCase("false ? false : true", true, LuaTarget.Lua51) - @TestCase("true ? undefined : true", undefined, LuaTarget.Lua51) - @TestCase("true ? false : true", false, LuaTarget.LuaJIT) - @TestCase("false ? false : true", true, LuaTarget.LuaJIT) - @TestCase("true ? undefined : true", undefined, LuaTarget.LuaJIT) - @TestCase("true ? literalValue : variableValue", "literal") - @TestCase("true ? variableValue : literalValue", undefined) + @TestCase("true ? literalValue : true", "literal") + @TestCase("true ? variableValue : true", undefined) + @TestCase("true ? maybeUndefinedValue : true", undefined) + @TestCase("true ? maybeBooleanValue : true", false) + @TestCase("true ? maybeUndefinedValue : true", undefined, { strictNullChecks: true }) + @TestCase("true ? maybeBooleanValue : true", false, { strictNullChecks: true }) + @TestCase("true ? false : true", false, { luaTarget: LuaTarget.Lua51 }) + @TestCase("false ? false : true", true, { luaTarget: LuaTarget.Lua51 }) + @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.Lua51 }) + @TestCase("true ? false : true", false, { luaTarget: LuaTarget.LuaJIT }) + @TestCase("false ? false : true", true, { luaTarget: LuaTarget.LuaJIT }) + @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.LuaJIT }) @Test("Ternary operator") - public ternaryOperator(input: string, expected: any, target?: LuaTarget): void { + public ternaryOperator(input: string, expected: any, options?: ts.CompilerOptions): void { const source = `const literalValue = 'literal';` + `let variableValue:string;` + + `let maybeBooleanValue:string|boolean = false;` + + `let maybeUndefinedValue:string|undefined;` + `return ${input};`; - const lua = util.transpileString(source, { luaTarget: target }); + const lua = util.transpileString(source, options); const result = util.executeLua(lua); Expect(result).toBe(expected); } From 95cdbf722240698a9c18114ccfa2fd8f74005cf0 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:31:47 +0100 Subject: [PATCH 14/20] remove FocusTest --- test/unit/expressions.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index cc101c118..7e498c44e 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,4 +1,4 @@ -import { Expect, Test, TestCase, FocusTest } from "alsatian"; +import { Expect, Test, TestCase } from "alsatian"; import { TranspileError } from "../../src/Errors"; import { LuaTarget } from "../../src/Transpiler"; @@ -192,7 +192,6 @@ export class ExpressionTests { Expect(util.transpileString("undefined")).toBe("nil;"); } - @FocusTest @TestCase("true ? false : true", false) @TestCase("false ? false : true", true) @TestCase("true ? literalValue : true", "literal") From 70a829384588bfb04af64e590efbd2e3b9d360fb Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 13:51:36 +0100 Subject: [PATCH 15/20] added literal ternary test --- test/unit/expressions.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 7e498c44e..7c49f820d 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -192,6 +192,8 @@ export class ExpressionTests { Expect(util.transpileString("undefined")).toBe("nil;"); } + @TestCase("true ? 'a' : 'b'", "a") + @TestCase("false ? 'a' : 'b'", "b") @TestCase("true ? false : true", false) @TestCase("false ? false : true", true) @TestCase("true ? literalValue : true", "literal") From 54df9877011d2500c153b0242156d185c8f60cff Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 14:03:17 +0100 Subject: [PATCH 16/20] remove PossiblyFalsy flag check as it is not applicable to lua --- src/TSHelper.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 400483560..719fc53d0 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -455,8 +455,7 @@ export class TSHelper { } public static isNonFalsible(type: ts.Type, strictNullChecks: boolean): boolean { - const falsibleFlags = ts.TypeFlags.PossiblyFalsy - | ts.TypeFlags.Boolean + const falsibleFlags = ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined | ts.TypeFlags.Any; From 71a87bc52ef50f2678ffdaeea4236c635d2ba86c Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Fri, 4 Jan 2019 14:19:50 +0100 Subject: [PATCH 17/20] correctly handle null --- src/TSHelper.ts | 1 + test/unit/expressions.spec.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 719fc53d0..8cd3e6039 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -458,6 +458,7 @@ export class TSHelper { const falsibleFlags = ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined + | ts.TypeFlags.Null | ts.TypeFlags.Any; if (type.flags & falsibleFlags) { diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 7c49f820d..2e86beac7 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -202,6 +202,8 @@ export class ExpressionTests { @TestCase("true ? maybeBooleanValue : true", false) @TestCase("true ? maybeUndefinedValue : true", undefined, { strictNullChecks: true }) @TestCase("true ? maybeBooleanValue : true", false, { strictNullChecks: true }) + @TestCase("true ? undefined : true", undefined, { strictNullChecks: true }) + @TestCase("true ? null : true", undefined, { strictNullChecks: true }) @TestCase("true ? false : true", false, { luaTarget: LuaTarget.Lua51 }) @TestCase("false ? false : true", true, { luaTarget: LuaTarget.Lua51 }) @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.Lua51 }) From 3c1d2b3d7600ef4d9ff90e1f88ed4e5c1ae8e8d9 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Sun, 6 Jan 2019 15:39:23 +0100 Subject: [PATCH 18/20] add Void and Never to falsible falgs --- src/TSHelper.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 8cd3e6039..d94fb2af7 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -459,6 +459,8 @@ export class TSHelper { | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined | ts.TypeFlags.Null + | ts.TypeFlags.Never + | ts.TypeFlags.Void | ts.TypeFlags.Any; if (type.flags & falsibleFlags) { From f617b7633f763d5d95cf8a707d14b3e4b1aed71b Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Thu, 17 Jan 2019 15:35:37 +0100 Subject: [PATCH 19/20] refactor isNonFalsible() -> isFalisble() --- src/TSHelper.ts | 12 ++++++------ src/Transpiler.ts | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index d94fb2af7..8399bf9a0 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -454,7 +454,7 @@ export class TSHelper { return defaultArrayPropertyNames.has(methodName); } - public static isNonFalsible(type: ts.Type, strictNullChecks: boolean): boolean { + public static isFalsible(type: ts.Type, strictNullChecks: boolean): boolean { const falsibleFlags = ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Undefined @@ -464,17 +464,17 @@ export class TSHelper { | ts.TypeFlags.Any; if (type.flags & falsibleFlags) { - return false; + return true; } else if (!strictNullChecks && !type.isLiteral()) { - return false; + return true; } else if (type.isUnion()) { for (const subType of type.types) { - if (!this.isNonFalsible(subType, strictNullChecks)) { - return false; + if (this.isFalsible(subType, strictNullChecks)) { + return true; } } } - return true; + return false; } } diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 84f0a24db..969d119e6 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -1038,13 +1038,13 @@ export abstract class LuaTranspiler { } public transpileConditionalExpression(node: ts.ConditionalExpression): string { - if (tsHelper.isNonFalsible(this.checker.getTypeAtLocation(node.whenTrue), this.options.strictNullChecks)) { - const condition = this.transpileExpression(node.condition); - const val1 = this.transpileExpression(node.whenTrue); - const val2 = this.transpileExpression(node.whenFalse); - return `((${condition}) and (${val1}) or (${val2}))`; + if (tsHelper.isFalsible(this.checker.getTypeAtLocation(node.whenTrue), this.options.strictNullChecks)) { + return this.transpileProtectedConditionalExpression(node); } - return this.transpileProtectedConditionalExpression(node); + const condition = this.transpileExpression(node.condition); + const val1 = this.transpileExpression(node.whenTrue); + const val2 = this.transpileExpression(node.whenFalse); + return `((${condition}) and (${val1}) or (${val2}))`; } public transpileBinaryAssignmentExpression( From 41416034771018f7cd8b81f106b3c48465123c0f Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Thu, 17 Jan 2019 16:39:21 +0100 Subject: [PATCH 20/20] check for strict mode --- src/Transpiler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 969d119e6..ed817816e 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -1038,7 +1038,8 @@ export abstract class LuaTranspiler { } public transpileConditionalExpression(node: ts.ConditionalExpression): string { - if (tsHelper.isFalsible(this.checker.getTypeAtLocation(node.whenTrue), this.options.strictNullChecks)) { + const isStrict = this.options.strict || this.options.strictNullChecks; + if (tsHelper.isFalsible(this.checker.getTypeAtLocation(node.whenTrue), isStrict)) { return this.transpileProtectedConditionalExpression(node); } const condition = this.transpileExpression(node.condition);