Skip to content

Commit 757b70f

Browse files
committed
Add support for abstract constructor types
1 parent 75f88ee commit 757b70f

31 files changed

+1222
-498
lines changed

src/compiler/checker.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -4590,8 +4590,12 @@ namespace ts {
45904590
returnTypeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword);
45914591
}
45924592
}
4593+
let modifiers: Modifier[] | undefined;
4594+
if ((kind === SyntaxKind.ConstructorType) && signature.flags & SignatureFlags.Abstract) {
4595+
modifiers = createModifiersFromModifierFlags(ModifierFlags.Abstract);
4596+
}
45934597
context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum
4594-
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode, typeArguments);
4598+
return createSignatureDeclaration(kind, modifiers, typeParameters, parameters, returnTypeNode, typeArguments);
45954599
}
45964600

45974601
function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration {
@@ -8013,7 +8017,10 @@ namespace ts {
80138017
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
80148018
if (signatures.length === 1) {
80158019
const s = signatures[0];
8016-
return !s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s) && getElementTypeOfArrayType(getTypeOfParameter(s.parameters[0])) === anyType;
8020+
if (!s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s)) {
8021+
const paramType = getTypeOfParameter(s.parameters[0]);
8022+
return isTypeAny(paramType) || getElementTypeOfArrayType(paramType) === anyType;
8023+
}
80178024
}
80188025
return false;
80198026
}
@@ -8994,8 +9001,10 @@ namespace ts {
89949001
function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
89959002
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
89969003
const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
9004+
const declaration = getClassLikeDeclarationOfSymbol(classType.symbol);
9005+
const isAbstract = !!declaration && hasModifier(declaration, ModifierFlags.Abstract);
89979006
if (baseSignatures.length === 0) {
8998-
return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None)];
9007+
return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, isAbstract ? SignatureFlags.Abstract : SignatureFlags.None)];
89999008
}
90009009
const baseTypeNode = getBaseTypeNodeOfClass(classType)!;
90019010
const isJavaScript = isInJSFile(baseTypeNode);
@@ -9009,6 +9018,7 @@ namespace ts {
90099018
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig);
90109019
sig.typeParameters = classType.localTypeParameters;
90119020
sig.resolvedReturnType = classType;
9021+
sig.flags = isAbstract ? sig.flags | SignatureFlags.Abstract : sig.flags & ~SignatureFlags.Abstract;
90129022
result.push(sig);
90139023
}
90149024
}
@@ -10403,6 +10413,10 @@ namespace ts {
1040310413
if (hasRestParameter(declaration) || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters)) {
1040410414
flags |= SignatureFlags.HasRestParameter;
1040510415
}
10416+
if (isConstructorTypeNode(declaration) && hasModifier(declaration, ModifierFlags.Abstract) ||
10417+
isConstructorDeclaration(declaration) && hasModifier(declaration.parent, ModifierFlags.Abstract)) {
10418+
flags |= SignatureFlags.Abstract;
10419+
}
1040610420
links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters,
1040710421
/*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined,
1040810422
minArgumentCount, flags);
@@ -16174,7 +16188,9 @@ namespace ts {
1617416188
SignatureKind.Call : kind);
1617516189

1617616190
if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) {
16177-
if (isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
16191+
const sourceIsAbstract = !!(sourceSignatures[0].flags & SignatureFlags.Abstract);
16192+
const targetIsAbstract = !!(targetSignatures[0].flags & SignatureFlags.Abstract);
16193+
if (sourceIsAbstract && !targetIsAbstract) {
1617816194
// An abstract constructor type is not assignable to a non-abstract constructor type
1617916195
// as it would otherwise be possible to new an abstract class. Note that the assignability
1618016196
// check we perform for an extends clause excludes construct signatures from the target,
@@ -25067,8 +25083,7 @@ namespace ts {
2506725083
// Note, only class declarations can be declared abstract.
2506825084
// In the case of a merged class-module or class-interface declaration,
2506925085
// only the class declaration node will have the Abstract flag set.
25070-
const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
25071-
if (valueDecl && hasModifier(valueDecl, ModifierFlags.Abstract)) {
25086+
if (constructSignatures[0].flags & SignatureFlags.Abstract) {
2507225087
error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class);
2507325088
return resolveErrorCall(node);
2507425089
}
@@ -28980,14 +28995,13 @@ namespace ts {
2898028995
const implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent;
2898128996
return implementationSharesContainerWithFirstOverload ? implementation! : overloads[0];
2898228997
}
28983-
28998+
2898428999
function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void {
2898529000
// Error if some overloads have a flag that is not shared by all overloads. To find the
2898629001
// deviations, we XOR someOverloadFlags with allOverloadFlags
2898729002
const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags;
2898829003
if (someButNotAllOverloadFlags !== 0) {
2898929004
const canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck);
28990-
2899129005
forEach(overloads, o => {
2899229006
const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags;
2899329007
if (deviation & ModifierFlags.Export) {
@@ -29005,7 +29019,7 @@ namespace ts {
2900529019
});
2900629020
}
2900729021
}
29008-
29022+
2900929023
function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void {
2901029024
if (someHaveQuestionToken !== allHaveQuestionToken) {
2901129025
const canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation));
@@ -33331,8 +33345,8 @@ namespace ts {
3333133345
return checkPropertyDeclaration(<PropertyDeclaration>node);
3333233346
case SyntaxKind.PropertySignature:
3333333347
return checkPropertySignature(<PropertySignature>node);
33334-
case SyntaxKind.FunctionType:
3333533348
case SyntaxKind.ConstructorType:
33349+
case SyntaxKind.FunctionType:
3333633350
case SyntaxKind.CallSignature:
3333733351
case SyntaxKind.ConstructSignature:
3333833352
case SyntaxKind.IndexSignature:
@@ -35469,7 +35483,8 @@ namespace ts {
3546935483
if (flags & ModifierFlags.Abstract) {
3547035484
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract");
3547135485
}
35472-
if (node.kind !== SyntaxKind.ClassDeclaration) {
35486+
if (node.kind !== SyntaxKind.ClassDeclaration &&
35487+
node.kind !== SyntaxKind.ConstructorType) {
3547335488
if (node.kind !== SyntaxKind.MethodDeclaration &&
3547435489
node.kind !== SyntaxKind.PropertyDeclaration &&
3547535490
node.kind !== SyntaxKind.GetAccessor &&
@@ -35580,6 +35595,7 @@ namespace ts {
3558035595
case SyntaxKind.FunctionDeclaration:
3558135596
return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword);
3558235597
case SyntaxKind.ClassDeclaration:
35598+
case SyntaxKind.ConstructorType:
3558335599
return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword);
3558435600
case SyntaxKind.InterfaceDeclaration:
3558535601
case SyntaxKind.VariableStatement:
@@ -35589,7 +35605,6 @@ namespace ts {
3558935605
return nodeHasAnyModifiersExcept(node, SyntaxKind.ConstKeyword);
3559035606
default:
3559135607
Debug.fail();
35592-
return false;
3559335608
}
3559435609
}
3559535610
}

src/compiler/emitter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,7 @@ namespace ts {
20482048

20492049
function emitConstructorType(node: ConstructorTypeNode) {
20502050
pushNameGenerationScope(node);
2051+
emitModifiers(node, node.modifiers);
20512052
writeKeyword("new");
20522053
writeSpace();
20532054
emitTypeParameters(node, node.typeParameters);

src/compiler/factoryPublic.ts

+54-21
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ namespace ts {
453453
type: TypeNode | undefined,
454454
name: string | PropertyName,
455455
questionToken: QuestionToken | undefined) {
456-
const node = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature;
456+
const node = createSignatureDeclaration(SyntaxKind.MethodSignature, /*modifiers*/ undefined, typeParameters, parameters, type) as MethodSignature;
457457
node.name = asName(name);
458458
node.questionToken = questionToken;
459459
return node;
@@ -651,19 +651,19 @@ namespace ts {
651651
}
652652

