Skip to content

Commit 7c9d1d4

Browse files
committed
check index access for fixed length tuple
1 parent 937afab commit 7c9d1d4

File tree

7 files changed

+151
-0
lines changed

7 files changed

+151
-0
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18293,6 +18293,13 @@ namespace ts {
1829318293
error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal);
1829418294
return errorType;
1829518295
}
18296+
if (isTupleType(objectType) && !objectType.target.hasRestElement && isNumericLiteral(indexExpression)) {
18297+
const index = +indexExpression.text;
18298+
const maximumIndex = length(objectType.target.typeParameters);
18299+
if (index >= maximumIndex) {
18300+
error(indexExpression, Diagnostics.Indexed_access_0_is_out_of_range_of_tuple_the_maximum_of_index_is_1, index, maximumIndex);
18301+
}
18302+
}
1829618303

1829718304
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node);
1829818305
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,10 @@
24372437
"category": "Error",
24382438
"code": 2732
24392439
},
2440+
"Indexed access '{0}' is out of range of tuple, the maximum of index is '{1}'.": {
2441+
"category": "Error",
2442+
"code": 2733
2443+
},
24402444

24412445
"Import declaration '{0}' is using private name '{1}'.": {
24422446
"category": "Error",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/conformance/types/tuple/tupleLengthCheck.ts(5,14): error TS2733: Indexed access '2' is out of range of tuple, the maximum of index is '2'.
2+
tests/cases/conformance/types/tuple/tupleLengthCheck.ts(6,14): error TS2733: Indexed access '1000' is out of range of tuple, the maximum of index is '2'.
3+
4+
5+
==== tests/cases/conformance/types/tuple/tupleLengthCheck.ts (2 errors) ====
6+
declare const a: [number, string]
7+
declare const rest: [number, string, ...boolean[]]
8+
9+
const a1 = a[1]
10+
const a2 = a[2]
11+
~
12+
!!! error TS2733: Indexed access '2' is out of range of tuple, the maximum of index is '2'.
13+
const a3 = a[1000]
14+
~~~~
15+
!!! error TS2733: Indexed access '1000' is out of range of tuple, the maximum of index is '2'.
16+
17+
const a4 = rest[1]
18+
const a5 = rest[2]
19+
const a6 = rest[3]
20+
const a7 = rest[1000]
21+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tupleLengthCheck.ts]
2+
declare const a: [number, string]
3+
declare const rest: [number, string, ...boolean[]]
4+
5+
const a1 = a[1]
6+
const a2 = a[2]
7+
const a3 = a[1000]
8+
9+
const a4 = rest[1]
10+
const a5 = rest[2]
11+
const a6 = rest[3]
12+
const a7 = rest[1000]
13+
14+
15+
//// [tupleLengthCheck.js]
16+
var a1 = a[1];
17+
var a2 = a[2];
18+
var a3 = a[1000];
19+
var a4 = rest[1];
20+
var a5 = rest[2];
21+
var a6 = rest[3];
22+
var a7 = rest[1000];
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/types/tuple/tupleLengthCheck.ts ===
2+
declare const a: [number, string]
3+
>a : Symbol(a, Decl(tupleLengthCheck.ts, 0, 13))
4+
5+
declare const rest: [number, string, ...boolean[]]
6+
>rest : Symbol(rest, Decl(tupleLengthCheck.ts, 1, 13))
7+
8+
const a1 = a[1]
9+
>a1 : Symbol(a1, Decl(tupleLengthCheck.ts, 3, 5))
10+
>a : Symbol(a, Decl(tupleLengthCheck.ts, 0, 13))
11+
>1 : Symbol(1)
12+
13+
const a2 = a[2]
14+
>a2 : Symbol(a2, Decl(tupleLengthCheck.ts, 4, 5))
15+
>a : Symbol(a, Decl(tupleLengthCheck.ts, 0, 13))
16+
17+
const a3 = a[1000]
18+
>a3 : Symbol(a3, Decl(tupleLengthCheck.ts, 5, 5))
19+
>a : Symbol(a, Decl(tupleLengthCheck.ts, 0, 13))
20+
21+
const a4 = rest[1]
22+
>a4 : Symbol(a4, Decl(tupleLengthCheck.ts, 7, 5))
23+
>rest : Symbol(rest, Decl(tupleLengthCheck.ts, 1, 13))
24+
>1 : Symbol(1)
25+
26+
const a5 = rest[2]
27+
>a5 : Symbol(a5, Decl(tupleLengthCheck.ts, 8, 5))
28+
>rest : Symbol(rest, Decl(tupleLengthCheck.ts, 1, 13))
29+
30+
const a6 = rest[3]
31+
>a6 : Symbol(a6, Decl(tupleLengthCheck.ts, 9, 5))
32+
>rest : Symbol(rest, Decl(tupleLengthCheck.ts, 1, 13))
33+
34+
const a7 = rest[1000]
35+
>a7 : Symbol(a7, Decl(tupleLengthCheck.ts, 10, 5))
36+
>rest : Symbol(rest, Decl(tupleLengthCheck.ts, 1, 13))
37+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/conformance/types/tuple/tupleLengthCheck.ts ===
2+
declare const a: [number, string]
3+
>a : [number, string]
4+
5+
declare const rest: [number, string, ...boolean[]]
6+
>rest : [number, string, ...boolean[]]
7+
8+
const a1 = a[1]
9+
>a1 : string
10+
>a[1] : string
11+
>a : [number, string]
12+
>1 : 1
13+
14+
const a2 = a[2]
15+
>a2 : string | number
16+
>a[2] : string | number
17+
>a : [number, string]
18+
>2 : 2
19+
20+
const a3 = a[1000]
21+
>a3 : string | number
22+
>a[1000] : string | number
23+
>a : [number, string]
24+
>1000 : 1000
25+
26+
const a4 = rest[1]
27+
>a4 : string
28+
>rest[1] : string
29+
>rest : [number, string, ...boolean[]]
30+
>1 : 1
31+
32+
const a5 = rest[2]
33+
>a5 : boolean
34+
>rest[2] : boolean
35+
>rest : [number, string, ...boolean[]]
36+
>2 : 2
37+
38+
const a6 = rest[3]
39+
>a6 : boolean
40+
>rest[3] : boolean
41+
>rest : [number, string, ...boolean[]]
42+
>3 : 3
43+
44+
const a7 = rest[1000]
45+
>a7 : boolean
46+
>rest[1000] : boolean
47+
>rest : [number, string, ...boolean[]]
48+
>1000 : 1000
49+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
declare const a: [number, string]
2+
declare const rest: [number, string, ...boolean[]]
3+
4+
const a1 = a[1]
5+
const a2 = a[2]
6+
const a3 = a[1000]
7+
8+
const a4 = rest[1]
9+
const a5 = rest[2]
10+
const a6 = rest[3]
11+
const a7 = rest[1000]

0 commit comments

Comments
 (0)