diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index def01ddca..437187ceb 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -854,10 +854,10 @@ final case class JSClassNewDecl( if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") nestedTypes.foreach(t => buffer += s" #$t;") - if (!privateMem.isEmpty) { - privateMem.foreach(f => buffer += s" #${f};") - privateMem.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") - } + privateMem.distinct.foreach(f => { + buffer += s" #${f};" + buffer += s" get ${f}() { return this.#${f}; }" + }) buffer += s" constructor($params) {" if (`extends`.isDefined) { val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index b910fd293..527ea98f1 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -212,8 +212,8 @@ class Baz { //│ if (this.#Baz === undefined) { //│ class Baz { //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor() { //│ this.#x = 123; diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls new file mode 100644 index 000000000..4de74414b --- /dev/null +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -0,0 +1,131 @@ +:NewParser +:NewDefs + +:js +class C(a: int) { let a = 1 } +//│ class C(a: int) { +//│ let a: 1 +//│ } +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #C; +//│ constructor() { +//│ } +//│ get C() { +//│ const outer = this; +//│ if (this.#C === undefined) { +//│ class C { +//│ #a; +//│ get a() { return this.#a; } +//│ constructor(a) { +//│ this.#a = a; +//│ this.#a = 1; +//│ const a1 = this.#a; +//│ } +//│ }; +//│ this.#C = ((a) => new C(a)); +//│ this.#C.class = C; +//│ } +//│ return this.#C; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.C = typing_unit.C; +//│ // End of generated code + +// should return 1 +let a = C(2) +a.a +//│ let a: C +//│ 1 +//│ a +//│ = C {} +//│ res +//│ = 1 + +:js +class C2(a: int, b: int) { + let a = b + 1 + let b = a + 1 +} +//│ class C2(a: int, b: int) { +//│ let a: int +//│ let b: int +//│ } +//│ // Prelude +//│ class TypingUnit2 { +//│ #C2; +//│ constructor() { +//│ } +//│ get C2() { +//│ const outer = this; +//│ if (this.#C2 === undefined) { +//│ class C2 { +//│ #a; +//│ get a() { return this.#a; } +//│ #b; +//│ get b() { return this.#b; } +//│ constructor(a, b) { +//│ this.#a = a; +//│ this.#b = b; +//│ this.#a = b + 1; +//│ const a1 = this.#a; +//│ this.#b = a1 + 1; +//│ const b1 = this.#b; +//│ } +//│ }; +//│ this.#C2 = ((a, b) => new C2(a, b)); +//│ this.#C2.class = C2; +//│ } +//│ return this.#C2; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.C2 = typing_unit2.C2; +//│ // End of generated code + +let c2 = C2(1, 2) +c2.a +c2.b +//│ let c2: C2 +//│ int +//│ c2 +//│ = C2 {} +//│ res +//│ = 3 +//│ res +//│ = 4 + +class C3(a: int) { + let a = 42 + class C4(a: int) { + let a = 44 + } +} +//│ class C3(a: int) { +//│ class C4(a: int) { +//│ let a: 44 +//│ } +//│ let a: 42 +//│ } + +:e +let c3 = C3(1) +let c4 = c3.C4(2) +c3.a +c4.a +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.115: let c4 = c3.C4(2) +//│ ╙── ^^^ +//│ let c3: C3 +//│ let c4: error +//│ error +//│ c3 +//│ = C3 {} +//│ c4 +//│ = C4 {} +//│ res +//│ = 42 +//│ res +//│ = 44 diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 080ba588a..6a63e89e6 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -19,8 +19,8 @@ class Lit(n: int) //│ if (this.#Add === undefined) { //│ class Add { //│ #lhs; -//│ #rhs; //│ get lhs() { return this.#lhs; } +//│ #rhs; //│ get rhs() { return this.#rhs; } //│ constructor(lhs, rhs) { //│ this.#lhs = lhs; @@ -66,8 +66,8 @@ class Lit(n: int) //│ │ │ if (this.#Add === undefined) { //│ │ │ class Add { //│ │ │ #lhs; -//│ │ │ #rhs; //│ │ │ get lhs() { return this.#lhs; } +//│ │ │ #rhs; //│ │ │ get rhs() { return this.#rhs; } //│ │ │ constructor(lhs, rhs) { //│ │ │ this.#lhs = lhs; diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 9fbb2464d..887b3af4f 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -582,8 +582,8 @@ module H { //│ if (this.#J === undefined) { //│ class J { //│ #x; -//│ #i; //│ get x() { return this.#x; } +//│ #i; //│ get i() { return this.#i; } //│ constructor(x) { //│ this.#x = x; @@ -666,8 +666,8 @@ ij.incY //│ class I { //│ #J; //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -679,8 +679,8 @@ ij.incY //│ if (this.#J === undefined) { //│ class J { //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -1125,8 +1125,8 @@ I(1).J(3).a //│ class I { //│ #J; //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -1138,8 +1138,8 @@ I(1).J(3).a //│ if (this.#J === undefined) { //│ class J { //│ #z; -//│ #a; //│ get z() { return this.#z; } +//│ #a; //│ get a() { return this.#a; } //│ constructor(z) { //│ this.#z = z; @@ -1378,8 +1378,8 @@ class Outer1(outer: int) { //│ if (this.#Outer2 === undefined) { //│ class Outer2 { //│ #x; -//│ #outer; //│ get x() { return this.#x; } +//│ #outer; //│ get outer() { return this.#outer; } //│ constructor(x) { //│ this.#x = x; diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 5cac01cd9..aa500a3b7 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -50,8 +50,8 @@ mixin Foo1 { //│ const outer = this; //│ return (class Foo1 extends base { //│ #foo0; -//│ #foo1; //│ get foo0() { return this.#foo0; } +//│ #foo1; //│ get foo1() { return this.#foo1; } //│ constructor(...rest) { //│ super(...rest);