Skip to content

Commit ab0eb5c

Browse files
committed
Fixed the issue with some longer variadic tuples with any rest being incorrectly assignable to shorter variadic tuples
1 parent c9586f3 commit ab0eb5c

File tree

10 files changed

+191
-147
lines changed

10 files changed

+191
-147
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20275,28 +20275,35 @@ namespace ts {
2027520275
}
2027620276
const sourceTypeArguments = getTypeArguments(source);
2027720277
const targetTypeArguments = getTypeArguments(target);
20278-
const startCount = Math.min(isTupleType(source) ? getStartElementCount(source.target, ElementFlags.NonRest) : 0, getStartElementCount(target.target, ElementFlags.NonRest));
20279-
const endCount = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.NonRest) : 0, targetRestFlag ? getEndElementCount(target.target, ElementFlags.NonRest) : 0);
20278+
const targetStartCount = getStartElementCount(target.target, ElementFlags.NonRest);
20279+
const targetEndCount = getEndElementCount(target.target, ElementFlags.NonRest);
20280+
const targetHasRestElement = target.target.hasRestElement;
2028020281
let canExcludeDiscriminants = !!excludedProperties;
20281-
for (let i = 0; i < targetArity; i++) {
20282-
const sourceIndex = i < targetArity - endCount ? i : i + sourceArity - targetArity;
20283-
const sourceFlags = isTupleType(source) && (i < startCount || i >= targetArity - endCount) ? source.target.elementFlags[sourceIndex] : ElementFlags.Rest;
20284-
const targetFlags = target.target.elementFlags[i];
20282+
for (let sourcePosition = 0; sourcePosition < sourceArity; sourcePosition++) {
20283+
const sourceFlags = isTupleType(source) ? source.target.elementFlags[sourcePosition] : ElementFlags.Rest;
20284+
const sourcePositionFromEnd = sourceArity - 1 - sourcePosition;
20285+
20286+
const targetPosition = targetHasRestElement && sourcePosition >= targetStartCount
20287+
? targetArity - 1 - Math.min(sourcePositionFromEnd, targetEndCount)
20288+
: sourcePosition;
20289+
20290+
const targetFlags = target.target.elementFlags[targetPosition];
20291+
2028520292
if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) {
2028620293
if (reportErrors) {
20287-
reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, i);
20294+
reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, targetPosition);
2028820295
}
2028920296
return Ternary.False;
2029020297
}
2029120298
if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) {
2029220299
if (reportErrors) {
20293-
reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourceIndex, i);
20300+
reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourcePosition, targetPosition);
2029420301
}
2029520302
return Ternary.False;
2029620303
}
2029720304
if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) {
2029820305
if (reportErrors) {
20299-
reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, i);
20306+
reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, targetPosition);
2030020307
}
2030120308
return Ternary.False;
2030220309
}
@@ -20305,24 +20312,24 @@ namespace ts {
2030520312
if (sourceFlags & ElementFlags.Variable || targetFlags & ElementFlags.Variable) {
2030620313
canExcludeDiscriminants = false;
2030720314
}
20308-
if (canExcludeDiscriminants && excludedProperties?.has(("" + i) as __String)) {
20315+
if (canExcludeDiscriminants && excludedProperties?.has(("" + sourcePosition) as __String)) {
2030920316
continue;
2031020317
}
2031120318
}
20312-
const sourceType = !isTupleType(source) ? sourceTypeArguments[0] :
20313-
i < startCount || i >= targetArity - endCount ? removeMissingType(sourceTypeArguments[sourceIndex], !!(sourceFlags & targetFlags & ElementFlags.Optional)) :
20314-
getElementTypeOfSliceOfTupleType(source, startCount, endCount) || neverType;
20315-
const targetType = targetTypeArguments[i];
20319+
20320+
const sourceType = removeMissingType(sourceTypeArguments[sourcePosition], !!(sourceFlags & targetFlags & ElementFlags.Optional));
20321+
const targetType = targetTypeArguments[targetPosition];
20322+
2031620323
const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) :
2031720324
removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional));
2031820325
const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
2031920326
if (!related) {
2032020327
if (reportErrors && (targetArity > 1 || sourceArity > 1)) {
20321-
if (i < startCount || i >= targetArity - endCount || sourceArity - startCount - endCount === 1) {
20322-
reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourceIndex, i);
20328+
if (targetHasRestElement && sourcePosition >= targetStartCount && sourcePositionFromEnd >= targetEndCount && targetStartCount !== sourceArity - targetEndCount - 1) {
20329+
reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, targetStartCount, sourceArity - targetEndCount - 1, targetPosition);
2032320330
}
2032420331
else {
20325-
reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, startCount, sourceArity - endCount - 1, i);
20332+
reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourcePosition, targetPosition);
2032620333
}
2032720334
}
2032820335
return Ternary.False;

