Skip to content

Commit

Permalink
[flow][lib] restrict typing of Array.concat
Browse files Browse the repository at this point in the history
Summary:
Before, given the declaration
```
declare class $ReadOnlyArray<+T> {
  ...
  concat<S, Item: $ReadOnlyArray<S> | S>(...items: Array<Item>): Array<T | S>;
  ...
}
```
the following forms were errors
```
declare const arr: Array<number>;
arr.concat();
arr.concat() as Array<number>;
```
* The first due to under-constrained `S`
* The second due to inferring a bad bound (`mixed`) which is incompatible with `number`

This change makes `.concat` behave better when called without arguments.

Changelog: [fix] improved definition of `Array.concat()`.

Reviewed By: gkz

Differential Revision: D67421211

fbshipit-source-id: b48516259e80e94134f07320504e0e4dffd35d79
  • Loading branch information
panagosg7 authored and facebook-github-bot committed Dec 19, 2024
1 parent 14a12b2 commit 3aa18b0
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 30 deletions.
2 changes: 1 addition & 1 deletion lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ declare class $ReadOnlyArray<+T> {
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
*/
concat<S, Item: $ReadOnlyArray<S> | S>(...items: Array<Item>): Array<T | S>;
concat<S = T>(...items: Array<$ReadOnlyArray<S> | S>): Array<T | S>;
/**
* Returns an iterable of key, value pairs for every entry in the array
*/
Expand Down
3 changes: 3 additions & 0 deletions tests/arraylib/array_lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var k: Array<number> = h.concat(h);
var l: Array<number> = h.concat(1, 2, 3);
var m: Array<number | string> = h.concat('a', 'b', 'c');
var n: Array<number> = h.concat('a', 'b', 'c'); // Error
var o = h.concat();
o as Array<number>; // OK
var p: Array<number> = h.concat(); // OK

function reduce_test() {
/* Adapted from the following source:
Expand Down
50 changes: 25 additions & 25 deletions tests/arraylib/arraylib.exp
Original file line number Diff line number Diff line change
Expand Up @@ -95,83 +95,83 @@ References:
^^^^^^ [2]


Error ----------------------------------------------------------------------------------------------- array_lib.js:55:29
Error ----------------------------------------------------------------------------------------------- array_lib.js:58:29

Cannot use operator `*` with operands string [1] and number [2] [unsafe-arithmetic]

array_lib.js:55:29
55| [''].reduce((acc, str) => acc * str.length); // error, string ~> number
array_lib.js:58:29
58| [''].reduce((acc, str) => acc * str.length); // error, string ~> number
^^^^^^^^^^^^^^^^

References:
array_lib.js:55:4
55| [''].reduce((acc, str) => acc * str.length); // error, string ~> number
array_lib.js:58:4
58| [''].reduce((acc, str) => acc * str.length); // error, string ~> number
^^ [1]
<BUILTINS>/core.js:1365:13
1365| length: number;
^^^^^^ [2]


Error ----------------------------------------------------------------------------------------------- array_lib.js:56:34
Error ----------------------------------------------------------------------------------------------- array_lib.js:59:34

Cannot use operator `*` with operands string [1] and number [2] [unsafe-arithmetic]

array_lib.js:56:34
56| [''].reduceRight((acc, str) => acc * str.length); // error, string ~> number
array_lib.js:59:34
59| [''].reduceRight((acc, str) => acc * str.length); // error, string ~> number
^^^^^^^^^^^^^^^^

References:
array_lib.js:56:4
56| [''].reduceRight((acc, str) => acc * str.length); // error, string ~> number
array_lib.js:59:4
59| [''].reduceRight((acc, str) => acc * str.length); // error, string ~> number
^^ [1]
<BUILTINS>/core.js:1365:13
1365| length: number;
^^^^^^ [2]


Error ------------------------------------------------------------------------------------------------ array_lib.js:68:3
Error ------------------------------------------------------------------------------------------------ array_lib.js:71:3

Cannot cast `Array.from(...)` to array type because string [1] is incompatible with empty [2] in array element.
[incompatible-cast]

array_lib.js:68:3
68| Array.from('abcd') as Array<empty>; // ERROR
array_lib.js:71:3
71| Array.from('abcd') as Array<empty>; // ERROR
^^^^^^^^^^^^^^^^^^

References:
<BUILTINS>/core.js:1139:37
1139| static from(str: string): Array<string>;
^^^^^^ [1]
array_lib.js:68:31
68| Array.from('abcd') as Array<empty>; // ERROR
array_lib.js:71:31
71| Array.from('abcd') as Array<empty>; // ERROR
^^^^^ [2]


Error ----------------------------------------------------------------------------------------------- array_lib.js:83:57
Error ----------------------------------------------------------------------------------------------- array_lib.js:86:57

Cannot call `Array.of` because number [1] is incompatible with string [2] in array element. [incompatible-call]

array_lib.js:83:57
83| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
array_lib.js:86:57
86| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
^ [1]

References:
array_lib.js:83:38
83| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
array_lib.js:86:38
86| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
^^^^^^ [2]


Error ----------------------------------------------------------------------------------------------- array_lib.js:83:60
Error ----------------------------------------------------------------------------------------------- array_lib.js:86:60

Cannot call `Array.of` because number [1] is incompatible with string [2] in array element. [incompatible-call]

array_lib.js:83:60
83| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
array_lib.js:86:60
86| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
^ [1]

References:
array_lib.js:83:38
83| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
array_lib.js:86:38
86| var incompatibleTypeNotOkay: Array<string> = Array.of(1, 2);
^^^^^^ [2]


Expand Down
4 changes: 2 additions & 2 deletions tests/autocomplete_from_h_to_l/autocomplete_from_h_to_l.exp
Original file line number Diff line number Diff line change
Expand Up @@ -2345,7 +2345,7 @@ Flags: --pretty
{"name":"?.at","type":"void | ((index: number) => T | void)"},
{
"name":"?.concat",
"type":"void | (<S, Item: $ReadOnlyArray<S> | S>(...items: Array<Item>) => Array<T | S>)"
"type":"void | (<S = T>(...items: Array<$ReadOnlyArray<S> | S>) => Array<T | S>)"
},
{
"name":"?.copyWithin",
Expand Down Expand Up @@ -2457,7 +2457,7 @@ Flags: --pretty
{"name":"at","type":"(index: number) => T | void"},
{
"name":"concat",
"type":"<S, Item: $ReadOnlyArray<S> | S>(...items: Array<Item>) => Array<T | S>"
"type":"<S = T>(...items: Array<$ReadOnlyArray<S> | S>) => Array<T | S>"
},
{
"name":"copyWithin",
Expand Down
4 changes: 2 additions & 2 deletions tests/rec/rec.exp
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,8 @@ defined. [method-unbinding]

References:
<BUILTINS>/core.js:716:5
716| concat<S, Item: $ReadOnlyArray<S> | S>(...items: Array<Item>): Array<T | S>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2]
716| concat<S = T>(...items: Array<$ReadOnlyArray<S> | S>): Array<T | S>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2]


Error ----------------------------------------------------------------------------------------------- this_subst.js:1:53
Expand Down

0 comments on commit 3aa18b0

Please sign in to comment.