653653
export function createCallSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
654-
return createSignatureDeclaration(SyntaxKind.CallSignature, typeParameters, parameters, type) as CallSignatureDeclaration;
654+
return createSignatureDeclaration(SyntaxKind.CallSignature, /*modifiers*/ undefined, typeParameters, parameters, type) as CallSignatureDeclaration;
655655
}
656656

657657
export function updateCallSignature(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
658-
return updateSignatureDeclaration(node, typeParameters, parameters, type);
658+
return updateSignatureDeclaration(node, /*modifiers*/ undefined, typeParameters, parameters, type);
659659
}
660660

661-
export function createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
662-
return createSignatureDeclaration(SyntaxKind.ConstructSignature, typeParameters, parameters, type) as ConstructSignatureDeclaration;
661+
export function createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration {
662+
return createSignatureDeclaration(SyntaxKind.ConstructSignature, /*modifiers*/ undefined, typeParameters, parameters, type) as ConstructSignatureDeclaration;
663663
}
664664

665-
export function updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
666-
return updateSignatureDeclaration(node, typeParameters, parameters, type);
665+
export function updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration {
666+
return updateSignatureDeclaration(node, /*modifiers*/ undefined, typeParameters, parameters, type);
667667
}
668668

669669
export function createIndexSignature(
@@ -694,20 +694,22 @@ namespace ts {
694694
}
695695

696696
/* @internal */
697-
export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, typeArguments?: readonly TypeNode[] | undefined) {
697+
export function createSignatureDeclaration(kind: SyntaxKind, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, typeArguments?: readonly TypeNode[] | undefined) {
698698
const node = createSynthesizedNode(kind) as SignatureDeclaration;
699+
node.modifiers = asNodeArray(modifiers);
699700
node.typeParameters = asNodeArray(typeParameters);
700701
node.parameters = asNodeArray(parameters);
701702
node.type = type;
702703
node.typeArguments = asNodeArray(typeArguments);
703704
return node;
704705
}
705706

706-
function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T {
707-
return node.typeParameters !== typeParameters
707+
function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): T {
708+
return node.modifiers !== modifiers
709+
|| node.typeParameters !== typeParameters
708710
|| node.parameters !== parameters
709711
|| node.type !== type
710-
? updateNode(<T>createSignatureDeclaration(node.kind, typeParameters, parameters, type), node)
712+
? updateNode(<T>createSignatureDeclaration(node.kind, modifiers, typeParameters, parameters, type), node)
711713
: node;
712714
}
713715

@@ -756,19 +758,50 @@ namespace ts {
756758
}
757759

758760
export function createFunctionTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
759-
return createSignatureDeclaration(SyntaxKind.FunctionType, typeParameters, parameters, type) as FunctionTypeNode;
761+
return createSignatureDeclaration(SyntaxKind.FunctionType, /*modifiers*/ undefined, typeParameters, parameters, type) as FunctionTypeNode;
760762
}
761763

