@@ -1720,6 +1720,16 @@ namespace ts {
1720
1720
return result;
1721
1721
}
1722
1722
1723
+ function visibilityToString(flags: NodeFlags) {
1724
+ if (flags === NodeFlags.Private) {
1725
+ return "private";
1726
+ }
1727
+ if (flags === NodeFlags.Protected) {
1728
+ return "protected";
1729
+ }
1730
+ return "public";
1731
+ }
1732
+
1723
1733
function getTypeAliasForTypeLiteral(type: Type): Symbol {
1724
1734
if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
1725
1735
let node = type.symbol.declarations[0].parent;
@@ -5907,16 +5917,20 @@ namespace ts {
5907
5917
5908
5918
const sourceSignatures = getSignaturesOfType(source, kind);
5909
5919
const targetSignatures = getSignaturesOfType(target, kind);
5910
- if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length &&
5911
- isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5912
- // An abstract constructor type is not assignable to a non-abstract constructor type
5920
+ if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) {
5921
+ if ( isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5922
+ // An abstract constructor type is not assignable to a non-abstract constructor type
5913
5923
// as it would otherwise be possible to new an abstract class. Note that the assignability
5914
- // check we perform for an extends clause excludes construct signatures from the target,
5915
- // so this check never proceeds.
5916
- if (reportErrors) {
5917
- reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5924
+ // check we perform for an extends clause excludes construct signatures from the target,
5925
+ // so this check never proceeds.
5926
+ if (reportErrors) {
5927
+ reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5928
+ }
5929
+ return Ternary.False;
5930
+ }
5931
+ if (!constructorVisibilitiesAreCompatible(sourceSignatures[0], targetSignatures[0], reportErrors)) {
5932
+ return Ternary.False;
5918
5933
}
5919
- return Ternary.False;
5920
5934
}
5921
5935
5922
5936
let result = Ternary.True;
@@ -6059,6 +6073,36 @@ namespace ts {
6059
6073
}
6060
6074
return Ternary.True;
6061
6075
}
6076
+
6077
+ function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) {
6078
+ if (!sourceSignature.declaration || !targetSignature.declaration) {
6079
+ return true;
6080
+ }
6081
+
6082
+ const sourceAccessibility = sourceSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
6083
+ const targetAccessibility = targetSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
6084
+
6085
+ // A public, protected and private signature is assignable to a private signature.
6086
+ if (targetAccessibility === NodeFlags.Private) {
6087
+ return true;
6088
+ }
6089
+
6090
+ // A public and protected signature is assignable to a protected signature.
6091
+ if (targetAccessibility === NodeFlags.Protected && sourceAccessibility !== NodeFlags.Private) {
6092
+ return true;
6093
+ }
6094
+
6095
+ // Only a public signature is assignable to public signature.
6096
+ if (targetAccessibility !== NodeFlags.Protected && !sourceAccessibility) {
6097
+ return true;
6098
+ }
6099
+
6100
+ if (reportErrors) {
6101
+ reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, visibilityToString(sourceAccessibility), visibilityToString(targetAccessibility));
6102
+ }
6103
+
6104
+ return false;
6105
+ }
6062
6106
}
6063
6107
6064
6108
// Return true if the given type is the constructor type for an abstract class
@@ -10166,6 +10210,9 @@ namespace ts {
10166
10210
// that the user will not add any.
10167
10211
const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct);
10168
10212
if (constructSignatures.length) {
10213
+ if (!isConstructorAccessible(node, constructSignatures[0])) {
10214
+ return resolveErrorCall(node);
10215
+ }
10169
10216
return resolveCall(node, constructSignatures, candidatesOutArray);
10170
10217
}
10171
10218
@@ -10186,6 +10233,36 @@ namespace ts {
10186
10233
return resolveErrorCall(node);
10187
10234
}
10188
10235
10236
+ function isConstructorAccessible(node: NewExpression, signature: Signature) {
10237
+ if (!signature || !signature.declaration) {
10238
+ return true;
10239
+ }
10240
+
10241
+ const declaration = signature.declaration;
10242
+ const flags = declaration.flags;
10243
+
10244
+ // Public constructor is accessible.
10245
+ if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
10246
+ return true;
10247
+ }
10248
+
10249
+ const declaringClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(declaration.parent.symbol);
10250
+ const declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(declaration.parent.symbol);
10251
+
10252
+ // A private or protected constructor can only be instantiated within it's own class
10253
+ if (!isNodeWithinClass(node, declaringClassDeclaration)) {
10254
+ if (flags & NodeFlags.Private) {
10255
+ error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass));
10256
+ }
10257
+ if (flags & NodeFlags.Protected) {
10258
+ error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass));
10259
+ }
10260
+ return false;
10261
+ }
10262
+
10263
+ return true;
10264
+ }
10265
+
10189
10266
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[]): Signature {
10190
10267
const tagType = checkExpression(node.tag);
10191
10268
const apparentType = getApparentType(tagType);
@@ -12123,7 +12200,7 @@ namespace ts {
12123
12200
error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient);
12124
12201
}
12125
12202
else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) {
12126
- error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
12203
+ error(o.name || o , Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
12127
12204
}
12128
12205
else if (deviation & NodeFlags.Abstract) {
12129
12206
error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_not_abstract);
@@ -13992,6 +14069,7 @@ namespace ts {
13992
14069
if (baseTypes.length && produceDiagnostics) {
13993
14070
const baseType = baseTypes[0];
13994
14071
const staticBaseType = getBaseConstructorTypeOfClass(type);
14072
+ checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
13995
14073
checkSourceElement(baseTypeNode.expression);
13996
14074
if (baseTypeNode.typeArguments) {
13997
14075
forEach(baseTypeNode.typeArguments, checkSourceElement);
@@ -14047,6 +14125,19 @@ namespace ts {
14047
14125
}
14048
14126
}
14049
14127
14128
+ function checkBaseTypeAccessibility(type: ObjectType, node: ExpressionWithTypeArguments) {
14129
+ const signatures = getSignaturesOfType(type, SignatureKind.Construct);
14130
+ if (signatures.length) {
14131
+ const declaration = signatures[0].declaration;
14132
+ if (declaration && declaration.flags & NodeFlags.Private) {
14133
+ const typeClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(type.symbol);
14134
+ if (!isNodeWithinClass(node, typeClassDeclaration)) {
14135
+ error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, (<Identifier>node.expression).text);
14136
+ }
14137
+ }
14138
+ }
14139
+ }
14140
+
14050
14141
function getTargetSymbol(s: Symbol) {
14051
14142
// if symbol is instantiated its flags are not copied from the 'target'
14052
14143
// so we'll need to get back original 'target' symbol to work with correct set of flags
@@ -15370,6 +15461,18 @@ namespace ts {
15370
15461
return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments;
15371
15462
}
15372
15463
15464
+ function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) {
15465
+ while (true) {
15466
+ node = getContainingClass(node);
15467
+ if (!node) {
15468
+ return false;
15469
+ }
15470
+ if (node === classDeclaration) {
15471
+ return true;
15472
+ }
15473
+ }
15474
+ }
15475
+
15373
15476
function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment {
15374
15477
while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) {
15375
15478
nodeOnRightSide = <QualifiedName>nodeOnRightSide.parent;
@@ -16253,16 +16356,12 @@ namespace ts {
16253
16356
case SyntaxKind.PublicKeyword:
16254
16357
case SyntaxKind.ProtectedKeyword:
16255
16358
case SyntaxKind.PrivateKeyword:
16256
- let text: string;
16257
- if (modifier.kind === SyntaxKind.PublicKeyword) {
16258
- text = "public";
16259
- }
16260
- else if (modifier.kind === SyntaxKind.ProtectedKeyword) {
16261
- text = "protected";
16359
+ let text = visibilityToString(modifierToFlag(modifier.kind));
16360
+
16361
+ if (modifier.kind === SyntaxKind.ProtectedKeyword) {
16262
16362
lastProtected = modifier;
16263
16363
}
16264
- else {
16265
- text = "private";
16364
+ else if (modifier.kind === SyntaxKind.PrivateKeyword) {
16266
16365
lastPrivate = modifier;
16267
16366
}
16268
16367
@@ -16413,12 +16512,6 @@ namespace ts {
16413
16512
if (flags & NodeFlags.Abstract) {
16414
16513
return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract");
16415
16514
}
16416
- else if (flags & NodeFlags.Protected) {
16417
- return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected");
16418
- }
16419
- else if (flags & NodeFlags.Private) {
16420
- return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private");
16421
- }
16422
16515
else if (flags & NodeFlags.Async) {
16423
16516
return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async");
16424
16517
}
0 commit comments