facebook / facebook/flow

The inferred types of array literals are unsound

Open
#7,222 4 comments 9 reactions 0 assignees View on GitHub
bug Typing: soundness Typing: tuple
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.