diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77128466cd..b34869f788 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26443,7 +26443,9 @@ namespace ts { node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement, isSuper: boolean, type: Type, prop: Symbol): boolean { const flags = getDeclarationModifierFlagsFromSymbol(prop); - const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : node.kind === SyntaxKind.ImportType ? node : node.name; + const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : + node.kind === SyntaxKind.ImportType ? node : + node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; if (isSuper) { // TS 1.0 spec (April 2014): 4.8.2 @@ -26470,7 +26472,8 @@ namespace ts { } // Referencing abstract properties within their own constructors is not allowed - if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) { + if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) && + (isThisProperty(node) || isThisInitializedObjectBindingExpression(node) || isObjectBindingPattern(node.parent) && isThisInitializedDeclaration(node.parent.parent))) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!); if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node)) { error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217 @@ -34698,7 +34701,7 @@ namespace ts { const property = getPropertyOfType(parentType, nameText); if (property) { markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isThisAccess*/ false); // A destructuring is never a write-only reference. - checkPropertyAccessibility(parent, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property); + checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property); } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e30462c20b..71e382fe5e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1731,6 +1731,14 @@ namespace ts { return !!node && isVariableDeclaration(node) && node.initializer?.kind === SyntaxKind.ThisKeyword; } + export function isThisInitializedObjectBindingExpression(node: Node | undefined): boolean { + return !!node + && (isShorthandPropertyAssignment(node) || isPropertyAssignment(node)) + && isBinaryExpression(node.parent.parent) + && node.parent.parent.operatorToken.kind === SyntaxKind.EqualsToken + && node.parent.parent.right.kind === SyntaxKind.ThisKeyword; + } + export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression | undefined { switch (node.kind) { case SyntaxKind.TypeReference: diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 030369d81e..8b98c0816e 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -4,9 +4,14 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2729: Property 'prop' is used before its initialization. tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(78,15): error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(78,18): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(79,12): error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(79,15): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(79,22): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. -==== tests/cases/compiler/abstractPropertyInConstructor.ts (6 errors) ==== +==== tests/cases/compiler/abstractPropertyInConstructor.ts (11 errors) ==== abstract class AbstractClass { constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); @@ -90,4 +95,36 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abst a.method2(); } } + + abstract class C1 { + abstract x: string; + abstract y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // error + ~ +!!! error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor. + ~ +!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. + ({ x, y: y1, "y": y1 } = this); // error + ~ +!!! error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor. + ~ +!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. + ~~~ +!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor. + } + } + + class C2 { + x: string; + y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // ok + ({ x, y: y1, "y": y1 } = this); // ok + } + } \ No newline at end of file diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js index 9048a5b9c4..95fc2bfaa0 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -69,6 +69,28 @@ class User { a.method2(); } } + +abstract class C1 { + abstract x: string; + abstract y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // error + ({ x, y: y1, "y": y1 } = this); // error + } +} + +class C2 { + x: string; + y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // ok + ({ x, y: y1, "y": y1 } = this); // ok + } +} //// [abstractPropertyInConstructor.js] @@ -148,3 +170,21 @@ var User = /** @class */ (function () { } return User; }()); +var C1 = /** @class */ (function () { + function C1() { + var _a; + var self = this; // ok + var _b = this, x = _b.x, y1 = _b.y; // error + (_a = this, x = _a.x, y1 = _a.y, y1 = _a["y"]); // error + } + return C1; +}()); +var C2 = /** @class */ (function () { + function C2() { + var _a; + var self = this; // ok + var _b = this, x = _b.x, y1 = _b.y; // ok + (_a = this, x = _a.x, y1 = _a.y, y1 = _a["y"]); // ok + } + return C2; +}()); diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index 628ee5c857..d75b31d140 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -224,3 +224,63 @@ class User { } } +abstract class C1 { +>C1 : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1)) + + abstract x: string; +>x : Symbol(C1.x, Decl(abstractPropertyInConstructor.ts, 71, 19)) + + abstract y: string; +>y : Symbol(C1.y, Decl(abstractPropertyInConstructor.ts, 72, 23)) + + constructor() { + let self = this; // ok +>self : Symbol(self, Decl(abstractPropertyInConstructor.ts, 76, 11)) +>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1)) + + let { x, y: y1 } = this; // error +>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 77, 13)) +>y : Symbol(C1.y, Decl(abstractPropertyInConstructor.ts, 72, 23)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16)) +>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1)) + + ({ x, y: y1, "y": y1 } = this); // error +>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 78, 10)) +>y : Symbol(y, Decl(abstractPropertyInConstructor.ts, 78, 13), Decl(abstractPropertyInConstructor.ts, 78, 20)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16)) +>"y" : Symbol(y, Decl(abstractPropertyInConstructor.ts, 78, 13), Decl(abstractPropertyInConstructor.ts, 78, 20)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16)) +>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1)) + } +} + +class C2 { +>C2 : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1)) + + x: string; +>x : Symbol(C2.x, Decl(abstractPropertyInConstructor.ts, 82, 10)) + + y: string; +>y : Symbol(C2.y, Decl(abstractPropertyInConstructor.ts, 83, 14)) + + constructor() { + let self = this; // ok +>self : Symbol(self, Decl(abstractPropertyInConstructor.ts, 87, 11)) +>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1)) + + let { x, y: y1 } = this; // ok +>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 88, 13)) +>y : Symbol(C2.y, Decl(abstractPropertyInConstructor.ts, 83, 14)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16)) +>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1)) + + ({ x, y: y1, "y": y1 } = this); // ok +>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 89, 10)) +>y : Symbol(y, Decl(abstractPropertyInConstructor.ts, 89, 13), Decl(abstractPropertyInConstructor.ts, 89, 20)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16)) +>"y" : Symbol(y, Decl(abstractPropertyInConstructor.ts, 89, 13), Decl(abstractPropertyInConstructor.ts, 89, 20)) +>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16)) +>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1)) + } +} + diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index e63737006c..ee8500d702 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -250,3 +250,69 @@ class User { } } +abstract class C1 { +>C1 : C1 + + abstract x: string; +>x : string + + abstract y: string; +>y : string + + constructor() { + let self = this; // ok +>self : this +>this : this + + let { x, y: y1 } = this; // error +>x : string +>y : any +>y1 : string +>this : this + + ({ x, y: y1, "y": y1 } = this); // error +>({ x, y: y1, "y": y1 } = this) : this +>{ x, y: y1, "y": y1 } = this : this +>{ x, y: y1, "y": y1 } : { x: string; y: string; } +>x : string +>y : string +>y1 : string +>"y" : string +>y1 : string +>this : this + } +} + +class C2 { +>C2 : C2 + + x: string; +>x : string + + y: string; +>y : string + + constructor() { + let self = this; // ok +>self : this +>this : this + + let { x, y: y1 } = this; // ok +>x : string +>y : any +>y1 : string +>this : this + + ({ x, y: y1, "y": y1 } = this); // ok +>({ x, y: y1, "y": y1 } = this) : this +>{ x, y: y1, "y": y1 } = this : this +>{ x, y: y1, "y": y1 } : { x: string; y: string; } +>x : string +>y : string +>y1 : string +>"y" : string +>y1 : string +>this : this + } +} + diff --git a/tests/baselines/reference/destructureComputedProperty.errors.txt b/tests/baselines/reference/destructureComputedProperty.errors.txt index ad6e8042f8..942f77d978 100644 --- a/tests/baselines/reference/destructureComputedProperty.errors.txt +++ b/tests/baselines/reference/destructureComputedProperty.errors.txt @@ -1,7 +1,7 @@ -tests/cases/compiler/destructureComputedProperty.ts(7,7): error TS2341: Property 'p' is private and only accessible within class 'C'. -tests/cases/compiler/destructureComputedProperty.ts(8,7): error TS2341: Property 'p' is private and only accessible within class 'C'. -tests/cases/compiler/destructureComputedProperty.ts(9,7): error TS2341: Property 'p' is private and only accessible within class 'C'. -tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Property 'p' is private and only accessible within class 'C'. +tests/cases/compiler/destructureComputedProperty.ts(7,9): error TS2341: Property 'p' is private and only accessible within class 'C'. +tests/cases/compiler/destructureComputedProperty.ts(8,9): error TS2341: Property 'p' is private and only accessible within class 'C'. +tests/cases/compiler/destructureComputedProperty.ts(9,9): error TS2341: Property 'p' is private and only accessible within class 'C'. +tests/cases/compiler/destructureComputedProperty.ts(10,9): error TS2341: Property 'p' is private and only accessible within class 'C'. ==== tests/cases/compiler/destructureComputedProperty.ts (4 errors) ==== @@ -12,15 +12,15 @@ tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Propert class C { private p: number; } const nameP = "p"; const { "p": p0 } = new C(); - ~~~~~~~~~~~ + ~~~ !!! error TS2341: Property 'p' is private and only accessible within class 'C'. const { ["p"]: p1 } = new C(); - ~~~~~~~~~~~~~ + ~~~~~ !!! error TS2341: Property 'p' is private and only accessible within class 'C'. const { [nameP]: p2 } = new C(); - ~~~~~~~~~~~~~~~ + ~~~~~~~ !!! error TS2341: Property 'p' is private and only accessible within class 'C'. const { p: p3 } = new C(); - ~~~~~~~~~ + ~ !!! error TS2341: Property 'p' is private and only accessible within class 'C'. \ No newline at end of file diff --git a/tests/baselines/reference/privateProtectedMembersAreNotAccessibleDestructuring.errors.txt b/tests/baselines/reference/privateProtectedMembersAreNotAccessibleDestructuring.errors.txt index 9c0db527fe..40c6f13615 100644 --- a/tests/baselines/reference/privateProtectedMembersAreNotAccessibleDestructuring.errors.txt +++ b/tests/baselines/reference/privateProtectedMembersAreNotAccessibleDestructuring.errors.txt @@ -1,13 +1,13 @@ -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(12,13): error TS2341: Property 'priv' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(17,5): error TS2341: Property 'priv' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(18,5): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(19,5): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2341: Property 'priv' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2341: Property 'priv' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. -tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(12,15): error TS2341: Property 'priv' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(17,7): error TS2341: Property 'priv' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(18,7): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(19,7): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,7): error TS2341: Property 'priv' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,16): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,25): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,14): error TS2341: Property 'priv' is private and only accessible within class 'K'. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,20): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. +tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,26): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. ==== tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts (10 errors) ==== @@ -23,35 +23,35 @@ tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAre class C extends K { m2() { let { priv: a } = this; // error - ~~~~~~~~~~~ + ~~~~ !!! error TS2341: Property 'priv' is private and only accessible within class 'K'. let { prot: b } = this; // ok } } let k = new K(); let { priv } = k; // error - ~~~~~~~~ + ~~~~ !!! error TS2341: Property 'priv' is private and only accessible within class 'K'. let { prot } = k; // error - ~~~~~~~~ + ~~~~ !!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. let { privateMethod } = k; // error - ~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~ !!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. let { priv: a, prot: b, privateMethod: pm } = k; // error - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ !!! error TS2341: Property 'priv' is private and only accessible within class 'K'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ !!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. + ~~~~~~~~~~~~~ +!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. function f({ priv, prot, privateMethod }: K) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ !!! error TS2341: Property 'priv' is private and only accessible within class 'K'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ !!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses. + ~~~~~~~~~~~~~ +!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'. } \ No newline at end of file diff --git a/tests/cases/compiler/abstractPropertyInConstructor.ts b/tests/cases/compiler/abstractPropertyInConstructor.ts index a665431bb4..b6b375e2d1 100644 --- a/tests/cases/compiler/abstractPropertyInConstructor.ts +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -68,3 +68,25 @@ class User { a.method2(); } } + +abstract class C1 { + abstract x: string; + abstract y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // error + ({ x, y: y1, "y": y1 } = this); // error + } +} + +class C2 { + x: string; + y: string; + + constructor() { + let self = this; // ok + let { x, y: y1 } = this; // ok + ({ x, y: y1, "y": y1 } = this); // ok + } +}