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
10 changes: 6 additions & 4 deletions tslang/lib/TypeScript/MLIRGenAccessCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,9 @@ namespace mlirgen
}
}

mlir::Value MLIRGenImpl::ClassAccessorAccess(ClassInfo::TypePtr classInfo,
mlir::Location location, mlir::Value thisValue, int accessorIndex, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext)
mlir::Value MLIRGenImpl::ClassAccessorAccess(ClassInfo::TypePtr classInfo,
mlir::Location location, mlir::Value thisValue, int accessorIndex,
bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext)
{

auto accessorInfo = classInfo->accessors[accessorIndex];
Expand Down Expand Up @@ -589,8 +590,9 @@ namespace mlirgen
}
else
{
auto effectiveThisValue = getThisRefOfClass(location, classInfo->classType, thisValue, isSuperClass, genContext);
auto thisAccessorOp = builder.create<mlir_ts::ThisAccessorOp>(
location, accessorResultType, thisValue,
location, accessorResultType, effectiveThisValue,
getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name)
: mlir::FlatSymbolRefAttr{},
setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name)
Expand Down Expand Up @@ -736,7 +738,7 @@ namespace mlirgen
auto accessorIndex = classInfo->getAccessorIndex(name);
if (accessorIndex >= 0)
{
return ClassAccessorAccess(classInfo, location, thisValue, accessorIndex, accessingFromLevel, genContext);
return ClassAccessorAccess(classInfo, location, thisValue, accessorIndex, isSuperClass, accessingFromLevel, genContext);
}

for (auto [index, baseClass] : enumerate(classInfo->baseClasses))
Expand Down
5 changes: 3 additions & 2 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5522,8 +5522,9 @@ class MLIRGenImpl
mlir::Location location, mlir::Value thisValue, int genericMethodIndex,
bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext);

mlir::Value ClassAccessorAccess(ClassInfo::TypePtr classInfo,
mlir::Location location, mlir::Value thisValue, int accessorIndex, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext);
mlir::Value ClassAccessorAccess(ClassInfo::TypePtr classInfo,
mlir::Location location, mlir::Value thisValue, int accessorIndex,
bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext);

