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
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace typescript
void printFunction(StringRef, ArrayRef<mlir::Type>, mlir::Type);
void printMethod(bool, StringRef, ArrayRef<mlir::Type>, mlir::Type, mlir::Type);
void printAccessor(bool, StringRef, StringRef, mlir_ts::AccessLevel, ArrayRef<mlir::Type>, mlir::Type, mlir::Type);
void printIndexer(mlir::Type, mlir::Type);
void printNamespaceBegin(NamespaceInfo::TypePtr);
void printNamespaceEnd(NamespaceInfo::TypePtr);
void print(mlir::Type);
Expand Down
30 changes: 29 additions & 1 deletion tslang/lib/TypeScript/DeclarationPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,20 @@ namespace typescript
newline();
}

void MLIRDeclarationPrinter::printTypeDeclaration(StringRef name, NamespaceInfo::TypePtr elementNamespace, mlir::Type type)
void MLIRDeclarationPrinter::printIndexer(mlir::Type indexType, mlir::Type resultType)
{
os.indent(4);

os << "[p0: ";
print(indexType);
os << "]: ";
print(resultType);
os << ";";

newline();
}

void MLIRDeclarationPrinter::printTypeDeclaration(StringRef name, NamespaceInfo::TypePtr elementNamespace, mlir::Type type)
{
printNamespaceBegin(elementNamespace);

Expand Down Expand Up @@ -493,6 +506,21 @@ namespace typescript
newline();
}

// index signature ([x: T]: U;) - not stored in storageType's fields,
// and (unlike accessors) its get/set methods are ordinary named
// "get"/"set" methods already covered by the methods loop below; only
// the signature declaration itself is missing from a plain method
// reprint, and without it a reimporting module's ClassInfo::indexes
// stays empty so `obj[i]`/`super[i]` can't resolve (see
// super-index-access-gap-fix memory).
for (auto indexInfo : classType->indexes)
{
if (!indexInfo.indexSignature || indexInfo.indexSignature.getNumResults() == 0)
continue;

printIndexer(indexInfo.indexSignature.getInput(0), indexInfo.indexSignature.getResult(0));
}

