Skip to content

Commit b24fcd0

Browse files
committed
Recursive tuple types + fix instantiation of recursive type references
1 parent 643351c commit b24fcd0

File tree

1 file changed

+33
-36
lines changed

1 file changed

+33
-36
lines changed

src/compiler/checker.ts

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9581,13 +9581,25 @@ namespace ts {
95819581
return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]);
95829582
}
95839583

9584-
function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
9584+
function getArrayOrTupleTargetType(node: ArrayTypeNode | TupleTypeNode): GenericType {
9585+
const readonly = isReadonlyTypeOperator(node.parent);
9586+
if (node.kind === SyntaxKind.ArrayType || node.elementTypes.length === 1 && node.elementTypes[0].kind === SyntaxKind.RestType) {
9587+
return readonly ? globalReadonlyArrayType : globalArrayType;
9588+
}
9589+
const lastElement = lastOrUndefined(node.elementTypes);
9590+
const restElement = lastElement && lastElement.kind === SyntaxKind.RestType ? lastElement : undefined;
9591+
const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1;
9592+
return getTupleTypeOfArity(node.elementTypes.length, minLength, !!restElement, readonly, /*associatedNames*/ undefined);
9593+
}
9594+
9595+
function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type {
95859596
const links = getNodeLinks(node);
95869597
if (!links.resolvedType) {
9587-
const target = isReadonlyTypeOperator(node.parent) ? globalReadonlyArrayType : globalArrayType;
9598+
const target = getArrayOrTupleTargetType(node);
95889599
const aliasSymbol = getAliasSymbolForTypeNode(node);
95899600
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
9590-
links.resolvedType = createDeferredTypeReference(target, [node.elementType], /*mapper*/ undefined, aliasSymbol, aliasTypeArguments);
9601+
const elementTypes = node.kind === SyntaxKind.ArrayType ? [node.elementType] : node.elementTypes;
9602+
links.resolvedType = elementTypes.length ? createDeferredTypeReference(target, elementTypes, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments) : target;
95919603
}
95929604
return links.resolvedType;
95939605
}
@@ -9665,21 +9677,6 @@ namespace ts {
96659677
return elementTypes.length ? createTypeReference(tupleType, elementTypes) : tupleType;
96669678
}
96679679

9668-
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
9669-
const links = getNodeLinks(node);
9670-
if (!links.resolvedType) {
9671-
const lastElement = lastOrUndefined(node.elementTypes);
9672-
const restElement = lastElement && lastElement.kind === SyntaxKind.RestType ? lastElement : undefined;
9673-
const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1;
9674-
const elementTypes = map(node.elementTypes, n => {
9675-
const type = getTypeFromTypeNode(n);
9676-
return n === restElement && getIndexTypeOfType(type, IndexKind.Number) || type;
9677-
});
9678-
links.resolvedType = createTupleType(elementTypes, minLength, !!restElement, isReadonlyTypeOperator(node.parent));
9679-
}
9680-
return links.resolvedType;
9681-
}
9682-
96839680
function sliceTupleType(type: TupleTypeReference, index: number) {
96849681
const tuple = type.target;
96859682
if (tuple.hasRestElement) {
@@ -11169,9 +11166,8 @@ namespace ts {
1116911166
case SyntaxKind.TypeQuery:
1117011167
return getTypeFromTypeQueryNode(<TypeQueryNode>node);
1117111168
case SyntaxKind.ArrayType:
11172-
return getTypeFromArrayTypeNode(<ArrayTypeNode>node);
1117311169
case SyntaxKind.TupleType:
11174-
return getTypeFromTupleTypeNode(<TupleTypeNode>node);
11170+
return getTypeFromArrayOrTupleTypeNode(<ArrayTypeNode | TupleTypeNode>node);
1117511171
case SyntaxKind.OptionalType:
1117611172
return getTypeFromOptionalTypeNode(<OptionalTypeNode>node);
1117711173
case SyntaxKind.UnionType:
@@ -11183,10 +11179,11 @@ namespace ts {
1118311179
case SyntaxKind.JSDocOptionalType:
1118411180
return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type));
1118511181
case SyntaxKind.ParenthesizedType:
11186-
case SyntaxKind.RestType:
1118711182
case SyntaxKind.JSDocNonNullableType:
1118811183
case SyntaxKind.JSDocTypeExpression:
11189-
return getTypeFromTypeNode((<ParenthesizedTypeNode | RestTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression>node).type);
11184+
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression>node).type);
11185+
case SyntaxKind.RestType:
11186+
return getElementTypeOfArrayType(getTypeFromTypeNode((<RestTypeNode>node).type)) || errorType;
1119011187
case SyntaxKind.JSDocVariadicType:
1119111188
return getTypeFromJSDocVariadicType(node as JSDocVariadicType);
1119211189
case SyntaxKind.FunctionType:
@@ -11644,19 +11641,15 @@ namespace ts {
1164411641
return getAnonymousTypeInstantiation(<AnonymousType>type, mapper);
1164511642
}
1164611643
if (objectFlags & ObjectFlags.Reference) {
11647-
const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
11648-
if (resolvedTypeArguments) {
11649-
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
11650-
return newTypeArguments !== resolvedTypeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
11651-
}
11652-
else {
11653-
const typeArgumentNodes = (<TypeReference>type).typeArgumentNodes;
11654-
if (typeArgumentNodes) {
11655-
const combinedMapper = combineTypeMappers((<TypeReference>type).mapper, mapper);
11656-
return createDeferredTypeReference((<TypeReference>type).target, typeArgumentNodes, combinedMapper,
11657-
(<TypeReference>type).aliasSymbol, instantiateTypes((<TypeReference>type).aliasTypeArguments, combinedMapper));
11658-
}
11644+
const typeArgumentNodes = (<TypeReference>type).typeArgumentNodes;
11645+
if (typeArgumentNodes) {
11646+
const combinedMapper = combineTypeMappers((<TypeReference>type).mapper, mapper);
11647+
return createDeferredTypeReference((<TypeReference>type).target, typeArgumentNodes, combinedMapper,
11648+
(<TypeReference>type).aliasSymbol, instantiateTypes((<TypeReference>type).aliasTypeArguments, combinedMapper));
1165911649
}
11650+
const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
11651+
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
11652+
return newTypeArguments !== resolvedTypeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
1166011653
}
1166111654
return type;
1166211655
}
@@ -14446,8 +14439,12 @@ namespace ts {
1444614439
return type.flags & TypeFlags.TypeParameter && !getConstraintOfTypeParameter(<TypeParameter>type);
1444714440
}
1444814441

14442+
function isNonDeferredTypeReference(type: Type): type is TypeReference {
14443+
return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(<TypeReference>type).typeArgumentNodes;
14444+
}
14445+
1444914446
function isTypeReferenceWithGenericArguments(type: Type): boolean {
14450-
return !!(getObjectFlags(type) & ObjectFlags.Reference) && some(getTypeArguments(<TypeReference>type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t));
14447+
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t));
1445114448
}
1445214449

1445314450
/**
@@ -26090,7 +26087,7 @@ namespace ts {
2609026087
grammarErrorOnNode(e, Diagnostics.A_rest_element_must_be_last_in_a_tuple_type);
2609126088
break;
2609226089
}
26093-
if (!isArrayType(getTypeFromTypeNode(e))) {
26090+
if (!isArrayType(getTypeFromTypeNode((<RestTypeNode>e).type))) {
2609426091
error(e, Diagnostics.A_rest_element_type_must_be_an_array_type);
2609526092
}
2609626093
}

0 commit comments

Comments
 (0)