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
85 changes: 85 additions & 0 deletions tslang/lib/TypeScript/MLIRGenFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,22 @@ namespace mlirgen
LLVM_DEBUG(dbgs() << "\n!! binding param " << namePtr << " is type " << type << "\n");
}

// a set accessor's value without a type is of the type its get accessor returns
if (mth.isNoneType(type) && kind == SyntaxKind::SetAccessor && !typeParameter && !initializer)
{
auto [result, getAccessorType] = getPairedGetAccessorType(parametersContextAST, genContext);
if (mlir::failed(result))
{
return {mlir::failure(), isGenericTypes, params};
}

if (getAccessorType)
{
type = getAccessorType;
isGenericTypes |= mth.isGenericType(type);
}
}

if (mth.isNoneType(type))
{
if (!typeParameter && !initializer)
Expand Down Expand Up @@ -373,6 +389,75 @@ namespace mlirgen
return {mlir::success(), isGenericTypes, params};
}

// the type a class's set accessor takes when its parameter has none: what the get accessor of the
// same name returns. No type when the class has no such get accessor; a failure while the get
// accessor, declared after the set accessor, is not resolved yet (mlirGenClassMembers retries it).
std::tuple<mlir::LogicalResult, mlir::Type> MLIRGenImpl::getPairedGetAccessorType(
SignatureDeclarationBase setAccessorAST, const GenContext &genContext)
{
auto parent = setAccessorAST->parent;
if (parent != SyntaxKind::ClassDeclaration && parent != SyntaxKind::ClassExpression)
{
return {mlir::success(), mlir::Type()};
}

auto [name, nameResult] = getNameForMethod(setAccessorAST, genContext);
if (!nameResult || name.empty())
{
return {mlir::success(), mlir::Type()};
}

auto isStatic = hasModifier(setAccessorAST, SyntaxKind::StaticKeyword);
FunctionLikeDeclarationBase getAccessorAST;
for (auto &classMember : parent.as<ClassLikeDeclaration>()->members)
{
if (classMember != SyntaxKind::GetAccessor || hasModifier(classMember, SyntaxKind::StaticKeyword) != isStatic)
{
continue;
}

auto getAccessor = classMember.as<FunctionLikeDeclarationBase>();
auto [getName, getNameResult] = getNameForMethod(getAccessor, genContext);
if (getNameResult && getName == name)
{
getAccessorAST = getAccessor;
break;
}
}

if (!getAccessorAST)
{
return {mlir::success(), mlir::Type()};
}

if (getAccessorAST->type)
{
auto type = getType(getAccessorAST->type, genContext);
return {type ? mlir::success() : mlir::failure(), type};
}

// the type the get accessor's body gives it, once the get accessor is registered
if (genContext.thisClassType)
{
if (auto classInfo = getClassInfoByFullName(genContext.thisClassType.getName().getValue()))
{
auto accessorIndex = classInfo->getAccessorIndex(name);
if (accessorIndex >= 0)
{
auto &getFunc = classInfo->accessors[accessorIndex].get;
if (getFunc)
{
return {mlir::success(), getFunc.funcType.getNumResults() > 0
? getFunc.funcType.getResult(0)
: mlir::Type()};
}
}
}
}

return {mlir::failure(), mlir::Type()};
}

std::tuple<std::string, std::string> MLIRGenImpl::getNameOfFunction(SignatureDeclarationBase signatureDeclarationBaseAST,
const GenContext &genContext)
{
Expand Down
41 changes: 34 additions & 7 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3276,6 +3276,9 @@ class MLIRGenImpl
std::tuple<mlir::LogicalResult, bool, std::vector<std::shared_ptr<FunctionParamDOM>>> mlirGenParameters(
SignatureDeclarationBase parametersContextAST, const GenContext &genContext);

std::tuple<mlir::LogicalResult, mlir::Type> getPairedGetAccessorType(SignatureDeclarationBase setAccessorAST,
const GenContext &genContext);

std::tuple<std::string, std::string> getNameOfFunction(SignatureDeclarationBase signatureDeclarationBaseAST,
const GenContext &genContext);

Expand Down Expand Up @@ -6781,6 +6784,30 @@ class MLIRGenImpl
}
};

// a set accessor takes the value as its last parameter, whose type need not be the one its get
// accessor returns (the accessor's type)
auto setAccessorValueType = [&](mlir::Type setAccessorType, mlir::Type accessorType) -> mlir::Type {
if (!mth.isAnyFunctionType(setAccessorType))
{
return accessorType;
}

auto params = mth.getParamsFromFuncRef(setAccessorType);
return params.empty() ? accessorType : params.back();
};

auto setAccessorSymbolValueType = [&](mlir::FlatSymbolRefAttr setAccessor, mlir::Type accessorType) -> mlir::Type {
if (setAccessor)
{
if (auto funcOp = theModule.lookupSymbol<mlir_ts::FuncOp>(setAccessor))
{
return setAccessorValueType(funcOp.getFunctionType(), accessorType);
}
}

return accessorType;
};

