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 @@ -35,6 +35,7 @@ namespace typescript
void printParams(ArrayRef<mlir::Type>, mlir::Type);
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 printNamespaceBegin(NamespaceInfo::TypePtr);
void printNamespaceEnd(NamespaceInfo::TypePtr);
void print(mlir::Type);
Expand Down
73 changes: 73 additions & 0 deletions tslang/lib/TypeScript/DeclarationPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,38 @@ namespace typescript
}
}

void MLIRDeclarationPrinter::printAccessor(bool isStatic, StringRef keyword, StringRef name, mlir_ts::AccessLevel accessLevel,
ArrayRef<mlir::Type> params, mlir::Type returnType, mlir::Type thisType)
{
os.indent(4);

if (accessLevel == mlir_ts::AccessLevel::Protected)
{
os << "protected ";
}
else if (accessLevel == mlir_ts::AccessLevel::Private)
{
os << "private ";
}

if (isStatic)
{
os << "static ";
}

os << keyword << " " << name;

printParams(params, thisType);

if (returnType)
{
os << " : ";
print(returnType);
}

newline();
}

void MLIRDeclarationPrinter::printTypeDeclaration(StringRef name, NamespaceInfo::TypePtr elementNamespace, mlir::Type type)
{
printNamespaceBegin(elementNamespace);
Expand Down Expand Up @@ -467,6 +499,22 @@ namespace typescript
if (filterName(method.name))
continue;

// get/set accessors are ALSO registered here under their mangled
// "get_x"/"set_x" funcOp name (so same-file/JIT compiles can find them as
// ordinary methods) - but that mangled form is printed separately below,
// via classType->accessors, using real `get`/`set` syntax. Printing it
// again here as a plain method would make the importer register it as an
// ordinary MethodDeclaration instead of a GetAccessor/SetAccessor, so
// property-style access (`obj.x`, `super.x`) would never populate the
// reconstructed class's accessors list and fail to resolve.
if (llvm::any_of(classType->accessors, [&](auto &accessor) {
return (accessor.get && accessor.get.name == method.funcName) ||
(accessor.set && accessor.set.name == method.funcName);
}))
{
continue;
}

os.indent(4);

if (method.accessLevel == mlir_ts::AccessLevel::Protected)
Expand All @@ -488,6 +536,31 @@ namespace typescript
newline();
}

// accessors
for (auto accessor : classType->accessors)
{
if (filterName(accessor.name))
continue;

if (accessor.get)
{
printAccessor(
accessor.isStatic, "get", accessor.name, accessor.getAccessLevel,
accessor.get.funcType.getParams(),
accessor.get.funcType.getNumResults() > 0 ? accessor.get.funcType.getResult(0) : mlir::Type(),
classType->classType);
}

if (accessor.set)
{
printAccessor(
accessor.isStatic, "set", accessor.name, accessor.setAccessLevel,
accessor.set.funcType.getParams(),
mlir::Type(),
classType->classType);
}
}

// TODO: we can't declare generic methods, otherwise we need to declare body of methods
// generic methods
// for (auto method : classType->staticGenericMethods)
Expand Down
72 changes: 72 additions & 0 deletions tslang/lib/TypeScript/MLIRGenAccessCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,78 @@ namespace mlirgen
else
{
auto effectiveThisValue = getThisRefOfClass(location, classInfo->classType, thisValue, isSuperClass, genContext);

if (classInfo->isDynamicImport)
{
// A plain FlatSymbolRefAttr (the path below) 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), so it needs the same runtime
// resolution ClassMethodAccess already does for dynamic-import members: resolve
// each accessor function to a VALUE (direct ref / dlsym-style global / inline
// SearchForAddressOfSymbolOp) and drive the call through the "indirect"
// (function-pointer) accessor op instead of the symbol-attr one.
auto resolveAccessorFunc = [&](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 = resolveAccessorFunc(getFunc);
auto setterValue = resolveAccessorFunc(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}, {accessorResultType}, false));
}

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

auto thisIndirectAccessorOp = builder.create<mlir_ts::ThisIndirectAccessorOp>(
location, accessorResultType, effectiveThisValue, getterValue, setterValue, mlir::Value());
return thisIndirectAccessorOp.getResult(0);
}

auto thisAccessorOp = builder.create<mlir_ts::ThisAccessorOp>(
location, accessorResultType, effectiveThisValue,
getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name)
Expand Down
16 changes: 8 additions & 8 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -951,12 +951,12 @@ add_test(NAME test-compile-shared-export-import-class-structural-interface COMMA
# add_test(NAME test-compile-shared-export-import-class-implements-interface-abstract COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_implements_interface_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_implements_interface_abstract.ts")
# FIXED: see the matching test-compile-export-import-class-generic comment above (2026-07-22).
add_test(NAME test-compile-shared-export-import-class-generic COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_generic.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_generic.ts")
# DISABLED: known issue found 2026-07-22 (separate from the super-accessor-call crash fixed
# above). Under the -shared dynamic-import path, a base class's get/set accessors are not
# resolvable at all from a derived class in another module ("Class member 'celsius' can't be
# found") - the same class of gap as the disabled generic-class tests: declaration
# reconstruction for a dynamically-imported class is incomplete for some member kinds.
# 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")
# FIXED (2026-07-22): the -shared declaration-reconstruction path never printed real
# get/set syntax for a class's accessors, only the underlying get_x/set_x funcOps as
# ordinary methods - so property-style access ("Class member 'celsius' can't be found")
# 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-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 @@ -995,8 +995,8 @@ add_test(NAME test-jit-shared-export-import-class-structural-interface COMMAND t
# add_test(NAME test-jit-shared-export-import-class-implements-interface-abstract COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_implements_interface_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_implements_interface_abstract.ts")
# FIXED: see the matching test-compile-export-import-class-generic comment above (2026-07-22).
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")
# DISABLED: see the matching test-compile-shared-export-import-class-accessor comment above (known issue, 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")
# 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-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
Loading