// TODO: why isSuperClass is not used here?
mlir::Value ClassIndexAccess(ClassInfo::TypePtr classInfo,
Expand Down
35 changes: 35 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ add_test(NAME test-compile-00-class-static-block COMMAND test-runner "${PROJECT_
add_test(NAME test-compile-00-class-discover-types COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_discover_types.ts")
add_test(NAME test-compile-00-class-accessor COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor.ts")
add_test(NAME test-compile-00-class-accessor-2 COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor2.ts")
add_test(NAME test-compile-00-class-accessor-super COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_super.ts")
add_test(NAME test-compile-00-class-super COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super.ts")
add_test(NAME test-compile-00-class-super-static COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super_static.ts")
add_test(NAME test-compile-00-class-default-constructor COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_def_constr.ts")
Expand Down Expand Up @@ -596,6 +597,7 @@ add_test(NAME test-jit-00-class-static-block COMMAND test-runner -jit "${PROJECT
add_test(NAME test-jit-00-class-discover-types COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_discover_types.ts")
add_test(NAME test-jit-00-class-accessor COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor.ts")
add_test(NAME test-jit-00-class-accessor-2 COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor2.ts")
add_test(NAME test-jit-00-class-accessor-super COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_super.ts")
add_test(NAME test-jit-00-class-super COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super.ts")
add_test(NAME test-jit-00-class-super-static COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super_static.ts")
add_test(NAME test-jit-00-class-default-constructor COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_def_constr.ts")
Expand Down Expand Up @@ -850,6 +852,23 @@ add_test(NAME test-compile-export-import-class-interface COMMAND test-runner "${
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")
add_test(NAME test-compile-export-import-class-extends-multilevel COMMAND test-runner "${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-compile-export-import-class-extends-implements-diamond COMMAND test-runner "${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-export-import-class-abstract COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_abstract.ts")
add_test(NAME test-compile-export-import-class-static COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_static.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_static.ts")
# Cross-module generic class instantiation: DISABLED, known issue found 2026-07-22. A generic
# class specialization instantiated in the IMPORTING module incorrectly inherits `export`
# (dllexport) linkage from the original `export class` declaration, even though the
# specialization is defined fresh, locally, in this module. For a multi-type-param generic
# (Pair<A,B>) the resulting mangled name contains a raw comma
# (M.Pair<!ts.number,!ts.string>..instanceOf), which is a linker-directive metacharacter -
# lld rejects it with "invalid /export:". Separately, the -shared tiers fail even earlier:
# once a compiled .dll/.lib for the exporting module already exists next to its .ts source,
# import resolution reads declarations back from that binary artifact instead of
# reparsing source, and that path has no representation for an uninstantiated generic
# template at all, so the whole namespace (M) fails to resolve ("can't resolve name: M").
# Re-enable once both are fixed; test files are kept in the tree (export_class_generic.ts /
# import_class_generic.ts) for that follow-up.
# 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")

# shared libs tests (dlls/compile-time)
add_test(NAME test-compile-time-shared-decl-emit-type COMMAND test-runner -shared -compile-time "${PROJECT_SOURCE_DIR}/test/tester/tests/emit_compiletime_func.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/decl_type.ts")
Expand Down Expand Up @@ -878,6 +897,16 @@ add_test(NAME test-compile-shared-export-import-object-literal-with-class-types
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")
add_test(NAME test-compile-shared-export-import-class-abstract COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_abstract.ts")
add_test(NAME test-compile-shared-export-import-class-static COMMAND test-runner -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_static.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_static.ts")
# DISABLED: see the matching test-compile-export-import-class-generic comment above (known issue, 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")
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 @@ -907,6 +936,12 @@ add_test(NAME test-jit-shared-export-import-object-literal-with-class-types COMM
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")
add_test(NAME test-jit-shared-export-import-class-abstract COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_abstract.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_abstract.ts")
add_test(NAME test-jit-shared-export-import-class-static COMMAND test-runner -jit -shared "${PROJECT_SOURCE_DIR}/test/tester/tests/import_class_static.ts" "${PROJECT_SOURCE_DIR}/test/tester/tests/export_class_static.ts")
# DISABLED: see the matching test-compile-export-import-class-generic comment above (known issue, 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")
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
46 changes: 46 additions & 0 deletions tslang/test/tester/tests/00class_accessor_super.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class Temperature {
protected _celsius: number = 0;

get celsius(): number {
return this._celsius;
}

set celsius(v: number) {
this._celsius = v;
}

get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
}

// overriding an accessor and calling back into the base implementation via
// `super.<accessor>` / `super.<accessor> = value` used to crash MLIR
// verification: the setter call's `this` operand was left as a raw by-value
// ClassStorageType struct instead of being materialized to a pointer (the
// same repair ordinary `super.method()` calls already got via
// getThisRefOfClass), so `'llvm.call' op operand type mismatch` was thrown
// the first time this combination was exercised (found via the cross-module
// accessor test, but the bug itself is general, not cross-module-specific).
class ClampedTemperature extends Temperature {
get celsius(): number {
return super.celsius;
}

set celsius(v: number) {
super.celsius = v < 0 ? 0 : v;
}
}

function main() {
const t = new ClampedTemperature();
t.celsius = -10;
assert(t.celsius == 0);
assert(t.fahrenheit == 32);

t.celsius = 100;
assert(t.celsius == 100);
assert(t.fahrenheit == 212);

print("done.");
}
30 changes: 30 additions & 0 deletions tslang/test/tester/tests/export_class_abstract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace M {

// 2-level abstract chain (abstract extends abstract) defined entirely in
// the exporting module - the importer supplies the first concrete
// override. This is the class analogue of the cross-module optional/vtable
// interface coverage but for abstract methods specifically: an abstract
// method's vtable slot has no implementation in the declaring module at
// all, so the slot must be patched purely from a module that never even
// sees the base class definition being compiled alongside it.

export abstract class Shape {
color: string = "red";

abstract area(): number;

describe(): string {
return `${this.color} area=${this.area()}`;
}
}

export abstract class NamedShape extends Shape {
name: string = "shape";

abstract area(): number;

describe(): string {
return `${this.name}:${super.describe()}`;
}
}
}
27 changes: 27 additions & 0 deletions tslang/test/tester/tests/export_class_accessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace M {

// A get/set accessor pair defined in the exporting module, overridden in
// an importer subclass which calls back into the base accessor via
// `super.celsius`. `super.<accessor> = value` across a module boundary
// used to crash MLIR verification (the `this` operand for the setter
// call was left as a raw by-value ClassStorageType struct instead of
// being materialized to a pointer via getThisRefOfClass, unlike ordinary
// super method calls) - fixed by threading isSuperClass through
// ClassAccessorAccess.

export class Temperature {
protected _celsius: number = 0;

get celsius(): number {
return this._celsius;
}

set celsius(v: number) {
this._celsius = v;
}

get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
}
}
38 changes: 38 additions & 0 deletions tslang/test/tester/tests/export_class_generic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace M {

// Generic class exported from one module and instantiated with concrete
// type arguments in another. Each distinct instantiation (Box<number>,
// Box<string>, Pair<number,string>) needs its own correctly-laid-out
// fields/methods to be materialized across the module boundary, not just
// a single generic-erased shape.

export class Box<T> {
value: T;

constructor(v: T) {
this.value = v;
}

get(): T {
return this.value;
}

set(v: T): void {
this.value = v;
}
}

export class Pair<A, B> {
first: A;
second: B;

constructor(a: A, b: B) {
this.first = a;
this.second = b;
}

swapDescribe(): string {
return `${this.second}-${this.first}`;
}
}
}
22 changes: 22 additions & 0 deletions tslang/test/tester/tests/export_class_static.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace M {

// Static fields/methods defined in the exporting module, inherited (not
// shadowed) by a subclass in the importer. TS static members are shared,
// not per-subclass storage - `Derived.count` and `Base.count` must be the
// SAME global cell across a module boundary, and `super.increment()`
// called from a static method in the importer must reach the base's
// static method and mutate the base's storage in place.

export class Counter {
static count: number = 0;
static label: string = "counter";

static increment(n: number): void {
Counter.count = Counter.count + n;
}

static describe(): string {
return `${Counter.label}:${Counter.count}`;
}
}
}
34 changes: 34 additions & 0 deletions tslang/test/tester/tests/import_class_abstract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import './export_class_abstract'

class Circle extends M.NamedShape {
radius: number = 2;

constructor() {
super();
this.name = "circle";
}

area(): number {
return 3 * this.radius * this.radius; // fake pi=3 to keep the check integer-exact
}
}

function main() {
const c = new Circle();
assert(c.area() == 12);
assert(c.describe() == "circle:red area=12");

// virtual dispatch of both the abstract method (area) and the concrete
// override (describe, which itself calls the abstract method through
// `this`) must still reach Circle's implementation through every
// abstract-typed ancestor reference.
const asNamedShape: M.NamedShape = c;
assert(asNamedShape.area() == 12);
assert(asNamedShape.describe() == "circle:red area=12");

const asShape: M.Shape = c;
assert(asShape.area() == 12);
assert(asShape.describe() == "circle:red area=12");

print("done.");
}
Loading
Loading