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
54 changes: 48 additions & 6 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1661,6 +1661,19 @@ class MLIRGenImpl

auto actualType = variableDeclarationInfo.typeProvided == TypeProvided::Yes ? type : mth.wideStorageType(type);

// A global other modules reach holds a function the way a local `let` does
// (adjustLocalVariableType): as a hybrid function. Its declaration in __decls,
// `let f : (p0: number) => number`, reads back as one, so a library inferring a plain
// function from its initializer stored a smaller value than its importers loaded - the
// call's arguments landed in the wrong place and it returned garbage.
if (variableDeclarationInfo.isExport || variableDeclarationInfo.isImport || variableDeclarationInfo.isExternal)
{
if (auto funcType = dyn_cast<mlir_ts::FunctionType>(actualType))
{
actualType = mlir_ts::HybridFunctionType::get(builder.getContext(), funcType);
}
}

variableDeclarationInfo.setType(actualType);

if (variableDeclarationInfo.initial && actualType != type)
Expand Down Expand Up @@ -1819,7 +1832,9 @@ class MLIRGenImpl
GenContext genContextWithNameReceiver(genContext);
if (variableDeclarationInfo.isConst)
{
genContextWithNameReceiver.receiverName = variableDeclarationInfo.fullName;
// the short name: getNameOfFunction qualifies it with the namespace itself, and the
// function's name-without-namespace is what __decls prints inside `namespace X { }`
genContextWithNameReceiver.receiverName = variableDeclarationInfo.variableName;
}
else
{
Expand Down Expand Up @@ -2029,11 +2044,23 @@ class MLIRGenImpl

mlir::LogicalResult isGlobalConstLambda(mlir::Location location, struct VariableDeclarationInfo &variableDeclarationInfo, const GenContext &genContext)
{
if (variableDeclarationInfo.isConst
&& variableDeclarationInfo.initial
// Only when the function IS the const: its initializer named the function after it (an
// arrow function or function expression, see getNameWithArguments), so erasing the global
// leaves the name resolving to that function. A const that merely holds a function made
// under another name - `const alias = plainFn`, or a generator's wrapper - must keep its
// global, or nothing named after it is left: "can't resolve name" in the module itself,
// an undefined symbol in its importers.
if (variableDeclarationInfo.isConst
&& variableDeclarationInfo.initial
&& mth.isAnyFunctionType(variableDeclarationInfo.type))
{
return mlir::success();
if (auto symbolRefOp = variableDeclarationInfo.initial.getDefiningOp<mlir_ts::SymbolRefOp>())
{
if (symbolRefOp.getIdentifier() == variableDeclarationInfo.fullName)
{
return mlir::success();
}
}
}

return mlir::failure();
Expand Down Expand Up @@ -2169,7 +2196,12 @@ class MLIRGenImpl
// so if arrow is part of call, it will be considered as receiver of initialization which is wrong,
// example: const seq = f( (x) => x + 1 );
// seq will become name of function
if (initializer != SyntaxKind::ArrowFunction)
// a generator function expression is rewritten into a wrapper (mlirGenFunctionGenerator),
// which must not take the receiver's name
auto isNamedByReceiver = initializer == SyntaxKind::ArrowFunction
|| (initializer == SyntaxKind::FunctionExpression
&& !initializer.template as<FunctionLikeDeclarationBase>()->asteriskToken);
if (!isNamedByReceiver)
{
genContextWithTypeReceiver.receiverName = StringRef();
genContextWithTypeReceiver.isGlobalVarReceiver = false;
Expand Down Expand Up @@ -10242,7 +10274,17 @@ class MLIRGenImpl
}
else if (declarationAST == SyntaxKind::FunctionExpression)
{
name = MLIRHelper::getAnonymousName(loc_check(declarationAST), ".fe", "");
// like an arrow function: `const f = function () {...}` is the function `f`, which
// is how another module refers to it (see mlirGen(VariableDeclaration)). A generator
// arrives without a receiver name: the variable's initializer clears it for one.
if (!genContext.receiverName.empty())
{
name = genContext.receiverName.str();
}
else
{
name = MLIRHelper::getAnonymousName(loc_check(declarationAST), ".fe", "");
}
}
else if (declarationAST == SyntaxKind::ClassExpression)
{
Expand Down
9 changes: 9 additions & 0 deletions tslang/lib/TypeScript/MLIRGenVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,15 @@ namespace mlirgen
});
}

// An exported module-level const is a variable, as an exported `let` is. A const may be
// folded away inside its module - a const function becomes the function and its global is
// erased (isGlobalConstLambda) - but other modules reach it by symbol, so it has to be the
// global they import: an importer reads `export const f = () => ...` out of variable `f`.
if (varClass.type == VariableType::Const && !isUsing && varClass.isExport && !varClass.isImport && !genContext.funcOp)
{
varClass.type = VariableType::Let;
}

for (auto &item : variableDeclarationListAST->declarations)
{
// we need it for support "undefined type" in 'let' without initialization
Expand Down
3 changes: 3 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@ add_test(NAME test-compile-export-import-class-interface COMMAND test-runner "${
# 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-export-import-const-functions COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_functions.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_functions.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")
Expand Down Expand Up @@ -1060,6 +1061,7 @@ add_test(NAME test-compile-shared-export-import-owned-returns COMMAND test-runne
# 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-const-functions COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_functions.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_functions.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")
Expand Down Expand Up @@ -1143,6 +1145,7 @@ add_test(NAME test-jit-shared-export-import-object-literal-with-class-types COMM
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-const-functions COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_const_functions.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_const_functions.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")
Expand Down
55 changes: 55 additions & 0 deletions tslang/test/tester/tests/export_const_functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// The library side of import_const_functions.ts. An exported module-level `const` holding a
// function is a variable, as an exported `let` is: importers read the function pointer out of it.
// Importers used to look for such a variable while the library had turned the const into a
// function and erased it - an undefined symbol when linked, a call through the function's code
// bytes under the JIT.

export const arrowBlock = (n: number) => {
let s = n * 3;
return s;
};

export const arrowExpression = (n: number) => n * 4;

export const functionExpression = function (n: number) {
return n * 5;
};

export const arrowWithConstLocal = (n: number) => {
const s = `v-${n}`;
return s;
};

export function namedFunction(n: number) {
return n * 7;
}

// holds a function made under another name
export const alias = namedFunction;

export let letArrow = (n: number) => n * 8;

const notExported = (n: number) => n + 100;

export function usesNotExported(n: number) {
return notExported(n);
}

// a generator's wrapper is not named after the const, so the const must keep its global
const localGenerator = function* () {
yield 3;
yield 4;
};

export function usesLocalGenerator() {
let sum = 0;
for (const v of localGenerator()) {
sum = sum + v;
}

return sum;
}

namespace NS {
export const inNamespace = (n: number) => n * 6;
}
18 changes: 18 additions & 0 deletions tslang/test/tester/tests/import_const_functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import './export_const_functions'

// Calling functions held by exported module-level consts from another module.
// See export_const_functions.ts.

function main() {
assert(arrowBlock(2) == 6, "arrowBlock");
assert(arrowExpression(2) == 8, "arrowExpression");
assert(functionExpression(2) == 10, "functionExpression");
assert(arrowWithConstLocal(7) == "v-7", "arrowWithConstLocal");
assert(alias(2) == 14, "alias");
assert(letArrow(2) == 16, "letArrow");
assert(usesNotExported(1) == 101, "usesNotExported");
assert(usesLocalGenerator() == 7, "usesLocalGenerator");
assert(NS.inNamespace(2) == 12, "NS.inNamespace");

print("done.");
}
Loading