762764
export function updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
763-
return updateSignatureDeclaration(node, typeParameters, parameters, type);
764-
}
765-
766-
export function createConstructorTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
767-
return createSignatureDeclaration(SyntaxKind.ConstructorType, typeParameters, parameters, type) as ConstructorTypeNode;
768-
}
769-
770-
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
771-
return updateSignatureDeclaration(node, typeParameters, parameters, type);
765+
return updateSignatureDeclaration(node, /*modifiers*/ undefined, typeParameters, parameters, type);
766+
}
767+
768+
export function createConstructorTypeNode(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructorTypeNode;
769+
export function createConstructorTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructorTypeNode;
770+
export function createConstructorTypeNode(...args:
771+
| [readonly Modifier[] | undefined, readonly TypeParameterDeclaration[] | undefined, readonly ParameterDeclaration[], TypeNode | undefined]
772+
| [readonly TypeParameterDeclaration[] | undefined, readonly ParameterDeclaration[], TypeNode | undefined]
773+
) {
774+
let modifiers: readonly Modifier[] | undefined;
775+
let typeParameters: readonly TypeParameterDeclaration[] | undefined;
776+
let parameters: readonly ParameterDeclaration[];
777+
let type: TypeNode | undefined;
778+
if (args.length === 4) {
779+
[modifiers, typeParameters, parameters, type] = args;
780+
}
781+
else {
782+
[typeParameters, parameters, type] = args;
783+
}
784+
return createSignatureDeclaration(SyntaxKind.ConstructorType, modifiers, typeParameters, parameters, type) as ConstructorTypeNode;
785+
}
786+
787+
export function updateConstructorTypeNode(node: ConstructorTypeNode, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructorTypeNode;
788+
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructorTypeNode;
789+
export function updateConstructorTypeNode(node: ConstructorTypeNode, ...args:
790+
| [readonly Modifier[] | undefined, readonly TypeParameterDeclaration[] | undefined, readonly ParameterDeclaration[], TypeNode | undefined]
791+
| [readonly TypeParameterDeclaration[] | undefined, readonly ParameterDeclaration[], TypeNode | undefined]
792+
) {
793+
let modifiers: readonly Modifier[] | undefined;
794+
let typeParameters: readonly TypeParameterDeclaration[] | undefined;
795+
let parameters: readonly ParameterDeclaration[];
796+
let type: TypeNode | undefined;
797+
if (args.length === 4) {
798+
[modifiers, typeParameters, parameters, type] = args;
799+
}
800+
else {
801+
[typeParameters, parameters, type] = args;
802+
modifiers = node.modifiers;
803+
}
804+
return updateSignatureDeclaration(node, modifiers, typeParameters, parameters, type);
772805
}
773806

774807
export function createTypeQueryNode(exprName: EntityName) {

0 commit comments

Comments
 (0)