The inferred types of array literals are unsound
- Dominant language
- Rust
- Stars
- 22.3k
- Forks
- 1.9k
- PR merge metrics
- No merged PRs in 30d
Description
[As seen here](https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoAxnAdgZwC5gCGATsWALxgDaA5AIw0A0YADALoDcqJxAdDnGJ4AFAEoumXAQAeALjD5iASywBzCkVJV2HMMGBgArrjjGAJqiA), this program involving a mutated array typechecks, which is unsound:
```js
/* @flow */
const arr = ['1', 0];
arr.sort();
const x: string = arr[0]; // unsound!
```
As far as I can tell, Flow treats the inferred type of `arr` sort of like a tuple, so `arr[0]` has type `string` and `arr[1]` has type `number`. However, it also *doesn’t* treat it like a tuple, since it allows `.sort()` and similar mutating methods to be applied to the value.
This only gets worse when I try to deduce what kind of mysterious type Flow is inferring for `arr`. If I use `flow type-at-pos` on the binding site (or any of the use sites), it claims it has inferred the type `Array`, but if I add that type as a type annotation, the program (correctly) fails to typecheck, [as seen here](https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoAxnAdgZwC5gCGATsQFxgCCphAngDz7ECWWA5mAD5hYCuAtgCMApsQB8YALxgA2gHIAjHIA0YAAwBdANyoSxAHQ44xPAAoAlDsy4CADwpNWHaXpmadQA):
```js
/* @flow */
const arr: Array = ['1', 0];
arr.sort();
const x: string = arr[0];
```
```
4: const x: string = arr[0];
^ Cannot assign `arr[0]` to `x` because number [1] is incompatible with string [2].
References:
2: const arr: Array = ['1', 0];
^ [1]
4: const x: string = arr[0];
^ [2]
```
I thought that perhaps this was a regression of #925, which caused tuple types to print as array types. However, that can’t be true, either, since this program *also* (correctly) fails to typecheck, since `.sort()` is (rightfully) illegal on tuples, [as seen here](https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoAxnAdgZwC5gCGATsQFxgDa+xAllgOYA0YWArgLYBGApsQLpgAvFQDkARlEsADPwDcqEsQB0OOMTwAKAJQLMuAgA8KNeg2FFSlWQqA):
```js
/* @flow */
const arr: [string, number] = ['1', 0];
arr.sort();
const x: string = arr[0];
```
```
3: arr.sort();
^ Cannot call `arr.sort` because property `sort` is missing in `$ReadOnlyArray` [1].
References:
2: const arr: [string, number] = ['1', 0];
^ [1]
```
Maybe the typechecker is tracking some refinements on individual array elements in a way I do not understand, which would not be reflected in the type reported by `type-at-pos`, but even if this is true, then it is still a bug, since `.sort()` should invalidate those refinements.
Contributor guide
Assessment
This issue has not been assessed yet.