diff --git a/tslang/lib/TypeScript/MLIRGenVariables.cpp b/tslang/lib/TypeScript/MLIRGenVariables.cpp index 2ad39a1de..eaac4d56c 100644 --- a/tslang/lib/TypeScript/MLIRGenVariables.cpp +++ b/tslang/lib/TypeScript/MLIRGenVariables.cpp @@ -765,7 +765,14 @@ namespace mlirgen #endif auto initFunc = [&](mlir::Location location, const GenContext &genContext) { - if (declarationMode) + // A module imported as source only declares what it defines, so a module-level + // variable gets its type and no initializer code. Not a local: a function body is only + // walked here to infer types (a dummy run, see mlirGenFunctionBody) and its IR is + // discarded, so its initializers may produce real values - and must. A `const` binds + // its name to that value, and a destructuring pattern reads its elements from it: + // without one, reading the const failed with "can't resolve name" and destructuring + // with "failed statement" or a crash. + if (declarationMode && !genContext.funcOp) { auto [t, b, p] = evaluateTypeAndInit(item, genContext); return std::make_tuple(t, mlir::Value(), p ? TypeProvided::Yes : TypeProvided::No); diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index cbf5913eb..31037cd0f 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -975,6 +975,7 @@ add_test(NAME test-compile-export-import-class-interface COMMAND test-runner "${ # static two-module form had no rc/none coverage at all, which is why the leak it fixes # went unmeasured for so long. add_test(NAME test-compile-export-import-owned-returns COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_owned_returns.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_owned_returns.ts") +add_test(NAME test-compile-export-import-const-locals COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_locals.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_locals.ts") add_test(NAME test-compile-rc-export-import-owned-returns COMMAND test-runner -mm=rc "${PROJECT_SOURCE_DIR}/test/tester/tests/import_owned_returns.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_owned_returns.ts") add_test(NAME test-compile-none-export-import-owned-returns COMMAND test-runner -mm=none "${PROJECT_SOURCE_DIR}/test/tester/tests/import_owned_returns.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_owned_returns.ts") add_test(NAME test-compile-export-import-class-extends COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends.ts") @@ -1058,6 +1059,7 @@ add_test(NAME test-compile-shared-export-import-owned-returns COMMAND test-runne # see the importer's array. Under -jit this failed (2000 of 2000 freed) while TypeScriptRuntime.dll # linked Boehm statically beside a library on gc.dll. add_test(NAME test-compile-shared-export-import-gc-single-collector COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_gc_single_collector.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_gc_single_collector.ts") +add_test(NAME test-compile-shared-export-import-const-locals COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_locals.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_locals.ts") add_test(NAME test-compile-shared-export-import-class-extends COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends.ts") add_test(NAME test-compile-shared-export-import-class-extends-implements-diamond COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends_implements_diamond.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends_implements_diamond.ts") add_test(NAME test-compile-shared-export-import-class-extends-multilevel COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends_multilevel.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends_multilevel.ts") @@ -1140,6 +1142,7 @@ add_test(NAME test-jit-shared-export-import-class-interface COMMAND test-runner add_test(NAME test-jit-shared-export-import-object-literal-with-class-types COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_with_class_types.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_with_class_types.ts") add_test(NAME test-jit-shared-export-import-owned-returns COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_owned_returns.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_owned_returns.ts") add_test(NAME test-jit-shared-export-import-gc-single-collector COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_gc_single_collector.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_gc_single_collector.ts") +add_test(NAME test-jit-shared-export-import-const-locals COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_locals.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_locals.ts") add_test(NAME test-jit-shared-export-import-class-extends COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends.ts") add_test(NAME test-jit-shared-export-import-class-extends-multilevel COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends_multilevel.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends_multilevel.ts") add_test(NAME test-jit-shared-export-import-class-extends-implements-diamond COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_extends_implements_diamond.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_extends_implements_diamond.ts") diff --git a/tslang/test/tester/tests/export_const_locals.ts b/tslang/test/tester/tests/export_const_locals.ts new file mode 100644 index 000000000..b33719f33 --- /dev/null +++ b/tslang/test/tester/tests/export_const_locals.ts @@ -0,0 +1,65 @@ +// The library side of import_const_locals.ts. Every function reads a `const` local. When a module +// imports this file as source (no shared library beside it), its bodies are compiled only to +// infer types, with no values - and a `const` used to bind its name to that missing value, so the +// importer failed with "can't resolve name". `let` was never affected. + +export function plainConst(n: number): number { + const s = n + 1; + return s; +} + +// No return type: it is inferred from the const, so the importer must infer the same one the +// library does - a const read back as its storage reference instead gave `ref` here. +export function inferredFromConst(n: number) { + const s = n + 2; + return s; +} + +export function stringConst(n: number): string { + const s = `v-${n}`; + return s; +} + +export function constInLoop(n: number): number { + let total = 0; + for (let j = 0; j < n; j++) { + const s = j * 2; + total = total + s; + } + + return total; +} + +export function constInBlock(n: number): number { + let total = 0; + if (n > 0) { + const s = `${n}`; + total = total + s.length; + } + + return total; +} + +export class WithConst { + method(n: number) { + const s = n + 10; + return s; + } +} + +export function arrayDestructuring(n: number): number { + const [a, b] = [n, n + 1]; + return a + b; +} + +export function objectDestructuring(n: number): number { + const { x, y } = { x: n, y: 5 }; + return x + y; +} + +namespace NS { + export function namespaceConst(n: number): number { + const s = `${n}-${n}`; + return s.length; + } +} diff --git a/tslang/test/tester/tests/import_const_locals.ts b/tslang/test/tester/tests/import_const_locals.ts new file mode 100644 index 000000000..20ede7a9b --- /dev/null +++ b/tslang/test/tester/tests/import_const_locals.ts @@ -0,0 +1,18 @@ +import './export_const_locals' + +// A module imported as source must compile when its functions read `const` locals. +// See export_const_locals.ts. + +function main() { + assert(plainConst(1) == 2, "plainConst"); + assert(inferredFromConst(3) == 5, "inferredFromConst"); + assert(stringConst(7) == "v-7", "stringConst"); + assert(constInLoop(4) == 12, "constInLoop"); + assert(constInBlock(123) == 3, "constInBlock"); + assert(new WithConst().method(5) == 15, "WithConst.method"); + assert(arrayDestructuring(3) == 7, "arrayDestructuring"); + assert(objectDestructuring(4) == 9, "objectDestructuring"); + assert(NS.namespaceConst(12) == 5, "NS.namespaceConst"); + + print("done."); +}