@@ -5549,32 +5549,24 @@ namespace ts {
5549
5549
if (target === anyFunctionType || source === anyFunctionType) {
5550
5550
return Ternary.True;
5551
5551
}
5552
+
5552
5553
const sourceSignatures = getSignaturesOfType(source, kind);
5553
5554
const targetSignatures = getSignaturesOfType(target, kind);
5554
- let result = Ternary.True;
5555
- const saveErrorInfo = errorInfo;
5556
-
5557
-
5558
-
5559
- if (kind === SignatureKind.Construct) {
5560
- // Only want to compare the construct signatures for abstractness guarantees.
5561
-
5562
- // Because the "abstractness" of a class is the same across all construct signatures
5563
- // (internally we are checking the corresponding declaration), it is enough to perform
5564
- // the check and report an error once over all pairs of source and target construct signatures.
5565
- //
5566
- // sourceSig and targetSig are (possibly) undefined.
5567
- //
5568
- // Note that in an extends-clause, targetSignatures is stripped, so the check never proceeds.
5569
- const sourceSig = sourceSignatures[0];
5570
- const targetSig = targetSignatures[0];
5571
-
5572
- result &= abstractSignatureRelatedTo(source, sourceSig, target, targetSig);
5573
- if (result !== Ternary.True) {
5574
- return result;
5555
+ if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length &&
5556
+ isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
5557
+ // An abstract constructor type is not assignable to a non-abstract constructor type
5558
+ // as it would otherwise be possible to new an abstract class. Note that the assignablity
5559
+ // check we perform for an extends clause excludes construct signatures from the target,
5560
+ // so this check never proceeds.
5561
+ if (reportErrors) {
5562
+ reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5575
5563
}
5564
+ return Ternary.False;
5576
5565
}
5577
5566
5567
+ let result = Ternary.True;
5568
+ const saveErrorInfo = errorInfo;
5569
+
5578
5570
outer: for (const t of targetSignatures) {
5579
5571
if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
5580
5572
// Only elaborate errors from the first failure
@@ -5601,40 +5593,6 @@ namespace ts {
5601
5593
}
5602
5594
}
5603
5595
return result;
5604
-
5605
- function abstractSignatureRelatedTo(source: Type, sourceSig: Signature, target: Type, targetSig: Signature) {
5606
- if (sourceSig && targetSig) {
5607
-
5608
- const sourceDecl = source.symbol && getClassLikeDeclarationOfSymbol(source.symbol);
5609
- const targetDecl = target.symbol && getClassLikeDeclarationOfSymbol(target.symbol);
5610
-
5611
- if (!sourceDecl) {
5612
- // If the source object isn't itself a class declaration, it can be freely assigned, regardless
5613
- // of whether the constructed object is abstract or not.
5614
- return Ternary.True;
5615
- }
5616
-
5617
- const sourceErasedSignature = getErasedSignature(sourceSig);
5618
- const targetErasedSignature = getErasedSignature(targetSig);
5619
-
5620
- const sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature);
5621
- const targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature);
5622
-
5623
- const sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getClassLikeDeclarationOfSymbol(sourceReturnType.symbol);
5624
- const targetReturnDecl = targetReturnType && targetReturnType.symbol && getClassLikeDeclarationOfSymbol(targetReturnType.symbol);
5625
- const sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract;
5626
- const targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract;
5627
-
5628
- if (sourceIsAbstract && !(targetIsAbstract && targetDecl)) {
5629
- // if target isn't a class-declaration type, then it can be new'd, so we forbid the assignment.
5630
- if (reportErrors) {
5631
- reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
5632
- }
5633
- return Ternary.False;
5634
- }
5635
- }
5636
- return Ternary.True;
5637
- }
5638
5596
}
5639
5597
5640
5598
/**
@@ -5830,6 +5788,20 @@ namespace ts {
5830
5788
}
5831
5789
}
5832
5790
5791
+ // Return true if the given type is the constructor type for an abstract class
5792
+ function isAbstractConstructorType(type: Type) {
5793
+ if (type.flags & TypeFlags.Anonymous) {
5794
+ const symbol = type.symbol;
5795
+ if (symbol && symbol.flags & SymbolFlags.Class) {
5796
+ const declaration = getClassLikeDeclarationOfSymbol(symbol);
5797
+ if (declaration && declaration.flags & NodeFlags.Abstract) {
5798
+ return true;
5799
+ }
5800
+ }
5801
+ }
5802
+ return false;
5803
+ }
5804
+
5833
5805
// Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
5834
5806
// when structural type comparisons have been started for 10 or more instantiations of the same generic type. It is possible,
5835
5807
// though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely expanding.
0 commit comments