@@ -5528,32 +5528,24 @@ namespace ts {
5528
5528
if (target === anyFunctionType || source === anyFunctionType) {
5529
5529
return Ternary.True;
5530
5530
}
5531
+
5531
5532
const sourceSignatures = getSignaturesOfType(source, kind);
5532
5533
const targetSignatures = getSignaturesOfType(target, kind);
5533
- let result = Ternary.True;
5534
- const saveErrorInfo = errorInfo;
5535
-
5536
-
5537
-
5538
- if (kind === SignatureKind.Construct) {
5539
- // Only want to compare the construct signatures for abstractness guarantees.
5540
-
5541
- // Because the "abstractness" of a class is the same across all construct signatures
5542
- // (internally we are checking the corresponding declaration), it is enough to perform
5543
- // the check and report an error once over all pairs of source and target construct signatures.
5544
- //
5545
- // sourceSig and targetSig are (possibly) undefined.
5546
- //
5547
- // Note that in an extends-clause, targetSignatures is stripped, so the check never proceeds.
5548
- const sourceSig = sourceSignatures[0];
5549
- const targetSig = targetSignatures[0];
5550
-
5551
- result &= abstractSignatureRelatedTo(source, sourceSig, target, targetSig);
5552
- if (result !== Ternary.True) {
5553
- return result;
5534
+ if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length &&
5535
+ isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5536
+ // An abstract constructor type is not assignable to a non-abstract constructor type
5537
+ // as it would otherwise be possible to new an abstract class. Note that the assignablity
5538
+ // check we perform for an extends clause excludes construct signatures from the target,
5539
+ // so this check never proceeds.
5540
+ if (reportErrors) {
5541
+ reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5554
5542
}
5543
+ return Ternary.False;
5555
5544
}
5556
5545
5546
+ let result = Ternary.True;
5547
+ const saveErrorInfo = errorInfo;
5548
+
5557
5549
outer: for (const t of targetSignatures) {
5558
5550
if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
5559
5551
// Only elaborate errors from the first failure
@@ -5580,40 +5572,6 @@ namespace ts {
5580
5572
}
5581
5573
}
5582
5574
return result;
5583
-
5584
- function abstractSignatureRelatedTo(source: Type, sourceSig: Signature, target: Type, targetSig: Signature) {
5585
- if (sourceSig && targetSig) {
5586
-
5587
- const sourceDecl = source.symbol && getClassLikeDeclarationOfSymbol(source.symbol);
5588
- const targetDecl = target.symbol && getClassLikeDeclarationOfSymbol(target.symbol);
5589
-
5590
- if (!sourceDecl) {
5591
- // If the source object isn't itself a class declaration, it can be freely assigned, regardless
5592
- // of whether the constructed object is abstract or not.
5593
- return Ternary.True;
5594
- }
5595
-
5596
- const sourceErasedSignature = getErasedSignature(sourceSig);
5597
- const targetErasedSignature = getErasedSignature(targetSig);
5598
-
5599
- const sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature);
5600
- const targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature);
5601
-
5602
- const sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getClassLikeDeclarationOfSymbol(sourceReturnType.symbol);
5603
- const targetReturnDecl = targetReturnType && targetReturnType.symbol && getClassLikeDeclarationOfSymbol(targetReturnType.symbol);
5604
- const sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract;
5605
- const targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract;
5606
-
5607
- if (sourceIsAbstract && !(targetIsAbstract && targetDecl)) {
5608
- // if target isn't a class-declaration type, then it can be new'd, so we forbid the assignment.
5609
- if (reportErrors) {
5610
- reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5611
- }
5612
- return Ternary.False;
5613
- }
5614
- }
5615
- return Ternary.True;
5616
- }
5617
5575
}
5618
5576
5619
5577
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
@@ -5782,6 +5740,20 @@ namespace ts {
5782
5740
}
5783
5741
}
5784
5742
5743
+ // Return true if the given type is the constructor type for an abstract class
5744
+ function isAbstractConstructorType(type: Type) {
5745
+ if (type.flags & TypeFlags.Anonymous) {
5746
+ const symbol = type.symbol;
5747
+ if (symbol && symbol.flags & SymbolFlags.Class) {
5748
+ const declaration = getClassLikeDeclarationOfSymbol(symbol);
5749
+ if (declaration && declaration.flags & NodeFlags.Abstract) {
5750
+ return true;
5751
+ }
5752
+ }
5753
+ }
5754
+ return false;
5755
+ }
5756
+
5785
5757
// Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
5786
5758
// when structural type comparisons have been started for 10 or more instantiations of the same generic type. It is possible,
5787
5759
// though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely expanding.
0 commit comments