diff --git a/src/lualib/Error.ts b/src/lualib/Error.ts index ea9cba478..ae5deb05b 100644 --- a/src/lualib/Error.ts +++ b/src/lualib/Error.ts @@ -1,3 +1,5 @@ +import { __TS__New } from "./New"; + interface ErrorType { name: string; new (...args: any[]): Error; @@ -22,6 +24,11 @@ function getErrorStack(constructor: () => any): string | undefined { if (_VERSION.includes("Lua 5.0")) { return debug.traceback(`[Level ${level}]`); + // @ts-ignore Fails when compiled with Lua 5.0 types + } else if (_VERSION === "Lua 5.1") { + // Lua 5.1 and LuaJIT have a bug where it's not possible to specify the level without a message. + // @ts-ignore Fails when compiled with Lua 5.0 types + return string.sub(debug.traceback("", level), 2); } else { // @ts-ignore Fails when compiled with Lua 5.0 types return debug.traceback(undefined, level); @@ -33,7 +40,7 @@ function wrapErrorToString(getDescription: (this: T) => string) const description = getDescription.call(this as T); const caller = debug.getinfo(3, "f"); // @ts-ignore Fails when compiled with Lua 5.0 types - const isClassicLua = _VERSION.includes("Lua 5.0") || _VERSION === "Lua 5.1"; + const isClassicLua = _VERSION.includes("Lua 5.0"); if (isClassicLua || (caller && caller.func !== error)) { return description; } else { @@ -55,7 +62,7 @@ export const Error: ErrorConstructor = initErrorClass( public stack?: string; constructor(public message = "") { - this.stack = getErrorStack((this.constructor as any).new); + this.stack = getErrorStack(__TS__New as any); const metatable = getmetatable(this); if (metatable && !metatable.__errorToStringPatched) { metatable.__errorToStringPatched = true; diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 388fee290..05399d492 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,4 +1,5 @@ import * as util from "../util"; +import * as tstl from "../../src"; test("throwString", () => { util.testFunction` @@ -343,3 +344,27 @@ test("still works without debug module", () => { stack: undefined, }); }); + +util.testEachVersion( + "error stacktrace omits constructor and __TS_New", + () => util.testFunction` + const e = new Error(); + return e.stack; + `, + { + ...util.expectEachVersionExceptJit(builder => { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + // eslint-disable-next-line jest/no-standalone-expect + expect(luaResult.split("\n")).toHaveLength(4); + }), + + // 5.0 debug.traceback doesn't support levels + [tstl.LuaTarget.Lua50](builder) { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + // eslint-disable-next-line jest/no-standalone-expect + expect(luaResult).toContain("Level 4"); + }, + } +); diff --git a/test/util.ts b/test/util.ts index 7ebe1ccd3..501b24bfb 100644 --- a/test/util.ts +++ b/test/util.ts @@ -43,7 +43,7 @@ function getLuaBindingsForVersion(target: tstl.LuaTarget): { lauxlib: LauxLib; l return { lauxlib, lua, lualib }; } if (target === tstl.LuaTarget.LuaJIT) { - throw Error("Can't use executeLua() or expectToMatchJsResult() wit LuaJIT as target!"); + throw Error("Can't use executeLua() or expectToMatchJsResult() with LuaJIT as target!"); } const { lauxlib, lua, lualib } = require("lua-wasm-bindings/dist/lua.54"); @@ -63,7 +63,7 @@ export function testEachVersion( ): void { for (const version of Object.values(tstl.LuaTarget) as tstl.LuaTarget[]) { const specialBuilder = special?.[version]; - if (specialBuilder === false) return; + if (specialBuilder === false) continue; const testName = name === undefined ? version : `${name} [${version}]`; defineTest(testName, () => {