diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bce4d21032df8..746522e61faf1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5097,6 +5097,13 @@ namespace ts { let targetSig = targetSignatures[0]; if (sourceSig && targetSig) { + if (kind === SignatureKind.Construct) { + result &= signatureVisibilityRelatedTo(sourceSig, targetSig); + if (result !== Ternary.True) { + return result; + } + } + let sourceErasedSignature = getErasedSignature(sourceSig); let targetErasedSignature = getErasedSignature(targetSig); @@ -5136,6 +5143,32 @@ namespace ts { } } return result; + + function signatureVisibilityRelatedTo(sourceSig: Signature, targetSig: Signature) { + if (sourceSig && targetSig && sourceSig.declaration && sourceSig.declaration.kind === SyntaxKind.Constructor) { + if (sourceSig.declaration && targetSig.declaration) { + let sourceVisibility = sourceSig.declaration.modifiers ? sourceSig.declaration.modifiers.flags : 0; + let targetVisibility = targetSig.declaration.modifiers ? targetSig.declaration.modifiers.flags : 0; + if (sourceVisibility !== targetVisibility && (!((sourceVisibility | targetVisibility) & NodeFlags.Public))) { + if (reportErrors) { + reportError(Diagnostics.Cannot_assign_a_0_constructor_to_a_1_constructor, visibilityToText(sourceVisibility), visibilityToText(targetVisibility)); + } + return Ternary.False; + } + } + } + return Ternary.True; + + function visibilityToText(flag: NodeFlags) { + if (flag === NodeFlags.Private) { + return "private"; + } + if (flag === NodeFlags.Protected) { + return "protected"; + } + return "public"; + } + } } function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary { @@ -8641,6 +8674,9 @@ namespace ts { result = chooseOverload(candidates, assignableRelation); } if (result) { + // Check to see if constructor accessibility is valid for this call + checkConstructorVisibility(result, node); + return result; } @@ -8697,6 +8733,45 @@ namespace ts { } return resolveErrorCall(node); + + function checkConstructorVisibility(signature: Signature, node: NewExpression) { + let constructor = result.declaration; + if (!constructor || !node.expression) { + return; + } + // if constructor is public, we don't need to check visibility + if (constructor.flags & NodeFlags.Public) { + return; + } + + let expressionType = checkExpression(node.expression); + expressionType = getApparentType(expressionType); + if (expressionType === unknownType) { + return; + } + + let declaration = expressionType.symbol && getDeclarationOfKind(expressionType.symbol, SyntaxKind.ClassDeclaration); + if (!declaration) { + return; + } + + // Get the declaring and enclosing class instance types + let enclosingClassDeclaration = getContainingClass(node); + let enclosingClass = enclosingClassDeclaration ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined; + let declaringClass = getDeclaredTypeOfSymbol(getSymbolOfNode(declaration)); + if (constructor.flags & NodeFlags.Private) { + // A private constructor is only accessible in the declaring class + if (declaringClass !== enclosingClass) { + reportError(Diagnostics.Constructor_of_type_0_is_private_and_only_accessible_within_class_1, signatureToString(result), typeToString(declaringClass)); + } + } + else if (constructor.flags & NodeFlags.Protected) { + // A protected constructor is only accessible in the declaring class and classes derived from it + if (!enclosingClass || !hasBaseType(enclosingClass, declaringClass)) { + reportError(Diagnostics.Constructor_of_type_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, signatureToString(result), typeToString(declaringClass)); + } + } + } function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void { let errorInfo: DiagnosticMessageChain; @@ -10738,7 +10813,7 @@ namespace ts { error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); } else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) { - error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); + error(o.name || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); } else if (deviation & NodeFlags.Abstract) { error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_not_abstract); @@ -14778,12 +14853,6 @@ namespace ts { if (flags & NodeFlags.Abstract) { return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract"); } - else if (flags & NodeFlags.Protected) { - return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected"); - } - else if (flags & NodeFlags.Private) { - return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private"); - } else if (flags & NodeFlags.Async) { return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); } @@ -15003,7 +15072,25 @@ namespace ts { if (heritageClause.types.length > 1) { return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); } - + + // if the base class (the class to extend) has a private constructor, + // then the derived class should not be allowed to extend it. + if (heritageClause.types.length == 1) { + let expression = heritageClause.types[0].expression; + if (expression) { + let baseType = getApparentType(checkExpression(expression)); + if (baseType !== unknownType) { + let signatures = getSignaturesOfType(baseType, SignatureKind.Construct); + for (let signature of signatures) { + let constuctor = signature.declaration; + if (constuctor && (constuctor.flags & NodeFlags.Private)) { + return grammarErrorOnFirstToken(expression, Diagnostics.Cannot_extend_private_class_0, (expression).text); + } + } + } + } + } + seenExtendsClause = true; } else { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 5ccc0a0db9b40..704615b2f4adb 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -427,6 +427,10 @@ namespace ts { Cannot_emit_namespaced_JSX_elements_in_React: { code: 2650, category: DiagnosticCategory.Error, key: "Cannot emit namespaced JSX elements in React" }, A_member_initializer_in_a_const_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_const_enums: { code: 2651, category: DiagnosticCategory.Error, key: "A member initializer in a 'const' enum declaration cannot reference members declared after it, including members defined in other 'const' enums." }, Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead: { code: 2652, category: DiagnosticCategory.Error, key: "Merged declaration '{0}' cannot include a default export declaration. Consider adding a separate 'export default {0}' declaration instead." }, + Cannot_extend_private_class_0: { code: 2653, category: DiagnosticCategory.Error, key: "Cannot extend private class '{0}'." }, + Constructor_of_type_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2654, category: DiagnosticCategory.Error, key: "Constructor of type '{0}' is protected and only accessible within class '{1}' and its subclasses." }, + Constructor_of_type_0_is_private_and_only_accessible_within_class_1: { code: 2655, category: DiagnosticCategory.Error, key: "Constructor of type '{0}' is private and only accessible within class '{1}'." }, + Cannot_assign_a_0_constructor_to_a_1_constructor: { code: 2656, category: DiagnosticCategory.Error, key: "Cannot assign a {0} constructor to a {1} constructor." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." }, Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." }, Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e138e2ddac489..8877da4d0c780 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1697,6 +1697,22 @@ "category": "Error", "code": 2652 }, + "Cannot extend private class '{0}'.": { + "category": "Error", + "code": 2653 + }, + "Constructor of type '{0}' is protected and only accessible within class '{1}' and its subclasses.": { + "category": "Error", + "code": 2654 + }, + "Constructor of type '{0}' is private and only accessible within class '{1}'.": { + "category": "Error", + "code": 2655 + }, + "Cannot assign a {0} constructor to a {1} constructor.": { + "category": "Error", + "code": 2656 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index da43984ee1377..4e965ee473085 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -360,9 +360,9 @@ namespace ts { export const enum NodeFlags { Export = 0x00000001, // Declarations Ambient = 0x00000002, // Declarations - Public = 0x00000010, // Property/Method - Private = 0x00000020, // Property/Method - Protected = 0x00000040, // Property/Method + Public = 0x00000010, // Property/Method/Constructor + Private = 0x00000020, // Property/Method/Constructor + Protected = 0x00000040, // Property/Method/Constructor Static = 0x00000080, // Property/Method Abstract = 0x00000100, // Class/Method/ConstructSignature Async = 0x00000200, // Property/Method/Function diff --git a/tests/baselines/reference/Protected3.errors.txt b/tests/baselines/reference/Protected3.errors.txt deleted file mode 100644 index 688422a1e0f6f..0000000000000 --- a/tests/baselines/reference/Protected3.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/conformance/parser/ecmascript5/Protected/Protected3.ts(2,3): error TS1089: 'protected' modifier cannot appear on a constructor declaration. - - -==== tests/cases/conformance/parser/ecmascript5/Protected/Protected3.ts (1 errors) ==== - class C { - protected constructor() { } - ~~~~~~~~~ -!!! error TS1089: 'protected' modifier cannot appear on a constructor declaration. - } \ No newline at end of file diff --git a/tests/baselines/reference/Protected3.symbols b/tests/baselines/reference/Protected3.symbols new file mode 100644 index 0000000000000..a9882189902f4 --- /dev/null +++ b/tests/baselines/reference/Protected3.symbols @@ -0,0 +1,6 @@ +=== tests/cases/conformance/parser/ecmascript5/Protected/Protected3.ts === +class C { +>C : Symbol(C, Decl(Protected3.ts, 0, 0)) + + protected constructor() { } +} diff --git a/tests/baselines/reference/Protected3.types b/tests/baselines/reference/Protected3.types new file mode 100644 index 0000000000000..d3f938a443191 --- /dev/null +++ b/tests/baselines/reference/Protected3.types @@ -0,0 +1,6 @@ +=== tests/cases/conformance/parser/ecmascript5/Protected/Protected3.ts === +class C { +>C : C + + protected constructor() { } +} diff --git a/tests/baselines/reference/classConstructorAccessibility.errors.txt b/tests/baselines/reference/classConstructorAccessibility.errors.txt index c22f3593bc57f..4520b90457bdd 100644 --- a/tests/baselines/reference/classConstructorAccessibility.errors.txt +++ b/tests/baselines/reference/classConstructorAccessibility.errors.txt @@ -1,29 +1,39 @@ -tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(6,5): error TS1089: 'private' modifier cannot appear on a constructor declaration. -tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(10,5): error TS1089: 'protected' modifier cannot appear on a constructor declaration. -tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(23,9): error TS1089: 'private' modifier cannot appear on a constructor declaration. -tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(27,9): error TS1089: 'protected' modifier cannot appear on a constructor declaration. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(20,9): error TS2655: Constructor of type '(x: number): D' is private and only accessible within class 'D'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(21,9): error TS2654: Constructor of type '(x: number): E' is protected and only accessible within class 'E' and its subclasses. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(38,13): error TS2655: Constructor of type '(x: number): D' is private and only accessible within class 'D'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(39,13): error TS2654: Constructor of type '(x: number): E' is protected and only accessible within class 'E' and its subclasses. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(46,1): error TS2322: Type 'typeof D' is not assignable to type 'new (x: number) => any'. + Cannot assign a private constructor to a public constructor. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts(47,1): error TS2322: Type 'typeof E' is not assignable to type 'new (x: number) => any'. + Cannot assign a protected constructor to a public constructor. -==== tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts (4 errors) ==== +==== tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts (6 errors) ==== + + class B { + constructor(public x: number) { } + } + class C { public constructor(public x: number) { } } class D { - private constructor(public x: number) { } // error - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. + private constructor(public x: number) { } } class E { - protected constructor(public x: number) { } // error - ~~~~~~~~~ -!!! error TS1089: 'protected' modifier cannot appear on a constructor declaration. + protected constructor(public x: number) { } } + var b = new B(1); var c = new C(1); - var d = new D(1); - var e = new E(1); + var d = new D(1); // error - D is private + ~~~~~~~~ +!!! error TS2655: Constructor of type '(x: number): D' is private and only accessible within class 'D'. + var e = new E(1); // error - E is protected + ~~~~~~~~ +!!! error TS2654: Constructor of type '(x: number): E' is protected and only accessible within class 'E' and its subclasses. module Generic { class C { @@ -31,19 +41,32 @@ tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessib } class D { - private constructor(public x: T) { } // error - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. + private constructor(public x: T) { } } class E { - protected constructor(public x: T) { } // error - ~~~~~~~~~ -!!! error TS1089: 'protected' modifier cannot appear on a constructor declaration. + protected constructor(public x: T) { } } + var b = new B(1); var c = new C(1); - var d = new D(1); - var e = new E(1); + var d = new D(1); // error - D is private + ~~~~~~~~ +!!! error TS2655: Constructor of type '(x: number): D' is private and only accessible within class 'D'. + var e = new E(1); // error - E is protected + ~~~~~~~~ +!!! error TS2654: Constructor of type '(x: number): E' is protected and only accessible within class 'E' and its subclasses. } - \ No newline at end of file + + // make sure signatures are covered. + let sig: new(x: number) => any; + sig = B; + sig = C; + sig = D; // error - private to public + ~~~ +!!! error TS2322: Type 'typeof D' is not assignable to type 'new (x: number) => any'. +!!! error TS2322: Cannot assign a private constructor to a public constructor. + sig = E; // error - protected to public + ~~~ +!!! error TS2322: Type 'typeof E' is not assignable to type 'new (x: number) => any'. +!!! error TS2322: Cannot assign a protected constructor to a public constructor. \ No newline at end of file diff --git a/tests/baselines/reference/classConstructorAccessibility.js b/tests/baselines/reference/classConstructorAccessibility.js index 15b12190392a4..f1f2509b905ba 100644 --- a/tests/baselines/reference/classConstructorAccessibility.js +++ b/tests/baselines/reference/classConstructorAccessibility.js @@ -1,19 +1,25 @@ //// [classConstructorAccessibility.ts] + +class B { + constructor(public x: number) { } +} + class C { public constructor(public x: number) { } } class D { - private constructor(public x: number) { } // error + private constructor(public x: number) { } } class E { - protected constructor(public x: number) { } // error + protected constructor(public x: number) { } } +var b = new B(1); var c = new C(1); -var d = new D(1); -var e = new E(1); +var d = new D(1); // error - D is private +var e = new E(1); // error - E is protected module Generic { class C { @@ -21,20 +27,33 @@ module Generic { } class D { - private constructor(public x: T) { } // error + private constructor(public x: T) { } } class E { - protected constructor(public x: T) { } // error + protected constructor(public x: T) { } } + var b = new B(1); var c = new C(1); - var d = new D(1); - var e = new E(1); + var d = new D(1); // error - D is private + var e = new E(1); // error - E is protected } - + +// make sure signatures are covered. +let sig: new(x: number) => any; +sig = B; +sig = C; +sig = D; // error - private to public +sig = E; // error - protected to public //// [classConstructorAccessibility.js] +var B = (function () { + function B(x) { + this.x = x; + } + return B; +})(); var C = (function () { function C(x) { this.x = x; @@ -44,18 +63,19 @@ var C = (function () { var D = (function () { function D(x) { this.x = x; - } // error + } return D; })(); var E = (function () { function E(x) { this.x = x; - } // error + } return E; })(); +var b = new B(1); var c = new C(1); -var d = new D(1); -var e = new E(1); +var d = new D(1); // error - D is private +var e = new E(1); // error - E is protected var Generic; (function (Generic) { var C = (function () { @@ -67,16 +87,49 @@ var Generic; var D = (function () { function D(x) { this.x = x; - } // error + } return D; })(); var E = (function () { function E(x) { this.x = x; - } // error + } return E; })(); + var b = new B(1); var c = new C(1); - var d = new D(1); - var e = new E(1); + var d = new D(1); // error - D is private + var e = new E(1); // error - E is protected })(Generic || (Generic = {})); +// make sure signatures are covered. +var sig; +sig = B; +sig = C; +sig = D; // error - private to public +sig = E; // error - protected to public + + +//// [classConstructorAccessibility.d.ts] +declare class B { + x: number; + constructor(x: number); +} +declare class C { + x: number; + constructor(x: number); +} +declare class D { + x: number; + constructor(x); +} +declare class E { + x: number; + constructor(x: number); +} +declare var b: B; +declare var c: C; +declare var d: D; +declare var e: E; +declare module Generic { +} +declare let sig: new (x: number) => any; diff --git a/tests/baselines/reference/classConstructorAccessibility2.errors.txt b/tests/baselines/reference/classConstructorAccessibility2.errors.txt new file mode 100644 index 0000000000000..c54a27cc05e64 --- /dev/null +++ b/tests/baselines/reference/classConstructorAccessibility2.errors.txt @@ -0,0 +1,86 @@ +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts(17,21): error TS2653: Cannot extend private class 'A'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts(19,12): error TS2655: Constructor of type '(a: string): A' is private and only accessible within class 'A'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts(48,10): error TS2655: Constructor of type '(a: string): A' is private and only accessible within class 'A'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts(49,10): error TS2654: Constructor of type '(): B' is protected and only accessible within class 'B' and its subclasses. + + +==== tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts (4 errors) ==== + + class A { + private constructor(a: string) // only private access + private constructor() { + + } + + static method() { + var t1 = new A("test"); // private is accessible in static method + } + + method() { + var t1 = new A("1"); // private is accessible in own class + } + } + + class A_ext extends A { // Cannot extend private class A + ~ +!!! error TS2653: Cannot extend private class 'A'. + method() { + var t1 = new A(""); // error - A is private and only accessible in it's own class + ~~~~~~~~~ +!!! error TS2655: Constructor of type '(a: string): A' is private and only accessible within class 'A'. + } + } + + class B { + protected constructor() { + } + + method() { + var t1 = new B(); // protected is accessible in own class + } + } + + class B_ext extends B { + method() { + var t1 = new B(); // protected is accessible in sub-class + } + } + + class C { + public constructor(){ + + } + methodA() { + var t1 = new C(); // public is accessible anywhere + } + } + + // check global scope + var t1 = new A(""); // error - A is private + ~~~~~~~~~ +!!! error TS2655: Constructor of type '(a: string): A' is private and only accessible within class 'A'. + var t2 = new B(); // error - B is protected + ~~~~~~~ +!!! error TS2654: Constructor of type '(): B' is protected and only accessible within class 'B' and its subclasses. + var t3 = new C(); + + // check Derived super call of a protected Base + class Base { + protected constructor() { + } + } + + class Derived extends Base { + protected constructor() { + super(); + } + } + + class SuperDerived extends Derived { + private constructor(){ + super(); + } + } + + var baseCtor = Base; + baseCtor = Derived; \ No newline at end of file diff --git a/tests/baselines/reference/classConstructorAccessibility2.js b/tests/baselines/reference/classConstructorAccessibility2.js new file mode 100644 index 0000000000000..cb6be6ced24f2 --- /dev/null +++ b/tests/baselines/reference/classConstructorAccessibility2.js @@ -0,0 +1,187 @@ +//// [classConstructorAccessibility2.ts] + +class A { + private constructor(a: string) // only private access + private constructor() { + + } + + static method() { + var t1 = new A("test"); // private is accessible in static method + } + + method() { + var t1 = new A("1"); // private is accessible in own class + } +} + +class A_ext extends A { // Cannot extend private class A + method() { + var t1 = new A(""); // error - A is private and only accessible in it's own class + } +} + +class B { + protected constructor() { + } + + method() { + var t1 = new B(); // protected is accessible in own class + } +} + +class B_ext extends B { + method() { + var t1 = new B(); // protected is accessible in sub-class + } +} + +class C { + public constructor(){ + + } + methodA() { + var t1 = new C(); // public is accessible anywhere + } +} + +// check global scope +var t1 = new A(""); // error - A is private +var t2 = new B(); // error - B is protected +var t3 = new C(); + +// check Derived super call of a protected Base +class Base { + protected constructor() { + } +} + +class Derived extends Base { + protected constructor() { + super(); + } +} + +class SuperDerived extends Derived { + private constructor(){ + super(); + } +} + +var baseCtor = Base; +baseCtor = Derived; + +//// [classConstructorAccessibility2.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + A.method = function () { + var t1 = new A("test"); // private is accessible in static method + }; + A.prototype.method = function () { + var t1 = new A("1"); // private is accessible in own class + }; + return A; +})(); +var A_ext = (function (_super) { + __extends(A_ext, _super); + function A_ext() { + _super.apply(this, arguments); + } + A_ext.prototype.method = function () { + var t1 = new A(""); // error - A is private and only accessible in it's own class + }; + return A_ext; +})(A); +var B = (function () { + function B() { + } + B.prototype.method = function () { + var t1 = new B(); // protected is accessible in own class + }; + return B; +})(); +var B_ext = (function (_super) { + __extends(B_ext, _super); + function B_ext() { + _super.apply(this, arguments); + } + B_ext.prototype.method = function () { + var t1 = new B(); // protected is accessible in sub-class + }; + return B_ext; +})(B); +var C = (function () { + function C() { + } + C.prototype.methodA = function () { + var t1 = new C(); // public is accessible anywhere + }; + return C; +})(); +// check global scope +var t1 = new A(""); // error - A is private +var t2 = new B(); // error - B is protected +var t3 = new C(); +// check Derived super call of a protected Base +var Base = (function () { + function Base() { + } + return Base; +})(); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + _super.call(this); + } + return Derived; +})(Base); +var SuperDerived = (function (_super) { + __extends(SuperDerived, _super); + function SuperDerived() { + _super.call(this); + } + return SuperDerived; +})(Derived); +var baseCtor = Base; +baseCtor = Derived; + + +//// [classConstructorAccessibility2.d.ts] +declare class A { + constructor(a); + static method(): void; + method(): void; +} +declare class A_ext extends A { + method(): void; +} +declare class B { + constructor(); + method(): void; +} +declare class B_ext extends B { + method(): void; +} +declare class C { + constructor(); + methodA(): void; +} +declare var t1: A; +declare var t2: B; +declare var t3: C; +declare class Base { + constructor(); +} +declare class Derived extends Base { + constructor(); +} +declare class SuperDerived extends Derived { + constructor(); +} +declare var baseCtor: typeof Base; diff --git a/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt b/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt new file mode 100644 index 0000000000000..7cde7beaa5f53 --- /dev/null +++ b/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt @@ -0,0 +1,51 @@ +tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts(3,2): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts(4,2): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts(4,2): error TS2394: Overload signature is not compatible with function implementation. +tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts(12,2): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts(12,2): error TS2394: Overload signature is not compatible with function implementation. + + +==== tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts (5 errors) ==== + + class A { + public constructor(a: boolean) // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + protected constructor(a: number) // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2394: Overload signature is not compatible with function implementation. + private constructor(a: string) + private constructor() { + + } + } + + class B { + protected constructor(a: number) // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2394: Overload signature is not compatible with function implementation. + constructor(a: string) + constructor() { + + } + } + + class C { + protected constructor(a: number) + protected constructor(a: string) + protected constructor() { + + } + } + + class D { + constructor(a: number) // ok + constructor(a: string) // ok + public constructor() { + + } + } \ No newline at end of file diff --git a/tests/baselines/reference/classConstructorOverloadsAccessibility.js b/tests/baselines/reference/classConstructorOverloadsAccessibility.js new file mode 100644 index 0000000000000..c0b252cd77dbb --- /dev/null +++ b/tests/baselines/reference/classConstructorOverloadsAccessibility.js @@ -0,0 +1,76 @@ +//// [classConstructorOverloadsAccessibility.ts] + +class A { + public constructor(a: boolean) // error + protected constructor(a: number) // error + private constructor(a: string) + private constructor() { + + } +} + +class B { + protected constructor(a: number) // error + constructor(a: string) + constructor() { + + } +} + +class C { + protected constructor(a: number) + protected constructor(a: string) + protected constructor() { + + } +} + +class D { + constructor(a: number) // ok + constructor(a: string) // ok + public constructor() { + + } +} + +//// [classConstructorOverloadsAccessibility.js] +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function () { + function C() { + } + return C; +})(); +var D = (function () { + function D() { + } + return D; +})(); + + +//// [classConstructorOverloadsAccessibility.d.ts] +declare class A { + constructor(a: boolean); + constructor(a: number); + constructor(a); +} +declare class B { + constructor(a: number); + constructor(a: string); +} +declare class C { + constructor(a: number); + constructor(a: string); +} +declare class D { + constructor(a: number); + constructor(a: string); +} diff --git a/tests/baselines/reference/implicitAnyInAmbientDeclaration.errors.txt b/tests/baselines/reference/implicitAnyInAmbientDeclaration.errors.txt index 4775ec0511bec..88acd5668b725 100644 --- a/tests/baselines/reference/implicitAnyInAmbientDeclaration.errors.txt +++ b/tests/baselines/reference/implicitAnyInAmbientDeclaration.errors.txt @@ -1,10 +1,9 @@ tests/cases/compiler/implicitAnyInAmbientDeclaration.ts(3,9): error TS7008: Member 'publicMember' implicitly has an 'any' type. tests/cases/compiler/implicitAnyInAmbientDeclaration.ts(6,9): error TS7010: 'publicFunction', which lacks return-type annotation, implicitly has an 'any' return type. tests/cases/compiler/implicitAnyInAmbientDeclaration.ts(6,31): error TS7006: Parameter 'x' implicitly has an 'any' type. -tests/cases/compiler/implicitAnyInAmbientDeclaration.ts(8,9): error TS1089: 'private' modifier cannot appear on a constructor declaration. -==== tests/cases/compiler/implicitAnyInAmbientDeclaration.ts (4 errors) ==== +==== tests/cases/compiler/implicitAnyInAmbientDeclaration.ts (3 errors) ==== module Test { declare class C { public publicMember; // this should be an error @@ -19,7 +18,5 @@ tests/cases/compiler/implicitAnyInAmbientDeclaration.ts(8,9): error TS1089: 'pri !!! error TS7006: Parameter 'x' implicitly has an 'any' type. private privateFunction(privateParam); // this should not be an error private constructor(privateParam); - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. } } \ No newline at end of file diff --git a/tests/baselines/reference/implicitAnyInAmbientDeclaration2.d.errors.txt b/tests/baselines/reference/implicitAnyInAmbientDeclaration2.d.errors.txt index 11f2ae90d3520..7deacb342e01b 100644 --- a/tests/baselines/reference/implicitAnyInAmbientDeclaration2.d.errors.txt +++ b/tests/baselines/reference/implicitAnyInAmbientDeclaration2.d.errors.txt @@ -4,11 +4,10 @@ tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(2,13): error TS7005: tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(4,5): error TS7008: Member 'publicMember' implicitly has an 'any' type. tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(7,5): error TS7010: 'publicFunction', which lacks return-type annotation, implicitly has an 'any' return type. tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(7,27): error TS7006: Parameter 'x' implicitly has an 'any' type. -tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(9,5): error TS1089: 'private' modifier cannot appear on a constructor declaration. tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(13,24): error TS7006: Parameter 'publicConsParam' implicitly has an 'any' type. -==== tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts (8 errors) ==== +==== tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts (7 errors) ==== declare function foo(x); // this should be an error ~~~ !!! error TS7010: 'foo', which lacks return-type annotation, implicitly has an 'any' return type. @@ -30,8 +29,6 @@ tests/cases/compiler/implicitAnyInAmbientDeclaration2.d.ts(13,24): error TS7006: !!! error TS7006: Parameter 'x' implicitly has an 'any' type. private privateFunction(privateParam); // this should not be an error private constructor(privateParam); // this should not be an error - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. } declare class D { diff --git a/tests/baselines/reference/parserConstructorDeclaration5.errors.txt b/tests/baselines/reference/parserConstructorDeclaration5.errors.txt deleted file mode 100644 index 4589ad95a32f7..0000000000000 --- a/tests/baselines/reference/parserConstructorDeclaration5.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration5.ts(2,3): error TS1089: 'private' modifier cannot appear on a constructor declaration. - - -==== tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration5.ts (1 errors) ==== - class C { - private constructor() { } - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. - } \ No newline at end of file diff --git a/tests/baselines/reference/parserConstructorDeclaration5.symbols b/tests/baselines/reference/parserConstructorDeclaration5.symbols new file mode 100644 index 0000000000000..6eb3d32a0f0c9 --- /dev/null +++ b/tests/baselines/reference/parserConstructorDeclaration5.symbols @@ -0,0 +1,6 @@ +=== tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration5.ts === +class C { +>C : Symbol(C, Decl(parserConstructorDeclaration5.ts, 0, 0)) + + private constructor() { } +} diff --git a/tests/baselines/reference/parserConstructorDeclaration5.types b/tests/baselines/reference/parserConstructorDeclaration5.types new file mode 100644 index 0000000000000..ae5d2c44b49f8 --- /dev/null +++ b/tests/baselines/reference/parserConstructorDeclaration5.types @@ -0,0 +1,6 @@ +=== tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration5.ts === +class C { +>C : C + + private constructor() { } +} diff --git a/tests/baselines/reference/protectedMembers.errors.txt b/tests/baselines/reference/protectedMembers.errors.txt index c35bc25fe7196..82bf9b71f0147 100644 --- a/tests/baselines/reference/protectedMembers.errors.txt +++ b/tests/baselines/reference/protectedMembers.errors.txt @@ -8,7 +8,6 @@ tests/cases/compiler/protectedMembers.ts(48,1): error TS2445: Property 'sx' is p tests/cases/compiler/protectedMembers.ts(49,1): error TS2445: Property 'sf' is protected and only accessible within class 'C2' and its subclasses. tests/cases/compiler/protectedMembers.ts(68,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'C'. tests/cases/compiler/protectedMembers.ts(69,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'C'. -tests/cases/compiler/protectedMembers.ts(86,5): error TS1089: 'protected' modifier cannot appear on a constructor declaration. tests/cases/compiler/protectedMembers.ts(98,1): error TS2322: Type 'B1' is not assignable to type 'A1'. Property 'x' is protected but type 'B1' is not a class derived from 'A1'. tests/cases/compiler/protectedMembers.ts(99,1): error TS2322: Type 'A1' is not assignable to type 'B1'. @@ -17,7 +16,7 @@ tests/cases/compiler/protectedMembers.ts(112,7): error TS2415: Class 'B3' incorr Property 'x' is protected in type 'B3' but public in type 'A3'. -==== tests/cases/compiler/protectedMembers.ts (14 errors) ==== +==== tests/cases/compiler/protectedMembers.ts (13 errors) ==== // Class with protected members class C1 { protected x: number; @@ -124,8 +123,6 @@ tests/cases/compiler/protectedMembers.ts(112,7): error TS2415: Class 'B3' incorr class CC { // Error, constructor cannot be protected protected constructor() { - ~~~~~~~~~ -!!! error TS1089: 'protected' modifier cannot appear on a constructor declaration. } } diff --git a/tests/baselines/reference/typesWithPrivateConstructor.errors.txt b/tests/baselines/reference/typesWithPrivateConstructor.errors.txt index 2440e51cd3972..ddbae5a90f053 100644 --- a/tests/baselines/reference/typesWithPrivateConstructor.errors.txt +++ b/tests/baselines/reference/typesWithPrivateConstructor.errors.txt @@ -1,31 +1,25 @@ -tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(4,5): error TS1089: 'private' modifier cannot appear on a constructor declaration. +tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(7,9): error TS2655: Constructor of type '(): C' is private and only accessible within class 'C'. tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(8,5): error TS2322: Type 'Function' is not assignable to type '() => void'. -tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(11,5): error TS1089: 'private' modifier cannot appear on a constructor declaration. -tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(12,5): error TS1089: 'private' modifier cannot appear on a constructor declaration. tests/cases/conformance/types/members/typesWithPrivateConstructor.ts(15,10): error TS2346: Supplied parameters do not match any signature of call target. -==== tests/cases/conformance/types/members/typesWithPrivateConstructor.ts (5 errors) ==== +==== tests/cases/conformance/types/members/typesWithPrivateConstructor.ts (3 errors) ==== // private constructors are not allowed class C { private constructor() { } - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. } var c = new C(); + ~~~~~~~ +!!! error TS2655: Constructor of type '(): C' is private and only accessible within class 'C'. var r: () => void = c.constructor; ~ !!! error TS2322: Type 'Function' is not assignable to type '() => void'. class C2 { private constructor(x: number); - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. private constructor(x: any) { } - ~~~~~~~ -!!! error TS1089: 'private' modifier cannot appear on a constructor declaration. } var c2 = new C2(); diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts index c2e4855e63a3b..922c93eae7449 100644 --- a/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility.ts @@ -1,18 +1,25 @@ +// @declaration: true + +class B { + constructor(public x: number) { } +} + class C { public constructor(public x: number) { } } class D { - private constructor(public x: number) { } // error + private constructor(public x: number) { } } class E { - protected constructor(public x: number) { } // error + protected constructor(public x: number) { } } +var b = new B(1); var c = new C(1); -var d = new D(1); -var e = new E(1); +var d = new D(1); // error - D is private +var e = new E(1); // error - E is protected module Generic { class C { @@ -20,14 +27,22 @@ module Generic { } class D { - private constructor(public x: T) { } // error + private constructor(public x: T) { } } class E { - protected constructor(public x: T) { } // error + protected constructor(public x: T) { } } + var b = new B(1); var c = new C(1); - var d = new D(1); - var e = new E(1); + var d = new D(1); // error - D is private + var e = new E(1); // error - E is protected } + +// make sure signatures are covered. +let sig: new(x: number) => any; +sig = B; +sig = C; +sig = D; // error - private to public +sig = E; // error - protected to public \ No newline at end of file diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts new file mode 100644 index 0000000000000..737932d2f6e43 --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorAccessibility2.ts @@ -0,0 +1,72 @@ +// @declaration: true + +class A { + private constructor(a: string) // only private access + private constructor() { + + } + + static method() { + var t1 = new A("test"); // private is accessible in static method + } + + method() { + var t1 = new A("1"); // private is accessible in own class + } +} + +class A_ext extends A { // Cannot extend private class A + method() { + var t1 = new A(""); // error - A is private and only accessible in it's own class + } +} + +class B { + protected constructor() { + } + + method() { + var t1 = new B(); // protected is accessible in own class + } +} + +class B_ext extends B { + method() { + var t1 = new B(); // protected is accessible in sub-class + } +} + +class C { + public constructor(){ + + } + methodA() { + var t1 = new C(); // public is accessible anywhere + } +} + +// check global scope +var t1 = new A(""); // error - A is private +var t2 = new B(); // error - B is protected +var t3 = new C(); + +// check Derived super call of a protected Base +class Base { + protected constructor() { + } +} + +class Derived extends Base { + protected constructor() { + super(); + } +} + +class SuperDerived extends Derived { + private constructor(){ + super(); + } +} + +var baseCtor = Base; +baseCtor = Derived; \ No newline at end of file diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts new file mode 100644 index 0000000000000..48b3ac21128b2 --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorOverloadsAccessibility.ts @@ -0,0 +1,34 @@ +// @declaration: true + +class A { + public constructor(a: boolean) // error + protected constructor(a: number) // error + private constructor(a: string) + private constructor() { + + } +} + +class B { + protected constructor(a: number) // error + constructor(a: string) + constructor() { + + } +} + +class C { + protected constructor(a: number) + protected constructor(a: string) + protected constructor() { + + } +} + +class D { + constructor(a: number) // ok + constructor(a: string) // ok + public constructor() { + + } +} \ No newline at end of file