src/compiler/types.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5691,9 +5691,12 @@ namespace ts {
56915691

56925692
export interface TupleType extends GenericType {
56935693
elementFlags: readonly ElementFlags[];
5694-
minLength: number; // Number of required or variadic elements
5695-
fixedLength: number; // Number of initial required or optional elements
5696-
hasRestElement: boolean; // True if tuple has any rest or variadic elements
5694+
/** Number of required or variadic elements */
5695+
minLength: number;
5696+
/** Number of initial required or optional elements */
5697+
fixedLength: number;
5698+
/** True if tuple has any rest or variadic elements */
5699+
hasRestElement: boolean;
56975700
combinedFlags: ElementFlags;
56985701
readonly: boolean;
56995702
labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[];

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2766,8 +2766,11 @@ declare namespace ts {
27662766
}
27672767
export interface TupleType extends GenericType {
27682768
elementFlags: readonly ElementFlags[];
2769+
/** Number of required or variadic elements */
27692770
minLength: number;
2771+
/** Number of initial required or optional elements */
27702772
fixedLength: number;
2773+
/** True if tuple has any rest or variadic elements */
27712774
hasRestElement: boolean;
27722775
combinedFlags: ElementFlags;
27732776
readonly: boolean;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2766,8 +2766,11 @@ declare namespace ts {
27662766
}
27672767
export interface TupleType extends GenericType {
27682768
elementFlags: readonly ElementFlags[];
2769+
/** Number of required or variadic elements */
27692770
minLength: number;
2771+
/** Number of initial required or optional elements */
27702772
fixedLength: number;
2773+
/** True if tuple has any rest or variadic elements */
27712774
hasRestElement: boolean;
27722775
combinedFlags: ElementFlags;
27732776
readonly: boolean;

tests/baselines/reference/restTupleElements1.errors.txt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ tests/cases/conformance/types/tuple/restTupleElements1.ts(33,31): error TS2344:
1818
Type 'string' is not assignable to type 'number'.
1919
tests/cases/conformance/types/tuple/restTupleElements1.ts(34,31): error TS2344: Type '[number, number, string]' does not satisfy the constraint '[number, ...number[]]'.
2020
Type at positions 1 through 2 in source is not compatible with type at position 1 in target.
21-
Type 'string | number' is not assignable to type 'number'.
22-
Type 'string' is not assignable to type 'number'.
21+
Type 'string' is not assignable to type 'number'.
2322
tests/cases/conformance/types/tuple/restTupleElements1.ts(35,31): error TS2344: Type '[number, number, number, string]' does not satisfy the constraint '[number, ...number[]]'.
2423
Type at positions 1 through 3 in source is not compatible with type at position 1 in target.
25-
Type 'string | number' is not assignable to type 'number'.
26-
Type 'string' is not assignable to type 'number'.
24+
Type 'string' is not assignable to type 'number'.
2725
tests/cases/conformance/types/tuple/restTupleElements1.ts(59,4): error TS2345: Argument of type '[]' is not assignable to parameter of type '[unknown, ...unknown[]]'.
2826
Source has 0 element(s) but target requires 1.
2927

@@ -94,14 +92,12 @@ tests/cases/conformance/types/tuple/restTupleElements1.ts(59,4): error TS2345: A
9492
~~~~~~~~~~~~~~~~~~~~~~~~
9593
!!! error TS2344: Type '[number, number, string]' does not satisfy the constraint '[number, ...number[]]'.
9694
!!! error TS2344: Type at positions 1 through 2 in source is not compatible with type at position 1 in target.
97-
!!! error TS2344: Type 'string | number' is not assignable to type 'number'.
98-
!!! error TS2344: Type 'string' is not assignable to type 'number'.
95+
!!! error TS2344: Type 'string' is not assignable to type 'number'.
9996
assign<[number, ...number[]], [number, number, number, string]>(); // Error
10097
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10198
!!! error TS2344: Type '[number, number, number, string]' does not satisfy the constraint '[number, ...number[]]'.
10299
!!! error TS2344: Type at positions 1 through 3 in source is not compatible with type at position 1 in target.
103-
!!! error TS2344: Type 'string | number' is not assignable to type 'number'.
104-
!!! error TS2344: Type 'string' is not assignable to type 'number'.
100+
!!! error TS2344: Type 'string' is not assignable to type 'number'.
105101

106102
type T20 = [number, string, ...boolean[]];
107103

0 commit comments

Comments
 (0)