@@ -10409,7 +10409,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
10409
10409
// If the parent is a tuple type, the rest element has a tuple type of the
10410
10410
// remaining tuple element types. Otherwise, the rest element has an array type with same
10411
10411
// element type as the parent type.
10412
- const baseConstraint = getBaseConstraintOrType (parentType);
10412
+ const baseConstraint = mapType (parentType, t => t.flags & TypeFlags.InstantiableNonPrimitive ? getBaseConstraintOrType(t) : t );
10413
10413
type = everyType(baseConstraint, isTupleType) ?
10414
10414
mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) :
10415
10415
createArrayType(elementType);
@@ -12556,6 +12556,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
12556
12556
return needApparentType ? getApparentType(type) : type;
12557
12557
}
12558
12558
12559
+ function getThisArgument(type: Type) {
12560
+ return getObjectFlags(type) & ObjectFlags.Reference && length(getTypeArguments(type as TypeReference)) > getTypeReferenceArity(type as TypeReference) ? last(getTypeArguments(type as TypeReference)) : type;
12561
+ }
12562
+
12559
12563
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) {
12560
12564
let mapper: TypeMapper | undefined;
12561
12565
let members: SymbolTable;
@@ -12685,7 +12689,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
12685
12689
return [sig.parameters];
12686
12690
12687
12691
function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number) {
12688
- const elementTypes = getTypeArguments (restType);
12692
+ const elementTypes = getElementTypes (restType);
12689
12693
const associatedNames = getUniqAssociatedNamesFromTupleType(restType);
12690
12694
const restParams = map(elementTypes, (t, i) => {
12691
12695
// Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name
@@ -13583,7 +13587,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13583
13587
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType) ||
13584
13588
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType)) ||
13585
13589
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType) ||
13586
- isGenericTupleType(type) && findIndex(getTypeArguments (type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
13590
+ isGenericTupleType(type) && findIndex(getElementTypes (type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
13587
13591
}
13588
13592
13589
13593
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
@@ -13708,7 +13712,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13708
13712
}
13709
13713
13710
13714
function getBaseConstraintOfType(type: Type): Type | undefined {
13711
- if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) {
13715
+ if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || isGenericTupleType(type) ) {
13712
13716
const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType);
13713
13717
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
13714
13718
}
@@ -13737,7 +13741,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13737
13741
return type.resolvedBaseConstraint;
13738
13742
}
13739
13743
const stack: object[] = [];
13740
- return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type);
13744
+ return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), getThisArgument( type) );
13741
13745
13742
13746
function getImmediateBaseConstraint(t: Type): Type {
13743
13747
if (!t.immediateBaseConstraint) {
@@ -13839,6 +13843,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13839
13843
if (t.flags & TypeFlags.Substitution) {
13840
13844
return getBaseConstraint(getSubstitutionIntersection(t as SubstitutionType));
13841
13845
}
13846
+ if (isGenericTupleType(t)) {
13847
+ // We substitute constraints for variadic elements only when the constraints are array types or
13848
+ // non-variadic tuple types as we want to avoid further (possibly unbounded) recursion.
13849
+ const newElements = map(getElementTypes(t), (v, i) => {
13850
+ const constraint = t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v;
13851
+ return constraint && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v;
13852
+ });
13853
+ return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations);
13854
+ }
13842
13855
return t;
13843
13856
}
13844
13857
}
@@ -16147,7 +16160,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16147
16160
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
16148
16161
}
16149
16162
else if (isTupleType(type)) {
16150
- const elements = getTypeArguments (type);
16163
+ const elements = getElementTypes (type);
16151
16164
if (elements.length + expandedTypes.length >= 10_000) {
16152
16165
error(currentNode, isPartOfTypeNode(currentNode!)
16153
16166
? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent
@@ -16229,6 +16242,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16229
16242
return type.elementFlags.length - findLastIndex(type.elementFlags, f => !(f & flags)) - 1;
16230
16243
}
16231
16244
16245
+ function getElementTypes(type: TupleTypeReference): readonly Type[] {
16246
+ const typeArguments = getTypeArguments(type);
16247
+ const arity = getTypeReferenceArity(type);
16248
+ return typeArguments.length === arity ? typeArguments : typeArguments.slice(0, arity);
16249
+ }
16250
+
16232
16251
function getTypeFromOptionalTypeNode(node: OptionalTypeNode): Type {
16233
16252
return addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true);
16234
16253
}
@@ -17779,7 +17798,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17779
17798
}
17780
17799
17781
17800
function isDeferredType(type: Type, checkTuples: boolean) {
17782
- return isGenericType(type) || checkTuples && isTupleType(type) && some(getTypeArguments (type), isGenericType);
17801
+ return isGenericType(type) || checkTuples && isTupleType(type) && some(getElementTypes (type), isGenericType);
17783
17802
}
17784
17803
17785
17804
function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
@@ -18920,7 +18939,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18920
18939
// M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M<T>, ...M<C[]>] and then rely on tuple type
18921
18940
// normalization to resolve the non-generic parts of the resulting tuple.
18922
18941
const elementFlags = tupleType.target.elementFlags;
18923
- const elementTypes = map(getTypeArguments (tupleType), (t, i) => {
18942
+ const elementTypes = map(getElementTypes (tupleType), (t, i) => {
18924
18943
const singleton = elementFlags[i] & ElementFlags.Variadic ? t :
18925
18944
elementFlags[i] & ElementFlags.Rest ? createArrayType(t) :
18926
18945
createTupleType([t], [elementFlags[i]]);
@@ -18939,7 +18958,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18939
18958
18940
18959
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
18941
18960
const elementFlags = tupleType.target.elementFlags;
18942
- const elementTypes = map(getTypeArguments (tupleType), (_, i) =>
18961
+ const elementTypes = map(getElementTypes (tupleType), (_, i) =>
18943
18962
instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper));
18944
18963
const modifiers = getMappedTypeModifiers(mappedType);
18945
18964
const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) :
@@ -20244,7 +20263,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20244
20263
}
20245
20264
20246
20265
function getNormalizedTupleType(type: TupleTypeReference, writing: boolean): Type {
20247
- const elements = getTypeArguments (type);
20266
+ const elements = getElementTypes (type);
20248
20267
const normalizedElements = sameMap(elements, t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t);
20249
20268
return elements !== normalizedElements ? createNormalizedTupleType(type.target, normalizedElements) : type;
20250
20269
}
@@ -21802,6 +21821,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21802
21821
return Ternary.False;
21803
21822
}
21804
21823
}
21824
+ else if (isGenericTupleType(source) && isTupleType(target) && !isGenericTupleType(target)) {
21825
+ const constraint = getBaseConstraintOrType(source);
21826
+ if (constraint !== source) {
21827
+ return isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors);
21828
+ }
21829
+ }
21805
21830
// A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x: string]: xxx }
21806
21831
// but not vice-versa. Without this rule, those types would be mutual subtypes.
21807
21832
else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
@@ -24083,7 +24108,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
24083
24108
function isPartiallyInferableType(type: Type): boolean {
24084
24109
return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) ||
24085
24110
isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) ||
24086
- isTupleType(type) && some(getTypeArguments (type), isPartiallyInferableType);
24111
+ isTupleType(type) && some(getElementTypes (type), isPartiallyInferableType);
24087
24112
}
24088
24113
24089
24114
function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) {
@@ -24098,7 +24123,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
24098
24123
return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source));
24099
24124
}
24100
24125
if (isTupleType(source)) {
24101
- const elementTypes = map(getTypeArguments (source), t => inferReverseMappedType(t, target, constraint));
24126
+ const elementTypes = map(getElementTypes (source), t => inferReverseMappedType(t, target, constraint));
24102
24127
const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
24103
24128
sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
24104
24129
source.target.elementFlags;
@@ -32491,7 +32516,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
32491
32516
function getMutableArrayOrTupleType(type: Type) {
32492
32517
return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) :
32493
32518
type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type :
32494
- isTupleType(type) ? createTupleType(getTypeArguments (type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) :
32519
+ isTupleType(type) ? createTupleType(getElementTypes (type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) :
32495
32520
createTupleType([type], [ElementFlags.Variadic]);
32496
32521
}
32497
32522
@@ -32825,7 +32850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
32825
32850
// We can call checkExpressionCached because spread expressions never have a contextual type.
32826
32851
const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression));
32827
32852
if (spreadType && isTupleType(spreadType)) {
32828
- forEach(getTypeArguments (spreadType), (t, i) => {
32853
+ forEach(getElementTypes (spreadType), (t, i) => {
32829
32854
const flags = spreadType.target.elementFlags[i];
32830
32855
const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t,
32831
32856
!!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]);
@@ -37436,7 +37461,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37436
37461
37437
37462
function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) {
37438
37463
const patternElements = pattern.elements;
37439
- const elementTypes = getTypeArguments (type).slice();
37464
+ const elementTypes = getElementTypes (type).slice();
37440
37465
const elementFlags = type.target.elementFlags.slice();
37441
37466
for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) {
37442
37467
const e = patternElements[i];
0 commit comments