@@ -5549,32 +5549,24 @@ namespace ts {
55495549 if (target === anyFunctionType || source === anyFunctionType) {
55505550 return Ternary.True;
55515551 }
5552+
55525553 const sourceSignatures = getSignaturesOfType(source, kind);
55535554 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);
55755563 }
5564+ return Ternary.False;
55765565 }
55775566
5567+ let result = Ternary.True;
5568+ const saveErrorInfo = errorInfo;
5569+
55785570 outer: for (const t of targetSignatures) {
55795571 if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
55805572 // Only elaborate errors from the first failure
@@ -5601,40 +5593,6 @@ namespace ts {
56015593 }
56025594 }
56035595 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- }
56385596 }
56395597
56405598 /**
@@ -5830,6 +5788,20 @@ namespace ts {
58305788 }
58315789 }
58325790
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+
58335805 // Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
58345806 // when structural type comparisons have been started for 10 or more instantiations of the same generic type. It is possible,
58355807 // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely expanding.
0 commit comments