From 292ab5923df4b06b972e61da9903253ca7c7ba53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 27 Sep 2023 18:11:19 +0200 Subject: [PATCH 1/5] Error on class fields accesses through `super` in JS files --- src/compiler/utilitiesPublic.ts | 4 +- .../classFieldSuperNotAccessibleJs.errors.txt | 30 ++++++++++ .../classFieldSuperNotAccessibleJs.symbols | 51 +++++++++++++++++ .../classFieldSuperNotAccessibleJs.types | 57 +++++++++++++++++++ .../classFieldSuperNotAccessibleJs.ts | 27 +++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt create mode 100644 tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols create mode 100644 tests/baselines/reference/classFieldSuperNotAccessibleJs.types create mode 100644 tests/cases/compiler/classFieldSuperNotAccessibleJs.ts diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 37257c679eb6e..6e7ea481638ff 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1706,7 +1706,9 @@ export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAcces /** @internal */ export function isClassFieldAndNotAutoAccessor(node: Node): boolean { - return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node); + return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node) || + // handles inferred class fields in JS files + node.kind === SyntaxKind.BinaryExpression; } /** @internal */ diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt new file mode 100644 index 0000000000000..db851bec632e1 --- /dev/null +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt @@ -0,0 +1,30 @@ +index.js(15,22): error TS2855: Class field 'roots' defined by the parent class is not accessible in the child class via super. +index.js(18,22): error TS2855: Class field 'foo' defined by the parent class is not accessible in the child class via super. + + +==== index.js (2 errors) ==== + // https://github.com/microsoft/TypeScript/issues/55884 + + class YaddaBase { + constructor() { + this.roots = "hi"; + this.b() + } + accessor b = () => { + this.foo = 10 + } + } + + class DerivedYadda extends YaddaBase { + get rootTests() { + return super.roots; + ~~~~~ +!!! error TS2855: Class field 'roots' defined by the parent class is not accessible in the child class via super. + } + get fooTests() { + return super.foo; + ~~~ +!!! error TS2855: Class field 'foo' defined by the parent class is not accessible in the child class via super. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols new file mode 100644 index 0000000000000..e54c2b270b7ff --- /dev/null +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols @@ -0,0 +1,51 @@ +//// [tests/cases/compiler/classFieldSuperNotAccessibleJs.ts] //// + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/55884 + +class YaddaBase { +>YaddaBase : Symbol(YaddaBase, Decl(index.js, 0, 0)) + + constructor() { + this.roots = "hi"; +>this.roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) +>this : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) + + this.b() +>this.b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) +>this : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) + } + accessor b = () => { +>b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) + + this.foo = 10 +>this.foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>this : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) + } +} + +class DerivedYadda extends YaddaBase { +>DerivedYadda : Symbol(DerivedYadda, Decl(index.js, 10, 1)) +>YaddaBase : Symbol(YaddaBase, Decl(index.js, 0, 0)) + + get rootTests() { +>rootTests : Symbol(DerivedYadda.rootTests, Decl(index.js, 12, 38)) + + return super.roots; +>super.roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) +>super : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) + } + get fooTests() { +>fooTests : Symbol(DerivedYadda.fooTests, Decl(index.js, 15, 5)) + + return super.foo; +>super.foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>super : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) + } +} + diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.types b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types new file mode 100644 index 0000000000000..427c4540c5c95 --- /dev/null +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/classFieldSuperNotAccessibleJs.ts] //// + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/55884 + +class YaddaBase { +>YaddaBase : YaddaBase + + constructor() { + this.roots = "hi"; +>this.roots = "hi" : "hi" +>this.roots : any +>this : this +>roots : any +>"hi" : "hi" + + this.b() +>this.b() : void +>this.b : () => void +>this : this +>b : () => void + } + accessor b = () => { +>b : () => void +>() => { this.foo = 10 } : () => void + + this.foo = 10 +>this.foo = 10 : 10 +>this.foo : number | undefined +>this : this +>foo : number | undefined +>10 : 10 + } +} + +class DerivedYadda extends YaddaBase { +>DerivedYadda : DerivedYadda +>YaddaBase : YaddaBase + + get rootTests() { +>rootTests : string + + return super.roots; +>super.roots : string +>super : YaddaBase +>roots : string + } + get fooTests() { +>fooTests : number | undefined + + return super.foo; +>super.foo : number | undefined +>super : YaddaBase +>foo : number | undefined + } +} + diff --git a/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts new file mode 100644 index 0000000000000..aaa23436625fd --- /dev/null +++ b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts @@ -0,0 +1,27 @@ +// @strict: true +// @checkJs: true +// @target: esnext +// @noEmit: true + +// @filename: index.js + +// https://github.com/microsoft/TypeScript/issues/55884 + +class YaddaBase { + constructor() { + this.roots = "hi"; + this.b() + } + accessor b = () => { + this.foo = 10 + } +} + +class DerivedYadda extends YaddaBase { + get rootTests() { + return super.roots; + } + get fooTests() { + return super.foo; + } +} From 49d35540e4187dded95d54a6fa4c041f576f8fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 27 Sep 2023 21:03:10 +0200 Subject: [PATCH 2/5] Fix all expando declaration types --- src/compiler/utilitiesPublic.ts | 10 ++-- .../classFieldSuperNotAccessibleJs.errors.txt | 23 +++++++-- .../classFieldSuperNotAccessibleJs.symbols | 47 +++++++++++++++---- .../classFieldSuperNotAccessibleJs.types | 28 +++++++++++ .../classFieldSuperNotAccessibleJs.ts | 11 +++++ 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 6e7ea481638ff..4b616bb765735 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -111,6 +111,7 @@ import { isClassStaticBlockDeclaration, isDecorator, isElementAccessExpression, + isExpandoPropertyDeclaration, isExportAssignment, isExportDeclaration, isExportSpecifier, @@ -1705,10 +1706,11 @@ export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAcces } /** @internal */ -export function isClassFieldAndNotAutoAccessor(node: Node): boolean { - return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node) || - // handles inferred class fields in JS files - node.kind === SyntaxKind.BinaryExpression; +export function isClassFieldAndNotAutoAccessor(node: Declaration): boolean { + if (isInJSFile(node) && isExpandoPropertyDeclaration(node)) { + return true; + } + return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node); } /** @internal */ diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt index db851bec632e1..24c8b83e22b4b 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt @@ -1,13 +1,20 @@ -index.js(15,22): error TS2855: Class field 'roots' defined by the parent class is not accessible in the child class via super. -index.js(18,22): error TS2855: Class field 'foo' defined by the parent class is not accessible in the child class via super. +index.js(20,22): error TS2855: Class field 'roots' defined by the parent class is not accessible in the child class via super. +index.js(23,22): error TS2855: Class field 'foo' defined by the parent class is not accessible in the child class via super. +index.js(26,22): error TS2855: Class field 'justProp' defined by the parent class is not accessible in the child class via super. +index.js(29,22): error TS2855: Class field ''literalElementAccess'' defined by the parent class is not accessible in the child class via super. -==== index.js (2 errors) ==== +==== index.js (4 errors) ==== // https://github.com/microsoft/TypeScript/issues/55884 class YaddaBase { constructor() { this.roots = "hi"; + /** @type number */ + this.justProp; + /** @type string */ + this['literalElementAccess']; + this.b() } accessor b = () => { @@ -26,5 +33,15 @@ index.js(18,22): error TS2855: Class field 'foo' defined by the parent class is ~~~ !!! error TS2855: Class field 'foo' defined by the parent class is not accessible in the child class via super. } + get justPropTests() { + return super.justProp; + ~~~~~~~~ +!!! error TS2855: Class field 'justProp' defined by the parent class is not accessible in the child class via super. + } + get literalElementAccessTests() { + return super.literalElementAccess; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2855: Class field ''literalElementAccess'' defined by the parent class is not accessible in the child class via super. + } } \ No newline at end of file diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols index e54c2b270b7ff..6b0884bdfdf18 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols @@ -12,27 +12,38 @@ class YaddaBase { >this : Symbol(YaddaBase, Decl(index.js, 0, 0)) >roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) + /** @type number */ + this.justProp; +>this.justProp : Symbol(YaddaBase.justProp, Decl(index.js, 4, 26)) +>this : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>justProp : Symbol(YaddaBase.justProp, Decl(index.js, 4, 26)) + + /** @type string */ + this['literalElementAccess']; +>this : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>'literalElementAccess' : Symbol(YaddaBase['literalElementAccess'], Decl(index.js, 6, 22)) + this.b() ->this.b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) +>this.b : Symbol(YaddaBase.b, Decl(index.js, 11, 5)) >this : Symbol(YaddaBase, Decl(index.js, 0, 0)) ->b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) +>b : Symbol(YaddaBase.b, Decl(index.js, 11, 5)) } accessor b = () => { ->b : Symbol(YaddaBase.b, Decl(index.js, 6, 5)) +>b : Symbol(YaddaBase.b, Decl(index.js, 11, 5)) this.foo = 10 ->this.foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>this.foo : Symbol(YaddaBase.foo, Decl(index.js, 12, 24)) >this : Symbol(YaddaBase, Decl(index.js, 0, 0)) ->foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>foo : Symbol(YaddaBase.foo, Decl(index.js, 12, 24)) } } class DerivedYadda extends YaddaBase { ->DerivedYadda : Symbol(DerivedYadda, Decl(index.js, 10, 1)) +>DerivedYadda : Symbol(DerivedYadda, Decl(index.js, 15, 1)) >YaddaBase : Symbol(YaddaBase, Decl(index.js, 0, 0)) get rootTests() { ->rootTests : Symbol(DerivedYadda.rootTests, Decl(index.js, 12, 38)) +>rootTests : Symbol(DerivedYadda.rootTests, Decl(index.js, 17, 38)) return super.roots; >super.roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) @@ -40,12 +51,28 @@ class DerivedYadda extends YaddaBase { >roots : Symbol(YaddaBase.roots, Decl(index.js, 3, 19)) } get fooTests() { ->fooTests : Symbol(DerivedYadda.fooTests, Decl(index.js, 15, 5)) +>fooTests : Symbol(DerivedYadda.fooTests, Decl(index.js, 20, 5)) return super.foo; ->super.foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>super.foo : Symbol(YaddaBase.foo, Decl(index.js, 12, 24)) +>super : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>foo : Symbol(YaddaBase.foo, Decl(index.js, 12, 24)) + } + get justPropTests() { +>justPropTests : Symbol(DerivedYadda.justPropTests, Decl(index.js, 23, 5)) + + return super.justProp; +>super.justProp : Symbol(YaddaBase.justProp, Decl(index.js, 4, 26)) +>super : Symbol(YaddaBase, Decl(index.js, 0, 0)) +>justProp : Symbol(YaddaBase.justProp, Decl(index.js, 4, 26)) + } + get literalElementAccessTests() { +>literalElementAccessTests : Symbol(DerivedYadda.literalElementAccessTests, Decl(index.js, 26, 5)) + + return super.literalElementAccess; +>super.literalElementAccess : Symbol(YaddaBase['literalElementAccess'], Decl(index.js, 6, 22)) >super : Symbol(YaddaBase, Decl(index.js, 0, 0)) ->foo : Symbol(YaddaBase.foo, Decl(index.js, 7, 24)) +>literalElementAccess : Symbol(YaddaBase['literalElementAccess'], Decl(index.js, 6, 22)) } } diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.types b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types index 427c4540c5c95..4b18c03f5ff77 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.types +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types @@ -14,6 +14,18 @@ class YaddaBase { >roots : any >"hi" : "hi" + /** @type number */ + this.justProp; +>this.justProp : number +>this : this +>justProp : number + + /** @type string */ + this['literalElementAccess']; +>this['literalElementAccess'] : any +>this : this +>'literalElementAccess' : "literalElementAccess" + this.b() >this.b() : void >this.b : () => void @@ -53,5 +65,21 @@ class DerivedYadda extends YaddaBase { >super : YaddaBase >foo : number | undefined } + get justPropTests() { +>justPropTests : number + + return super.justProp; +>super.justProp : number +>super : YaddaBase +>justProp : number + } + get literalElementAccessTests() { +>literalElementAccessTests : any + + return super.literalElementAccess; +>super.literalElementAccess : any +>super : YaddaBase +>literalElementAccess : any + } } diff --git a/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts index aaa23436625fd..d20bfc3757cef 100644 --- a/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts +++ b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts @@ -10,6 +10,11 @@ class YaddaBase { constructor() { this.roots = "hi"; + /** @type number */ + this.justProp; + /** @type string */ + this['literalElementAccess']; + this.b() } accessor b = () => { @@ -24,4 +29,10 @@ class DerivedYadda extends YaddaBase { get fooTests() { return super.foo; } + get justPropTests() { + return super.justProp; + } + get literalElementAccessTests() { + return super.literalElementAccess; + } } From 44010a3a03e5fa0156bf994eefedcf3105d2fc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 28 Sep 2023 05:45:47 +0200 Subject: [PATCH 3/5] Fixed bindable prototype accesses --- src/compiler/utilitiesPublic.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 4b616bb765735..a1620e715ae9e 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -102,6 +102,7 @@ import { isArrowFunction, isAssignmentExpression, isBinaryExpression, + isBindableStaticAccessExpression, isBindableStaticElementAccessExpression, isBindingElement, isBlock, @@ -154,6 +155,7 @@ import { isPropertyAccessExpression, isPropertyAssignment, isPropertyDeclaration, + isPrototypeAccess, isRootedDiskPath, isSourceFile, isStringLiteral, @@ -1708,7 +1710,7 @@ export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAcces /** @internal */ export function isClassFieldAndNotAutoAccessor(node: Declaration): boolean { if (isInJSFile(node) && isExpandoPropertyDeclaration(node)) { - return true; + return !isBindableStaticAccessExpression(node) || !isPrototypeAccess(node.expression); } return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node); } From 05b21a032d0d9c6c2d07b4ed394e36cab8cff6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 28 Sep 2023 05:57:35 +0200 Subject: [PATCH 4/5] add a test for the accessor case --- .../reference/classFieldSuperAccessible.js | 17 ++++++++++++++ .../classFieldSuperAccessible.symbols | 20 +++++++++++++++++ .../reference/classFieldSuperAccessible.types | 22 +++++++++++++++++++ .../classFieldSuperNotAccessibleJs.errors.txt | 2 +- .../classFieldSuperNotAccessibleJs.symbols | 2 +- .../classFieldSuperNotAccessibleJs.types | 2 +- .../compiler/classFieldSuperAccessible.ts | 9 ++++++++ .../classFieldSuperNotAccessibleJs.ts | 2 +- 8 files changed, 72 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/classFieldSuperAccessible.js b/tests/baselines/reference/classFieldSuperAccessible.js index 6412b47de38d1..d7ba25a981dea 100644 --- a/tests/baselines/reference/classFieldSuperAccessible.js +++ b/tests/baselines/reference/classFieldSuperAccessible.js @@ -16,6 +16,15 @@ class C extends Array { console.log(super.length); } } + +class D { + accessor b = () => {} +} +class E extends D { + foo() { + super.b() + } +} //// [classFieldSuperAccessible.js] @@ -35,3 +44,11 @@ class C extends Array { console.log(super.length); } } +class D { + accessor b = () => { }; +} +class E extends D { + foo() { + super.b(); + } +} diff --git a/tests/baselines/reference/classFieldSuperAccessible.symbols b/tests/baselines/reference/classFieldSuperAccessible.symbols index 5558ce70f4d7a..9d23d58215b51 100644 --- a/tests/baselines/reference/classFieldSuperAccessible.symbols +++ b/tests/baselines/reference/classFieldSuperAccessible.symbols @@ -46,3 +46,23 @@ class C extends Array { } } +class D { +>D : Symbol(D, Decl(classFieldSuperAccessible.ts, 14, 1)) + + accessor b = () => {} +>b : Symbol(D.b, Decl(classFieldSuperAccessible.ts, 16, 9)) +} +class E extends D { +>E : Symbol(E, Decl(classFieldSuperAccessible.ts, 18, 1)) +>D : Symbol(D, Decl(classFieldSuperAccessible.ts, 14, 1)) + + foo() { +>foo : Symbol(E.foo, Decl(classFieldSuperAccessible.ts, 19, 19)) + + super.b() +>super.b : Symbol(D.b, Decl(classFieldSuperAccessible.ts, 16, 9)) +>super : Symbol(D, Decl(classFieldSuperAccessible.ts, 14, 1)) +>b : Symbol(D.b, Decl(classFieldSuperAccessible.ts, 16, 9)) + } +} + diff --git a/tests/baselines/reference/classFieldSuperAccessible.types b/tests/baselines/reference/classFieldSuperAccessible.types index 8ec922a9f52cb..4de66dd2d0079 100644 --- a/tests/baselines/reference/classFieldSuperAccessible.types +++ b/tests/baselines/reference/classFieldSuperAccessible.types @@ -50,3 +50,25 @@ class C extends Array { } } +class D { +>D : D + + accessor b = () => {} +>b : () => void +>() => {} : () => void +} +class E extends D { +>E : E +>D : D + + foo() { +>foo : () => void + + super.b() +>super.b() : void +>super.b : () => void +>super : D +>b : () => void + } +} + diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt index 24c8b83e22b4b..b48180a81e475 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.errors.txt @@ -14,7 +14,7 @@ index.js(29,22): error TS2855: Class field ''literalElementAccess'' defined by t this.justProp; /** @type string */ this['literalElementAccess']; - + this.b() } accessor b = () => { diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols index 6b0884bdfdf18..954d3acc32ff8 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.symbols @@ -22,7 +22,7 @@ class YaddaBase { this['literalElementAccess']; >this : Symbol(YaddaBase, Decl(index.js, 0, 0)) >'literalElementAccess' : Symbol(YaddaBase['literalElementAccess'], Decl(index.js, 6, 22)) - + this.b() >this.b : Symbol(YaddaBase.b, Decl(index.js, 11, 5)) >this : Symbol(YaddaBase, Decl(index.js, 0, 0)) diff --git a/tests/baselines/reference/classFieldSuperNotAccessibleJs.types b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types index 4b18c03f5ff77..a3a3d7d0920b8 100644 --- a/tests/baselines/reference/classFieldSuperNotAccessibleJs.types +++ b/tests/baselines/reference/classFieldSuperNotAccessibleJs.types @@ -25,7 +25,7 @@ class YaddaBase { >this['literalElementAccess'] : any >this : this >'literalElementAccess' : "literalElementAccess" - + this.b() >this.b() : void >this.b : () => void diff --git a/tests/cases/compiler/classFieldSuperAccessible.ts b/tests/cases/compiler/classFieldSuperAccessible.ts index 92c22f30c1698..1c94a37acf64e 100644 --- a/tests/cases/compiler/classFieldSuperAccessible.ts +++ b/tests/cases/compiler/classFieldSuperAccessible.ts @@ -14,3 +14,12 @@ class C extends Array { console.log(super.length); } } + +class D { + accessor b = () => {} +} +class E extends D { + foo() { + super.b() + } +} diff --git a/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts index d20bfc3757cef..82e723ab661b8 100644 --- a/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts +++ b/tests/cases/compiler/classFieldSuperNotAccessibleJs.ts @@ -14,7 +14,7 @@ class YaddaBase { this.justProp; /** @type string */ this['literalElementAccess']; - + this.b() } accessor b = () => { From 23ec307cbd7d2dd834539cf83e370175e39032d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 28 Sep 2023 06:28:15 +0200 Subject: [PATCH 5/5] Fixed static name expressions --- src/compiler/utilitiesPublic.ts | 3 +- .../classFieldSuperAccessibleJs1.errors.txt | 18 ++++ .../classFieldSuperAccessibleJs1.symbols | 37 ++++++++ .../classFieldSuperAccessibleJs1.types | 42 +++++++++ .../classFieldSuperAccessibleJs2.symbols | 77 ++++++++++++++++ .../classFieldSuperAccessibleJs2.types | 92 +++++++++++++++++++ .../compiler/classFieldSuperAccessibleJs1.ts | 18 ++++ .../compiler/classFieldSuperAccessibleJs2.ts | 30 ++++++ 8 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/classFieldSuperAccessibleJs1.errors.txt create mode 100644 tests/baselines/reference/classFieldSuperAccessibleJs1.symbols create mode 100644 tests/baselines/reference/classFieldSuperAccessibleJs1.types create mode 100644 tests/baselines/reference/classFieldSuperAccessibleJs2.symbols create mode 100644 tests/baselines/reference/classFieldSuperAccessibleJs2.types create mode 100644 tests/cases/compiler/classFieldSuperAccessibleJs1.ts create mode 100644 tests/cases/compiler/classFieldSuperAccessibleJs2.ts diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index a1620e715ae9e..88654c1503f71 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -104,6 +104,7 @@ import { isBinaryExpression, isBindableStaticAccessExpression, isBindableStaticElementAccessExpression, + isBindableStaticNameExpression, isBindingElement, isBlock, isCallExpression, @@ -1710,7 +1711,7 @@ export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAcces /** @internal */ export function isClassFieldAndNotAutoAccessor(node: Declaration): boolean { if (isInJSFile(node) && isExpandoPropertyDeclaration(node)) { - return !isBindableStaticAccessExpression(node) || !isPrototypeAccess(node.expression); + return (!isBindableStaticAccessExpression(node) || !isPrototypeAccess(node.expression)) && !isBindableStaticNameExpression(node, /*excludeThisKeyword*/ true); } return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node); } diff --git a/tests/baselines/reference/classFieldSuperAccessibleJs1.errors.txt b/tests/baselines/reference/classFieldSuperAccessibleJs1.errors.txt new file mode 100644 index 0000000000000..bc9fa32877a26 --- /dev/null +++ b/tests/baselines/reference/classFieldSuperAccessibleJs1.errors.txt @@ -0,0 +1,18 @@ +index.js(9,23): error TS2565: Property 'blah2' is used before being assigned. + + +==== index.js (1 errors) ==== + class C { + static blah1 = 123; + } + C.blah2 = 456; + + class D extends C { + static { + console.log(super.blah1); + console.log(super.blah2); + ~~~~~ +!!! error TS2565: Property 'blah2' is used before being assigned. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/classFieldSuperAccessibleJs1.symbols b/tests/baselines/reference/classFieldSuperAccessibleJs1.symbols new file mode 100644 index 0000000000000..5ab85733594c0 --- /dev/null +++ b/tests/baselines/reference/classFieldSuperAccessibleJs1.symbols @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/classFieldSuperAccessibleJs1.ts] //// + +=== index.js === +class C { +>C : Symbol(C, Decl(index.js, 0, 0), Decl(index.js, 2, 1)) + + static blah1 = 123; +>blah1 : Symbol(C.blah1, Decl(index.js, 0, 9)) +} +C.blah2 = 456; +>C.blah2 : Symbol(C.blah2, Decl(index.js, 2, 1)) +>C : Symbol(C, Decl(index.js, 0, 0), Decl(index.js, 2, 1)) +>blah2 : Symbol(C.blah2, Decl(index.js, 2, 1)) + +class D extends C { +>D : Symbol(D, Decl(index.js, 3, 14)) +>C : Symbol(C, Decl(index.js, 0, 0), Decl(index.js, 2, 1)) + + static { + console.log(super.blah1); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>super.blah1 : Symbol(C.blah1, Decl(index.js, 0, 9)) +>super : Symbol(C, Decl(index.js, 0, 0), Decl(index.js, 2, 1)) +>blah1 : Symbol(C.blah1, Decl(index.js, 0, 9)) + + console.log(super.blah2); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>super.blah2 : Symbol(C.blah2, Decl(index.js, 2, 1)) +>super : Symbol(C, Decl(index.js, 0, 0), Decl(index.js, 2, 1)) +>blah2 : Symbol(C.blah2, Decl(index.js, 2, 1)) + } +} + diff --git a/tests/baselines/reference/classFieldSuperAccessibleJs1.types b/tests/baselines/reference/classFieldSuperAccessibleJs1.types new file mode 100644 index 0000000000000..72353b280feda --- /dev/null +++ b/tests/baselines/reference/classFieldSuperAccessibleJs1.types @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/classFieldSuperAccessibleJs1.ts] //// + +=== index.js === +class C { +>C : C + + static blah1 = 123; +>blah1 : number +>123 : 123 +} +C.blah2 = 456; +>C.blah2 = 456 : 456 +>C.blah2 : number +>C : typeof C +>blah2 : number +>456 : 456 + +class D extends C { +>D : D +>C : C + + static { + console.log(super.blah1); +>console.log(super.blah1) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>super.blah1 : number +>super : typeof C +>blah1 : number + + console.log(super.blah2); +>console.log(super.blah2) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>super.blah2 : number +>super : typeof C +>blah2 : number + } +} + diff --git a/tests/baselines/reference/classFieldSuperAccessibleJs2.symbols b/tests/baselines/reference/classFieldSuperAccessibleJs2.symbols new file mode 100644 index 0000000000000..8a1628b49ecae --- /dev/null +++ b/tests/baselines/reference/classFieldSuperAccessibleJs2.symbols @@ -0,0 +1,77 @@ +//// [tests/cases/compiler/classFieldSuperAccessibleJs2.ts] //// + +=== index.js === +class C { +>C : Symbol(C, Decl(index.js, 0, 0)) + + constructor() { + this.foo = () => { +>this.foo : Symbol(C.foo, Decl(index.js, 5, 3)) +>this : Symbol(C, Decl(index.js, 0, 0)) +>foo : Symbol(C.foo, Decl(index.js, 1, 17)) + + console.log("called arrow"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + }; + } + foo() { +>foo : Symbol(C.foo, Decl(index.js, 5, 3)) + + console.log("called method"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + } +} + +class D extends C { +>D : Symbol(D, Decl(index.js, 9, 1)) +>C : Symbol(C, Decl(index.js, 0, 0)) + + foo() { +>foo : Symbol(D.foo, Decl(index.js, 11, 19)) + + console.log("SUPER:"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + super.foo(); +>super.foo : Symbol(C.foo, Decl(index.js, 5, 3)) +>super : Symbol(C, Decl(index.js, 0, 0)) +>foo : Symbol(C.foo, Decl(index.js, 5, 3)) + + console.log("THIS:"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + this.foo(); +>this.foo : Symbol(D.foo, Decl(index.js, 11, 19)) +>this : Symbol(D, Decl(index.js, 9, 1)) +>foo : Symbol(D.foo, Decl(index.js, 11, 19)) + } +} + +const obj = new D(); +>obj : Symbol(obj, Decl(index.js, 20, 5)) +>D : Symbol(D, Decl(index.js, 9, 1)) + +obj.foo(); +>obj.foo : Symbol(D.foo, Decl(index.js, 11, 19)) +>obj : Symbol(obj, Decl(index.js, 20, 5)) +>foo : Symbol(D.foo, Decl(index.js, 11, 19)) + +D.prototype.foo.call(obj); +>D.prototype.foo.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>D.prototype.foo : Symbol(D.foo, Decl(index.js, 11, 19)) +>D.prototype : Symbol(D.prototype) +>D : Symbol(D, Decl(index.js, 9, 1)) +>prototype : Symbol(D.prototype) +>foo : Symbol(D.foo, Decl(index.js, 11, 19)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>obj : Symbol(obj, Decl(index.js, 20, 5)) + diff --git a/tests/baselines/reference/classFieldSuperAccessibleJs2.types b/tests/baselines/reference/classFieldSuperAccessibleJs2.types new file mode 100644 index 0000000000000..343b3a632169f --- /dev/null +++ b/tests/baselines/reference/classFieldSuperAccessibleJs2.types @@ -0,0 +1,92 @@ +//// [tests/cases/compiler/classFieldSuperAccessibleJs2.ts] //// + +=== index.js === +class C { +>C : C + + constructor() { + this.foo = () => { +>this.foo = () => { console.log("called arrow"); } : () => void +>this.foo : () => void +>this : this +>foo : () => void +>() => { console.log("called arrow"); } : () => void + + console.log("called arrow"); +>console.log("called arrow") : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>"called arrow" : "called arrow" + + }; + } + foo() { +>foo : () => void + + console.log("called method"); +>console.log("called method") : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>"called method" : "called method" + } +} + +class D extends C { +>D : D +>C : C + + foo() { +>foo : () => void + + console.log("SUPER:"); +>console.log("SUPER:") : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>"SUPER:" : "SUPER:" + + super.foo(); +>super.foo() : void +>super.foo : () => void +>super : C +>foo : () => void + + console.log("THIS:"); +>console.log("THIS:") : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>"THIS:" : "THIS:" + + this.foo(); +>this.foo() : void +>this.foo : () => void +>this : this +>foo : () => void + } +} + +const obj = new D(); +>obj : D +>new D() : D +>D : typeof D + +obj.foo(); +>obj.foo() : void +>obj.foo : () => void +>obj : D +>foo : () => void + +D.prototype.foo.call(obj); +>D.prototype.foo.call(obj) : void +>D.prototype.foo.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>D.prototype.foo : () => void +>D.prototype : D +>D : typeof D +>prototype : D +>foo : () => void +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>obj : D + diff --git a/tests/cases/compiler/classFieldSuperAccessibleJs1.ts b/tests/cases/compiler/classFieldSuperAccessibleJs1.ts new file mode 100644 index 0000000000000..3cab7ac7922f4 --- /dev/null +++ b/tests/cases/compiler/classFieldSuperAccessibleJs1.ts @@ -0,0 +1,18 @@ +// @strict: true +// @checkJs: true +// @target: esnext +// @noEmit: true + +// @filename: index.js + +class C { + static blah1 = 123; +} +C.blah2 = 456; + +class D extends C { + static { + console.log(super.blah1); + console.log(super.blah2); + } +} diff --git a/tests/cases/compiler/classFieldSuperAccessibleJs2.ts b/tests/cases/compiler/classFieldSuperAccessibleJs2.ts new file mode 100644 index 0000000000000..23e9f9e6cc3a9 --- /dev/null +++ b/tests/cases/compiler/classFieldSuperAccessibleJs2.ts @@ -0,0 +1,30 @@ +// @strict: true +// @checkJs: true +// @target: esnext +// @noEmit: true + +// @filename: index.js + +class C { + constructor() { + this.foo = () => { + console.log("called arrow"); + }; + } + foo() { + console.log("called method"); + } +} + +class D extends C { + foo() { + console.log("SUPER:"); + super.foo(); + console.log("THIS:"); + this.foo(); + } +} + +const obj = new D(); +obj.foo(); +D.prototype.foo.call(obj);