// TODO: logic to support safe cast
if (auto safeCastOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::SafeCastOp>())
{
Expand Down Expand Up @@ -6898,7 +6925,7 @@ class MLIRGenImpl
}
else if (auto accessorOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::AccessorOp>())
{
syncSavingValue(accessorOp.getType(0));
syncSavingValue(setAccessorSymbolValueType(accessorOp.getSetAccessorAttr(), accessorOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6913,7 +6940,7 @@ class MLIRGenImpl
}
else if (auto thisAccessorOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::ThisAccessorOp>())
{
syncSavingValue(thisAccessorOp.getType(0));
syncSavingValue(setAccessorSymbolValueType(thisAccessorOp.getSetAccessorAttr(), thisAccessorOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6928,7 +6955,7 @@ class MLIRGenImpl
}
else if (auto thisAccessorIndirectOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::ThisIndirectAccessorOp>())
{
syncSavingValue(thisAccessorIndirectOp.getType(0));
syncSavingValue(setAccessorValueType(thisAccessorIndirectOp.getSetAccessor().getType(), thisAccessorIndirectOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6945,7 +6972,7 @@ class MLIRGenImpl
}
else if (auto thisIndexAccessorOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::ThisIndexAccessorOp>())
{
syncSavingValue(thisIndexAccessorOp.getType(0));
syncSavingValue(setAccessorSymbolValueType(thisIndexAccessorOp.getSetAccessorAttr(), thisIndexAccessorOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6960,7 +6987,7 @@ class MLIRGenImpl
}
else if (auto thisIndirectIndexAccessorOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::ThisIndirectIndexAccessorOp>())
{
syncSavingValue(thisIndirectIndexAccessorOp.getType(0));
syncSavingValue(setAccessorValueType(thisIndirectIndexAccessorOp.getSetAccessor().getType(), thisIndirectIndexAccessorOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6975,7 +7002,7 @@ class MLIRGenImpl
}
else if (auto boundAccessorIndirectOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::BoundIndirectAccessorOp>())
{
syncSavingValue(boundAccessorIndirectOp.getType(0));
syncSavingValue(setAccessorValueType(boundAccessorIndirectOp.getSetAccessor().getType(), boundAccessorIndirectOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
Expand All @@ -6991,7 +7018,7 @@ class MLIRGenImpl
}
else if (auto boundIndirectIndexAccessorOp = leftExpressionValueBeforeCast.getDefiningOp<mlir_ts::BoundIndirectIndexAccessorOp>())
{
syncSavingValue(boundIndirectIndexAccessorOp.getType(0));
syncSavingValue(setAccessorValueType(boundIndirectIndexAccessorOp.getSetAccessor().getType(), boundIndirectIndexAccessorOp.getType(0)));
if (!savingValue)
{
return mlir::failure();
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 @@ -609,6 +609,7 @@ tslang_add_test(NAME test-compile-00-class-accessor-super COMMAND test-runner "$
tslang_add_test(NAME test-compile-00-class-accessor-virtual COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_virtual.ts")
tslang_add_test(NAME test-compile-00-class-accessor-implements-field COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_implements_field.ts")
tslang_add_test(NAME test-compile-00-object-literal-contextual-lambda COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00object_literal_contextual_lambda.ts")
tslang_add_test(NAME test-compile-00-class-accessor-untyped-setter COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_untyped_setter.ts")
tslang_add_test(NAME test-compile-00-class-super COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super.ts")
tslang_add_test(NAME test-compile-00-class-implicit-constructor COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_implicit_constructor.ts")
tslang_add_test(NAME test-compile-00-class-super-static COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super_static.ts")
Expand Down Expand Up @@ -1224,6 +1225,7 @@ tslang_add_test(NAME test-jit-00-class-accessor-super COMMAND test-runner -jit "
tslang_add_test(NAME test-jit-00-class-accessor-virtual COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_virtual.ts")
tslang_add_test(NAME test-jit-00-class-accessor-implements-field COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_implements_field.ts")
tslang_add_test(NAME test-jit-00-object-literal-contextual-lambda COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00object_literal_contextual_lambda.ts")
tslang_add_test(NAME test-jit-00-class-accessor-untyped-setter COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_accessor_untyped_setter.ts")
tslang_add_test(NAME test-jit-00-class-super COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super.ts")
tslang_add_test(NAME test-jit-00-class-implicit-constructor COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_implicit_constructor.ts")
tslang_add_test(NAME test-jit-00-class-super-static COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00class_super_static.ts")
Expand Down Expand Up @@ -2178,6 +2180,7 @@ set(TSLANG_CORPUS
00class_accessor_virtual.ts
00class_accessor_implements_field.ts
00object_literal_contextual_lambda.ts
00class_accessor_untyped_setter.ts
00class_accessor.ts
00class_accessor2.ts
00class_constr_fields.ts
Expand Down
57 changes: 57 additions & 0 deletions tslang/test/tester/tests/00class_accessor_untyped_setter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// a set accessor's parameter without a type takes the type its get accessor returns
class GetFirst {
f = 1;
get prop() { return this.f; }
set prop(v) { print("set", v); this.f = v; }
}

// the get accessor after the set accessor
class SetFirst {
f = 1;
set prop(v) { this.f = v + 1; }
get prop() { return this.f; }
}

// a get accessor with a written type
class Typed {
s = "";
get prop(): string { return this.s; }
set prop(v) { this.s = v + "!"; }
}

class Static {
static f = 1;
static get prop() { return Static.f; }
static set prop(v) { Static.f = v * 2; }
}

// the value is given to a set accessor as the type it takes, not as the one its get accessor returns
class AnySetter {
f = 1;
get prop() { return this.f; }
set prop(v: any) { this.f = v; }
}

function main() {
const c = new GetFirst();
c.prop = 5;
print(c.prop);
assert(c.prop == 5);

const s = new SetFirst();
s.prop = 5;
assert(s.prop == 6);

const t = new Typed();
t.prop = "hi";
assert(t.prop == "hi!");

Static.prop = 4;
assert(Static.prop == 8);

const a = new AnySetter();
a.prop = 7;
assert(a.prop == 7);

print("done.");
}
Loading