Skip to content

Commit 1cd16ba

Browse files
authored
Support using super accessors (#1532)
1 parent ee3dfcf commit 1cd16ba

File tree

7 files changed

+136
-49
lines changed

7 files changed

+136
-49
lines changed

src/LuaLib.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export enum LuaLibFeature {
4848
DecorateParam = "DecorateParam",
4949
Delete = "Delete",
5050
DelegatedYield = "DelegatedYield",
51+
DescriptorGet = "DescriptorGet",
52+
DescriptorSet = "DescriptorSet",
5153
Error = "Error",
5254
FunctionBind = "FunctionBind",
5355
Generator = "Generator",

src/lualib/DescriptorGet.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const getmetatable = _G.getmetatable;
2+
const rawget = _G.rawget;
3+
4+
export function __TS__DescriptorGet(this: any, metatable: any, key: string): void {
5+
while (metatable) {
6+
const rawResult = rawget(metatable, key as any);
7+
if (rawResult !== undefined) {
8+
return rawResult;
9+
}
10+
11+
const descriptors = rawget(metatable, "_descriptors");
12+
if (descriptors) {
13+
const descriptor: PropertyDescriptor = descriptors[key];
14+
if (descriptor !== undefined) {
15+
if (descriptor.get) {
16+
return descriptor.get.call(this);
17+
}
18+
19+
return descriptor.value;
20+
}
21+
}
22+
23+
metatable = getmetatable(metatable);
24+
}
25+
}

src/lualib/DescriptorSet.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const getmetatable = _G.getmetatable;
2+
const rawget = _G.rawget;
3+
const rawset = _G.rawset;
4+
5+
export function __TS__DescriptorSet(this: any, metatable: any, key: string, value: any): void {
6+
while (metatable) {
7+
const descriptors = rawget(metatable, "_descriptors");
8+
if (descriptors) {
9+
const descriptor: PropertyDescriptor = descriptors[key];
10+
if (descriptor !== undefined) {
11+
if (descriptor.set) {
12+
descriptor.set.call(this, value);
13+
} else {
14+
if (descriptor.writable === false) {
15+
throw `Cannot assign to read only property '${key}' of object '${this}'`;
16+
}
17+
18+
descriptor.value = value;
19+
}
20+
return;
21+
}
22+
}
23+
24+
metatable = getmetatable(metatable);
25+
}
26+
27+
rawset(this, key, value);
28+
}

src/lualib/SetDescriptor.ts

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,15 @@
11
import { __TS__CloneDescriptor } from "./CloneDescriptor";
2+
import { __TS__DescriptorGet } from "./DescriptorGet";
3+
import { __TS__DescriptorSet } from "./DescriptorSet";
24

3-
function descriptorIndex(this: any, key: string): void {
4-
const value = rawget(this, key);
5-
if (value !== null) {
6-
return value;
7-
}
8-
9-
let metatable = getmetatable(this);
10-
while (metatable) {
11-
const rawResult = rawget(metatable, key as any);
12-
if (rawResult !== undefined) {
13-
return rawResult;
14-
}
5+
const getmetatable = _G.getmetatable;
156

16-
const descriptors = rawget(metatable, "_descriptors");
17-
if (descriptors) {
18-
const descriptor: PropertyDescriptor = descriptors[key];
19-
if (descriptor !== undefined) {
20-
if (descriptor.get) {
21-
return descriptor.get.call(this);
22-
}
23-
24-
return descriptor.value;
25-
}
26-
}
27-
28-
metatable = getmetatable(metatable);
29-
}
7+
function descriptorIndex(this: any, key: string): void {
8+
return __TS__DescriptorGet.call(this, getmetatable(this), key);
309
}
3110

3211
function descriptorNewIndex(this: any, key: string, value: any): void {
33-
let metatable = getmetatable(this);
34-
while (metatable) {
35-
const descriptors = rawget(metatable, "_descriptors");
36-
if (descriptors) {
37-
const descriptor: PropertyDescriptor = descriptors[key];
38-
if (descriptor !== undefined) {
39-
if (descriptor.set) {
40-
descriptor.set.call(this, value);
41-
} else {
42-
if (descriptor.writable === false) {
43-
throw `Cannot assign to read only property '${key}' of object '${this}'`;
44-
}
45-
46-
descriptor.value = value;
47-
}
48-
return;
49-
}
50-
}
51-
52-
metatable = getmetatable(metatable);
53-
}
54-
55-
rawset(this, key, value);
12+
return __TS__DescriptorSet.call(this, getmetatable(this), key, value);
5613
}
5714

5815
// It's also used directly in class transform to add descriptors to the prototype

src/transformation/visitors/access.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
isOptionalContinuation,
2323
captureThisValue,
2424
} from "./optional-chaining";
25+
import { SyntaxKind } from "typescript";
2526

2627
function addOneToArrayAccessArgument(
2728
context: TransformationContext,
@@ -173,6 +174,18 @@ export function transformPropertyAccessExpressionWithCapture(
173174
thisValue,
174175
};
175176
}
177+
if (node.expression.kind === SyntaxKind.SuperKeyword) {
178+
return {
179+
expression: transformLuaLibFunction(
180+
context,
181+
LuaLibFeature.DescriptorGet,
182+
node,
183+
lua.createIdentifier("self"),
184+
table,
185+
lua.createStringLiteral(property)
186+
),
187+
};
188+
}
176189
return { expression: lua.createTableIndexExpression(table, lua.createStringLiteral(property), node) };
177190
}
178191

src/transformation/visitors/binary-expression/assignments.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as ts from "typescript";
2+
import { SyntaxKind } from "typescript";
23
import * as lua from "../../../LuaAST";
34
import { TransformationContext } from "../../context";
45
import { validateAssignment } from "../../utils/assignment-validation";
@@ -75,6 +76,26 @@ export function transformAssignment(
7576
return [arrayLengthAssignment];
7677
}
7778

79+
if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) {
80+
if (lhs.expression.kind === SyntaxKind.SuperKeyword) {
81+
return [
82+
lua.createExpressionStatement(
83+
transformLuaLibFunction(
84+
context,
85+
LuaLibFeature.DescriptorSet,
86+
parent,
87+
lua.createIdentifier("self"),
88+
context.transformExpression(lhs.expression),
89+
ts.isPropertyAccessExpression(lhs)
90+
? lua.createStringLiteral(lhs.name.text)
91+
: context.transformExpression(lhs.argumentExpression),
92+
right
93+
)
94+
),
95+
];
96+
}
97+
}
98+
7899
const symbol =
79100
lhs.parent && ts.isShorthandPropertyAssignment(lhs.parent)
80101
? context.checker.getShorthandAssignmentValueSymbol(lhs.parent)

test/unit/classes/accessors.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,44 @@ test("static get/set accessors in base class", () => {
327327
return fooOriginal + Bar.foo;
328328
`.expectToMatchJsResult();
329329
});
330+
331+
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1437
332+
test("super class get accessor (#1437)", () => {
333+
util.testFunction`
334+
class A {
335+
get foo() {
336+
return "A";
337+
}
338+
}
339+
340+
class B extends A {
341+
override get foo() {
342+
return super.foo + "B";
343+
}
344+
}
345+
346+
return new B().foo;
347+
`.expectToMatchJsResult();
348+
});
349+
350+
test("super class set accessor", () => {
351+
util.testFunction`
352+
let result = "unset";
353+
354+
class A {
355+
set result(value: string) {
356+
result = "foo" + value;
357+
}
358+
}
359+
360+
class B extends A {
361+
override set result(value: string) {
362+
super.result = "bar" + value;
363+
}
364+
}
365+
366+
new B().result = "baz";
367+
368+
return result;
369+
`.expectToMatchJsResult();
370+
});

0 commit comments

Comments
 (0)