// methods (including static)
for (auto method : classType->methods)
{
Expand Down
70 changes: 70 additions & 0 deletions tslang/lib/TypeScript/MLIRGenAccessCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,76 @@ namespace mlirgen
// same as it always did for `super.method()`/`super.<accessor>`.
auto effectiveThisValue = getThisRefOfClass(location, classInfo->classType, thisValue, isSuperClass, genContext);

if (classInfo->isDynamicImport)
{
// same reasoning as ClassAccessorAccess's isDynamicImport branch: a plain
// FlatSymbolRefAttr lowers to a call the static linker must resolve, but a
// -shared importer never links against the exporter's .lib (see
// cross-module-instanceof-investigation.md) - resolve get/set to VALUEs
// (direct ref / dlsym-style global / inline SearchForAddressOfSymbolOp) and
// drive the call through ThisIndirectIndexAccessorOp instead.
auto resolveIndexFunc = [&](FunctionEntry funcEntry) -> mlir::Value {
if (!funcEntry)
{
return mlir::Value();
}

StringRef funcName = funcEntry.name;
auto effectiveFuncType = funcEntry.funcType;

if (auto funcOp = theModule.lookupSymbol<mlir_ts::FuncOp>(funcName))
{
if (!funcOp.getBody().empty())
{
return builder.create<mlir_ts::SymbolRefOp>(
location, effectiveFuncType, mlir::FlatSymbolRefAttr::get(builder.getContext(), funcName));
}
}

auto globalFuncVar = resolveFullNameIdentifier(location, funcName, false, genContext);
if (!globalFuncVar)
{
auto symbolNameValue = V(mlirGenStringValue(location, funcName.str(), true));
auto referenceToFuncOpaque = builder.create<mlir_ts::SearchForAddressOfSymbolOp>(
location, getOpaqueType(), symbolNameValue);
auto castResult = cast(location, effectiveFuncType, referenceToFuncOpaque, genContext);
if (castResult.failed_or_no_value())
{
emitError(location, "Class member '") << funcName << "' can't be resolved (dynamic import)";
return mlir::Value();
}

globalFuncVar = V(castResult);
}

return globalFuncVar;
};

auto getterValue = resolveIndexFunc(getFunc);
auto setterValue = resolveIndexFunc(setFunc);
if ((getFunc && !getterValue) || (setFunc && !setterValue))
{
return mlir::Value();
}

auto opaqueThisType = mlir_ts::OpaqueType::get(builder.getContext());
if (!getterValue)
{
getterValue = builder.create<mlir_ts::UndefOp>(
location, mlir_ts::FunctionType::get(builder.getContext(), {opaqueThisType, argumentType}, {indexResultType}, false));
}

if (!setterValue)
{
setterValue = builder.create<mlir_ts::UndefOp>(
location, mlir_ts::FunctionType::get(builder.getContext(), {opaqueThisType, argumentType, indexResultType}, {}, false));
}

auto thisIndirectIndexAccessorOp = builder.create<mlir_ts::ThisIndirectIndexAccessorOp>(
location, indexResultType, effectiveThisValue, V(result), getterValue, setterValue, mlir::Value());
return thisIndirectIndexAccessorOp.getResult(0);
}

auto thisIndexAccessorOp = builder.create<mlir_ts::ThisIndexAccessorOp>(
location, indexResultType, effectiveThisValue, V(result),
getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name)
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 @@ -885,6 +885,7 @@ add_test(NAME test-compile-export-import-class-static COMMAND test-runner "${PRO
# See class-generic-declaration-export-fix memory for the full account.
add_test(NAME test-compile-export-import-class-generic COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_generic.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_generic.ts")
add_test(NAME test-compile-export-import-class-accessor COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_accessor.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_accessor.ts")
add_test(NAME test-compile-export-import-class-indexer COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_indexer.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_indexer.ts")
add_test(NAME test-compile-export-import-class-implements-interface-multilevel COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_implements_interface_multilevel.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_implements_interface_multilevel.ts")
add_test(NAME test-compile-export-import-class-implements-interface-optional COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_implements_interface_optional.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_implements_interface_optional.ts")
add_test(NAME test-compile-export-import-class-implements-interface-abstract COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_implements_interface_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_implements_interface_abstract.ts")
Expand Down Expand Up @@ -959,6 +960,7 @@ add_test(NAME test-compile-shared-export-import-class-generic COMMAND test-runne
# never populated the reimported class's accessors list. See print(ClassInfo::TypePtr)
# in DeclarationPrinter.cpp.
add_test(NAME test-compile-shared-export-import-class-accessor COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_accessor.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_accessor.ts")
add_test(NAME test-compile-shared-export-import-class-indexer COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_indexer.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_indexer.ts")
add_test(NAME test-compile-shared-export-import-object-literal-with-interface COMMAND test-runner -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_with_interface.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_with_interface.ts")
add_test(NAME test-compile-shared-export-import-object-literal-untyped COMMAND test-runner -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_untyped.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_untyped.ts")
add_test(NAME test-compile-shared-export-import-object-literal-untyped-multi-method COMMAND test-runner -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_untyped_multi_method.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_untyped_multi_method.ts")
Expand Down Expand Up @@ -999,6 +1001,7 @@ add_test(NAME test-jit-shared-export-import-class-structural-interface COMMAND t
add_test(NAME test-jit-shared-export-import-class-generic COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_generic.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_generic.ts")
# FIXED: see the matching test-compile-shared-export-import-class-accessor comment above (2026-07-22).
add_test(NAME test-jit-shared-export-import-class-accessor COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_accessor.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_accessor.ts")
add_test(NAME test-jit-shared-export-import-class-indexer COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_indexer.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_indexer.ts")
add_test(NAME test-jit-shared-export-import-object-literal-with-interface COMMAND test-runner -jit -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_with_interface.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_with_interface.ts")
add_test(NAME test-jit-shared-export-import-object-literal-untyped COMMAND test-runner -jit -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_untyped.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_untyped.ts")
add_test(NAME test-jit-shared-export-import-object-literal-untyped-multi-method COMMAND test-runner -jit -shared -gctors-as-method "${PROJECT_SOURCE_DIR}/test/tester/tests/import_object_literal_untyped_multi_method.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_object_literal_untyped_multi_method.ts")
Expand Down
21 changes: 21 additions & 0 deletions tslang/test/tester/tests/export_class_indexer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace M {

// A get/set indexer pair defined in the exporting module, overridden in
// an importer subclass which calls back into the base indexer via
// `super[index]`. Cross-module counterpart to 00class_indexer_super.ts
// (same-file) - see super-index-access-gap-fix memory.

export class Storage {
protected _val: string = "";

[index: number]: string;

get(index: number): string {
return this._val;
}

set(index: number, value: string) {
this._val = value;
}
}
}
21 changes: 21 additions & 0 deletions tslang/test/tester/tests/import_class_indexer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import './export_class_indexer'

class UpperStorage extends M.Storage {
[index: number]: string;

get(index: number): string {
return super[index] + "!";
}

set(index: number, value: string) {
super[index] = "U:" + value;
}
}

function main() {
const s = new UpperStorage();
s[0] = "hi";
assert(s[0] == "U:hi!");

print("done.");
}
Loading