Skip to content

Commit 46b015f

Browse files
authored
Fixed the issue with some longer variadic tuples with any rest being incorrectly assignable to shorter variadic tuples (#50218)
1 parent fdcb2ff commit 46b015f

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
@@ -20592,28 +20592,35 @@ namespace ts {
2059220592
}
2059320593
const sourceTypeArguments = getTypeArguments(source);
2059420594
const targetTypeArguments = getTypeArguments(target);
20595-
const startCount = Math.min(isTupleType(source) ? getStartElementCount(source.target, ElementFlags.NonRest) : 0, getStartElementCount(target.target, ElementFlags.NonRest));
20596-
const endCount = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.NonRest) : 0, targetRestFlag ? getEndElementCount(target.target, ElementFlags.NonRest) : 0);
20595+
const targetStartCount = getStartElementCount(target.target, ElementFlags.NonRest);
20596+
const targetEndCount = getEndElementCount(target.target, ElementFlags.NonRest);
20597+
const targetHasRestElement = target.target.hasRestElement;
2059720598
let canExcludeDiscriminants = !!excludedProperties;
20598-
for (let i = 0; i < targetArity; i++) {
20599-
const sourceIndex = i < targetArity - endCount ? i : i + sourceArity - targetArity;
20600-
const sourceFlags = isTupleType(source) && (i < startCount || i >= targetArity - endCount) ? source.target.elementFlags[sourceIndex] : ElementFlags.Rest;
20601-
const targetFlags = target.target.elementFlags[i];
20599+
for (let sourcePosition = 0; sourcePosition < sourceArity; sourcePosition++) {
20600+
const sourceFlags = isTupleType(source) ? source.target.elementFlags[sourcePosition] : ElementFlags.Rest;
20601+
const sourcePositionFromEnd = sourceArity - 1 - sourcePosition;
20602+
20603+
const targetPosition = targetHasRestElement && sourcePosition >= targetStartCount
20604+
? targetArity - 1 - Math.min(sourcePositionFromEnd, targetEndCount)
20605+
: sourcePosition;
20606+
20607+
const targetFlags = target.target.elementFlags[targetPosition];
20608+
2060220609
if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) {
2060320610
if (reportErrors) {
20604-
reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, i);
20611+
reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, targetPosition);
2060520612
}
2060620613
return Ternary.False;
2060720614
}
2060820615
if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) {
2060920616
if (reportErrors) {
20610-
reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourceIndex, i);
20617+
reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourcePosition, targetPosition);
2061120618
}
2061220619
return Ternary.False;
2061320620
}
2061420621
if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) {
2061520622
if (reportErrors) {
20616-
reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, i);
20623+
reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, targetPosition);
2061720624
}
2061820625
return Ternary.False;
2061920626
}
@@ -20622,24 +20629,24 @@ namespace ts {
2062220629
if (sourceFlags & ElementFlags.Variable || targetFlags & ElementFlags.Variable) {
2062320630
canExcludeDiscriminants = false;
2062420631
}
20625-
if (canExcludeDiscriminants && excludedProperties?.has(("" + i) as __String)) {
20632+
if (canExcludeDiscriminants && excludedProperties?.has(("" + sourcePosition) as __String)) {
2062620633
continue;
2062720634
}
2062820635
}
20629-
const sourceType = !isTupleType(source) ? sourceTypeArguments[0] :
20630-
i < startCount || i >= targetArity - endCount ? removeMissingType(sourceTypeArguments[sourceIndex], !!(sourceFlags & targetFlags & ElementFlags.Optional)) :
20631-
getElementTypeOfSliceOfTupleType(source, startCount, endCount) || neverType;
20632-
const targetType = targetTypeArguments[i];
20636+
20637+
const sourceType = removeMissingType(sourceTypeArguments[sourcePosition], !!(sourceFlags & targetFlags & ElementFlags.Optional));
20638+
const targetType = targetTypeArguments[targetPosition];
20639+
2063320640
const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) :
2063420641
removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional));
2063520642
const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
2063620643
if (!related) {
2063720644
if (reportErrors && (targetArity > 1 || sourceArity > 1)) {
20638-
if (i < startCount || i >= targetArity - endCount || sourceArity - startCount - endCount === 1) {
20639-
reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourceIndex, i);
20645+
if (targetHasRestElement && sourcePosition >= targetStartCount && sourcePositionFromEnd >= targetEndCount && targetStartCount !== sourceArity - targetEndCount - 1) {
20646+
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);
2064020647
}
2064120648
else {
20642-
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);
20649+
reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourcePosition, targetPosition);
2064320650
}
2064420651
}
2064520652
return Ternary.False;

src/compiler/types.ts

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

59315931
export interface TupleType extends GenericType {
59325932
elementFlags: readonly ElementFlags[];
5933-
minLength: number; // Number of required or variadic elements
5934-
fixedLength: number; // Number of initial required or optional elements
5935-
hasRestElement: boolean; // True if tuple has any rest or variadic elements
5933+
/** Number of required or variadic elements */
5934+
minLength: number;
5935+
/** Number of initial required or optional elements */
5936+
fixedLength: number;
5937+
/** True if tuple has any rest or variadic elements */
5938+
hasRestElement: boolean;
59365939
combinedFlags: ElementFlags;
59375940
readonly: boolean;
59385941
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
@@ -2781,8 +2781,11 @@ declare namespace ts {
27812781
}
27822782
export interface TupleType extends GenericType {
27832783
elementFlags: readonly ElementFlags[];
2784+
/** Number of required or variadic elements */
27842785
minLength: number;
2786+
/** Number of initial required or optional elements */
27852787
fixedLength: number;
2788+
/** True if tuple has any rest or variadic elements */
27862789
hasRestElement: boolean;
27872790
combinedFlags: ElementFlags;
27882791
readonly: boolean;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,8 +2781,11 @@ declare namespace ts {
27812781
}
27822782
export interface TupleType extends GenericType {
27832783
elementFlags: readonly ElementFlags[];
2784+
/** Number of required or variadic elements */
27842785
minLength: number;
2786+
/** Number of initial required or optional elements */
27852787
fixedLength: number;
2788+
/** True if tuple has any rest or variadic elements */
27862789
hasRestElement: boolean;
27872790
combinedFlags: ElementFlags;
27882791
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)