@@ -5889,16 +5889,20 @@ namespace ts {
58895889
58905890 const sourceSignatures = getSignaturesOfType(source, kind);
58915891 const targetSignatures = getSignaturesOfType(target, kind);
5892- if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length &&
5893- isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5894- // An abstract constructor type is not assignable to a non-abstract constructor type
5895- // as it would otherwise be possible to new an abstract class. Note that the assignablity
5896- // check we perform for an extends clause excludes construct signatures from the target,
5897- // so this check never proceeds.
5898- if (reportErrors) {
5899- reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5892+ if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) {
5893+ if (isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5894+ // An abstract constructor type is not assignable to a non-abstract constructor type
5895+ // as it would otherwise be possible to new an abstract class. Note that the assignablity
5896+ // check we perform for an extends clause excludes construct signatures from the target,
5897+ // so this check never proceeds.
5898+ if (reportErrors) {
5899+ reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5900+ }
5901+ return Ternary.False;
5902+ }
5903+ if (!constructorRelatedTo(sourceSignatures[0], targetSignatures[0], reportErrors)) {
5904+ return Ternary.False;
59005905 }
5901- return Ternary.False;
59025906 }
59035907
59045908 let result = Ternary.True;
@@ -6052,6 +6056,32 @@ namespace ts {
60526056 }
60536057 return Ternary.True;
60546058 }
6059+
6060+ function constructorRelatedTo(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) {
6061+ if (sourceSignature && targetSignature && sourceSignature.declaration && targetSignature.declaration) {
6062+ const sourceAccessibility = sourceSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
6063+ const targetAccessibility = targetSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
6064+
6065+ const isRelated = sourceAccessibility === targetAccessibility;
6066+ if (!isRelated && reportErrors) {
6067+ reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, flagsToString(sourceAccessibility), flagsToString(targetAccessibility));
6068+ }
6069+
6070+ return isRelated;
6071+ }
6072+
6073+ return true;
6074+
6075+ function flagsToString(flags: NodeFlags) {
6076+ if (flags === NodeFlags.Private) {
6077+ return "private";
6078+ }
6079+ if (flags === NodeFlags.Protected) {
6080+ return "protected";
6081+ }
6082+ return "public";
6083+ }
6084+ }
60556085 }
60566086
60576087 // Return true if the given type is the constructor type for an abstract class
@@ -10103,6 +10133,9 @@ namespace ts {
1010310133 // that the user will not add any.
1010410134 const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct);
1010510135 if (constructSignatures.length) {
10136+ if (!isConstructorAccessible(node, constructSignatures[0])) {
10137+ return resolveErrorCall(node);
10138+ }
1010610139 return resolveCall(node, constructSignatures, candidatesOutArray);
1010710140 }
1010810141
@@ -10123,6 +10156,37 @@ namespace ts {
1012310156 return resolveErrorCall(node);
1012410157 }
1012510158
10159+ function isConstructorAccessible(node: NewExpression, signature: Signature) {
10160+ if (!signature || !signature.declaration) {
10161+ return true;
10162+ }
10163+
10164+ const declaration = signature.declaration;
10165+ const flags = declaration.flags;
10166+
10167+ // Public constructor is accessible.
10168+ if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
10169+ return true;
10170+ }
10171+
10172+ const declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(declaration.parent.symbol);
10173+ const enclosingClassDeclaration = getContainingClass(node);
10174+ const enclosingClass = enclosingClassDeclaration ? <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined;
10175+
10176+ // A private or protected constructor can only be instantiated within it's own class
10177+ if (declaringClass !== enclosingClass) {
10178+ if (flags & NodeFlags.Private) {
10179+ error(node, Diagnostics.Constructor_of_type_0_is_private_and_only_accessible_within_class_1, signatureToString(signature), typeToString(declaringClass));
10180+ }
10181+ if (flags & NodeFlags.Protected) {
10182+ error(node, Diagnostics.Constructor_of_type_0_is_protected_and_only_accessible_within_class_1, signatureToString(signature), typeToString(declaringClass));
10183+ }
10184+ return false;
10185+ }
10186+
10187+ return true;
10188+ }
10189+
1012610190 function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[]): Signature {
1012710191 const tagType = checkExpression(node.tag);
1012810192 const apparentType = getApparentType(tagType);
@@ -12059,7 +12123,7 @@ namespace ts {
1205912123 error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient);
1206012124 }
1206112125 else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) {
12062- error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
12126+ error(o.name || o , Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
1206312127 }
1206412128 else if (deviation & NodeFlags.Abstract) {
1206512129 error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_not_abstract);
@@ -13928,6 +13992,7 @@ namespace ts {
1392813992 if (baseTypes.length && produceDiagnostics) {
1392913993 const baseType = baseTypes[0];
1393013994 const staticBaseType = getBaseConstructorTypeOfClass(type);
13995+ checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
1393113996 checkSourceElement(baseTypeNode.expression);
1393213997 if (baseTypeNode.typeArguments) {
1393313998 forEach(baseTypeNode.typeArguments, checkSourceElement);
@@ -13983,6 +14048,16 @@ namespace ts {
1398314048 }
1398414049 }
1398514050
14051+ function checkBaseTypeAccessibility(type: ObjectType, node: ExpressionWithTypeArguments) {
14052+ const signatures = getSignaturesOfType(type, SignatureKind.Construct);
14053+ if (signatures.length) {
14054+ const declaration = signatures[0].declaration;
14055+ if (declaration && declaration.flags & NodeFlags.Private) {
14056+ error(node, Diagnostics.Cannot_extend_private_class_0, (<Identifier>node.expression).text);
14057+ }
14058+ }
14059+ }
14060+
1398614061 function getTargetSymbol(s: Symbol) {
1398714062 // if symbol is instantiated its flags are not copied from the 'target'
1398814063 // so we'll need to get back original 'target' symbol to work with correct set of flags
@@ -16348,12 +16423,6 @@ namespace ts {
1634816423 if (flags & NodeFlags.Abstract) {
1634916424 return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract");
1635016425 }
16351- else if (flags & NodeFlags.Protected) {
16352- return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected");
16353- }
16354- else if (flags & NodeFlags.Private) {
16355- return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private");
16356- }
1635716426 else if (flags & NodeFlags.Async) {
1635816427 return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async");
1635916428 }
0 commit comments