Skip to content

Commit 697a912

Browse files
committed
fix Object.defineProperty sharing values across instances
When Object.defineProperty is called on an instance (not a prototype), create a per-instance metatable if the shared metatable already has descriptors, so that each instance gets its own descriptor storage. Fixes #1625
1 parent c3dc829 commit 697a912

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

src/lualib/SetDescriptor.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ export function __TS__SetDescriptor(
2626
setmetatable(target, metatable);
2727
}
2828

29+
// When setting a descriptor on an instance (not a prototype), ensure it has
30+
// its own metatable so descriptors are not shared across instances.
31+
// See: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1625
32+
if (!isPrototype && rawget(metatable, "_descriptors")) {
33+
// The metatable already has descriptors from a previous defineProperty
34+
// call (likely on a different instance sharing the same class metatable).
35+
// Create a per-instance metatable that chains to the original.
36+
const instanceMetatable: any = {};
37+
setmetatable(instanceMetatable, metatable);
38+
setmetatable(target, instanceMetatable);
39+
metatable = instanceMetatable;
40+
}
41+
2942
const value = rawget(target, key);
3043
if (value !== undefined) rawset(target, key, undefined);
3144

test/unit/builtins/object.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,21 @@ describe("Object.defineProperty", () => {
196196
return { prop: foo.bar, err };
197197
`.expectToMatchJsResult();
198198
});
199+
200+
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1625
201+
test("instance isolation", () => {
202+
util.testFunction`
203+
class Test {
204+
declare obj: object;
205+
constructor() {
206+
Object.defineProperty(this, "obj", { value: {}, writable: true, configurable: true });
207+
}
208+
}
209+
const t1 = new Test();
210+
const t2 = new Test();
211+
return t1.obj === t2.obj;
212+
`.expectToMatchJsResult();
213+
});
199214
});
200215

201216
describe("Object.getOwnPropertyDescriptor", () => {

0 commit comments

Comments
 (0)