Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRGenContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ struct GenContext
bool insertIntoParentScope = false;
mlir::Operation *currentOperation = nullptr;
mlir_ts::FuncOp funcOp;
// The function a root's own statements are generated in when they are held back from the
// module level (generateGlobalEntryCode): its variables are still the module's, and an
// exported one is exported (#448). A function nested in them has a funcOp of its own.
mlir_ts::FuncOp rootStatementsFuncOp;
FunctionPrototypeDOM::TypePtr funcProto;
llvm::StringMap<ts::VariableDeclarationDOM::TypePtr> *capturedVars = nullptr;
llvm::SmallVector<ts::VariableDeclarationDOM::TypePtr> *usingVars = nullptr;
Expand Down
5 changes: 4 additions & 1 deletion tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2533,7 +2533,10 @@ class MLIRGenImpl
{
// there is no initializer, var declration can be undefined
//type = getUnionType(type, getUndefinedType());
if (!isa<mlir_ts::OptionalType>(type) && !hasModifier(parent, SyntaxKind::DeclareKeyword))
// a variable a library declares to its importers (`@dllimport let k: s32;` in its
// __decls) is defined in the library, so it has no initializer here (#448)
if (!isa<mlir_ts::OptionalType>(type) && !hasModifier(parent, SyntaxKind::DeclareKeyword) &&
!MLIRHelper::hasDecorator(parent, DLL_IMPORT))
{
emitWarning(loc(item), "'let' does not have initializer, use undefined union type '<type> | undefined'.");
}
Expand Down
8 changes: 6 additions & 2 deletions tslang/lib/TypeScript/MLIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,10 @@ namespace mlirgen
return mlir::success();
}

// the root's own statements: its variables are still the module's to export
GenContext rootGenContext(genContext);
rootGenContext.rootStatementsFuncOp = genContext.funcOp;

for (auto &statement : statements)
{
auto isVariableStatement = statement == SyntaxKind::VariableStatement;
Expand All @@ -808,11 +812,11 @@ namespace mlirgen
[](auto decl) { return decl->initializer == SyntaxKind::ArrowFunction; });
if (!hasArrowDeclaration)
{
variableStatement->declarationList->flags &= ~NodeFlags::Const;
variableStatement->declarationList->flags &= ~NodeFlags::Const;
}
}

if (failed(mlirGen(statement, genContext)))
if (failed(mlirGen(statement, rootGenContext)))
{
emitError(loc(statement), "failed statement");
return mlir::failure();
Expand Down
6 changes: 5 additions & 1 deletion tslang/lib/TypeScript/MLIRGenVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,9 +1001,13 @@ namespace mlirgen
// every function's locals too, and declared them to importers as `@dllimport` globals
// in a `.f_<function>` namespace, which no library defines.
auto itemVarClass = varClass;
// A root's statements held back into its entry function are still the module's
// (rootStatementsFuncOp): `export const k = 5` beside top-level code was not exported,
// and the importer of the library could not resolve k (#448).
auto atModuleLevel = !genContext.funcOp || genContext.funcOp == genContext.rootStatementsFuncOp;
if (variableDeclarationListAST->parent && !exportByDecorator)
{
itemVarClass.isExport = !genContext.funcOp && getExportModifier(
itemVarClass.isExport = atModuleLevel && getExportModifier(
variableDeclarationListAST->parent, MLIRHelper::getName(item->name, stringAllocator));
}

Expand Down
8 changes: 8 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,14 @@ tslang_add_import_tests(import-source-new-imported-class "${import_source_dir}"
# instruction", and a module linked beside the program got a `main` of its own (#447).
tslang_add_test(NAME test-jit-import-source-toplevel COMMAND test-runner -jit "${import_source_dir}/import_toplevel.ts")
tslang_add_import_tests(import-source-toplevel "${import_source_dir}" import_toplevel toplevel_module)
# An exported const of a module with top-level statements, imported: the importer could not resolve
# it under -shared ("can't resolve name: k"), and it was a `let` with no initializer otherwise (#448).
tslang_add_test(NAME test-jit-import-source-export-const COMMAND test-runner -jit "${import_source_dir}/import_export_const.ts")
tslang_add_import_tests(import-source-export-const "${import_source_dir}" import_export_const export_const_module)
# the library declares k to its importer as `@dllimport let k: s32;`, defined in the library: no
# "'let' does not have initializer" warning for it
set_tests_properties(test-compile-shared-import-source-export-const test-jit-shared-import-source-export-const
PROPERTIES FAIL_REGULAR_EXPRESSION "does not have initializer|Stack dump|Assertion failed")

# The JIT cache (--emit=jit, on by default): each .ts module imported is an object of its own,
# loaded beside the program's - imported through two others and initialized first; and a program
Expand Down
4 changes: 4 additions & 0 deletions tslang/test/tester/import-source/export_const_module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// A module with an exported const and a top-level statement, imported (#448).
export const k = 5;

print("module init");
7 changes: 7 additions & 0 deletions tslang/test/tester/import-source/import_export_const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// The importer of a module with an exported const and a top-level statement (#448).
import "./export_const_module";

function main() {
assert(k == 5, "the module's exported const");
print("done.");
}
Loading