Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Stricter enforcement of arity for unpacked arguments
Summary: This diff adds a typechecker option to be stricter with argument unpacking. Consider the following function: ``` function max<T as num>( T $first, T $second, T ...$rest, ): T; ``` The typechecker currently allows us to call the function like this: ``` $max = max(...$my_numbers); ``` If that particular Container has no elements, this will be a runtime exception. This diff requires that, when the option is set, that users pass in at least two arguments, and unpack the rest, or use a function that supports Containers: ``` $max = max($first, $second, ...$my_numbers); // OR: $max = max2($my_numbers); ``` Note that, in case of a tuple, we will allow the arguments to be unpacked because we can guarantee the arity: ``` $my_numbers = tuple(1, 2); $max = max(...$my_numbers); // OK ``` Reviewed By: jamesjwu Differential Revision: D6926957 fbshipit-source-id: 27942e0420d4e5d31c22493e72ea45689c6bd666
- Loading branch information
Showing
with
217 additions
and 29 deletions.
- +15 −0 hphp/hack/src/options/globalOptions.ml
- +1 −0 hphp/hack/src/options/globalOptions.mli
- +2 −0 hphp/hack/src/options/typecheckerOptions.ml
- +11 −6 hphp/hack/src/typing/typing.ml
- +44 −1 hphp/hack/test/typecheck/argument_unpacking/unpack_call1.php.exp
- +20 −13 hphp/hack/test/typecheck/argument_unpacking/unpack_call11.php
- +38 −8 hphp/hack/test/typecheck/argument_unpacking/unpack_call11.php.exp
- +42 −0 hphp/hack/test/typecheck/argument_unpacking/unpack_call13_arity.php
- +32 −0 hphp/hack/test/typecheck/argument_unpacking/unpack_call13_arity.php.exp
- 0 hphp/hack/test/typecheck/argument_unpacking/unpack_call13_arity.php.no_format
- +4 −0 hphp/hack/test/typecheck/argument_unpacking/unpack_call3.php.exp
- +4 −0 hphp/hack/test/typecheck/argument_unpacking/unpack_call6.php.exp
- +4 −1 hphp/hack/test/typecheck/construct/parent_construct1.php.exp
@@ -1 +1,44 @@ | ||
No errors | ||
File "unpack_call1.php", line 38, characters 3-13: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 39, characters 11-26: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 8, characters 19-29: | ||
Definition is here | ||
File "unpack_call1.php", line 40, characters 3-20: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 12, characters 19-19: | ||
Definition is here | ||
File "unpack_call1.php", line 41, characters 11-26: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 16, characters 19-29: | ||
Definition is here | ||
File "unpack_call1.php", line 42, characters 3-20: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 12, characters 19-19: | ||
Definition is here | ||
File "unpack_call1.php", line 51, characters 3-23: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 53, characters 3-15: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 69, characters 3-13: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 75, characters 3-13: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 85, characters 3-26: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here | ||
File "unpack_call1.php", line 87, characters 3-15: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call1.php", line 3, characters 10-10: | ||
Definition is here |
@@ -1,16 +1,46 @@ | ||
File "unpack_call11.php", line 30, characters 3-36: | ||
Too many arguments (Typing[4105]) | ||
File "unpack_call11.php", line 40, characters 10-18: | ||
Definition is here | ||
File "unpack_call11.php", line 31, characters 26-27: | ||
File "unpack_call11.php", line 32, characters 16-18: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 48, characters 26-26: | ||
This is an object of type B | ||
File "unpack_call11.php", line 17, characters 24-30: | ||
It is incompatible with an object of type A | ||
File "unpack_call11.php", line 33, characters 26-27: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 49, characters 32-33: | ||
This is an object of type B (variadic argument) | ||
File "unpack_call11.php", line 15, characters 21-27: | ||
It is incompatible with an object of type E | ||
File "unpack_call11.php", line 34, characters 35-36: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 49, characters 32-33: | ||
This is an object of type B (variadic argument) | ||
File "unpack_call11.php", line 15, characters 21-27: | ||
It is incompatible with an object of type E | ||
File "unpack_call11.php", line 35, characters 26-27: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 44, characters 33-33: | ||
File "unpack_call11.php", line 51, characters 33-33: | ||
This is an object of type E | ||
File "unpack_call11.php", line 15, characters 12-18: | ||
It is incompatible with an object of type B | ||
File "unpack_call11.php", line 31, characters 26-27: | ||
File "unpack_call11.php", line 35, characters 26-27: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 44, characters 27-27: | ||
File "unpack_call11.php", line 51, characters 27-27: | ||
This is an object of type B | ||
File "unpack_call11.php", line 15, characters 21-27: | ||
It is incompatible with an object of type E | ||
File "unpack_call11.php", line 35, characters 3-28: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call11.php", line 51, characters 10-19: | ||
Definition is here | ||
File "unpack_call11.php", line 36, characters 26-28: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 52, characters 27-27: | ||
This is an object of type C | ||
File "unpack_call11.php", line 20, characters 15-21: | ||
It is incompatible with an object of type B | ||
File "unpack_call11.php", line 44, characters 26-27: | ||
Invalid argument (Typing[4110]) | ||
File "unpack_call11.php", line 49, characters 32-33: | ||
This is an object of type B (variadic argument) | ||
File "unpack_call11.php", line 39, characters 24-24: | ||
It is incompatible with an object of type E |
@@ -0,0 +1,42 @@ | ||
<?hh // strict | ||
|
||
function test_splat_arity(): void { | ||
$tuple2 = tuple(1, 2); | ||
|
||
// OK | ||
expect_const2(...$tuple2); | ||
expect_const3(0, ...$tuple2); | ||
expect_variadic0(...$tuple2); | ||
expect_variadic1(...$tuple2); | ||
expect_variadic2(...$tuple2); | ||
|
||
// Errors | ||
expect_const1(...$tuple2); | ||
expect_const2(0, ...$tuple2); | ||
expect_variadic3(...$tuple2); | ||
|
||
$vec2 = vec[1, 2]; | ||
|
||
// OK | ||
expect_variadic0(...$vec2); | ||
expect_variadic1(0, ...$vec2); | ||
expect_variadic2(0, 1, ...$vec2); | ||
expect_variadic3(0, 1, 2, ...$vec2); | ||
|
||
// Errors | ||
expect_const1(...$vec2); | ||
expect_const1(0, ...$vec2); | ||
expect_const2(...$vec2); | ||
expect_const2(0, ...$vec2); | ||
expect_const2(0, 1, ...$vec2); | ||
} | ||
|
||
type M = mixed; | ||
|
||
function expect_const1(M $a): void {} | ||
function expect_const2(M $a, M $b): void {} | ||
function expect_const3(M $a, M $b, M $c): void {} | ||
function expect_variadic0(M ...$as): void {} | ||
function expect_variadic1(M $a, M ...$bs): void {} | ||
function expect_variadic2(M $a, M $b, M ...$cs): void {} | ||
function expect_variadic3(M $a, M $b, M $c, M...$ds): void {} |
@@ -0,0 +1,32 @@ | ||
File "unpack_call13_arity.php", line 14, characters 3-27: | ||
Too many arguments (Typing[4105]) | ||
File "unpack_call13_arity.php", line 36, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 15, characters 3-30: | ||
Too many arguments (Typing[4105]) | ||
File "unpack_call13_arity.php", line 37, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 16, characters 3-30: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call13_arity.php", line 42, characters 10-25: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 27, characters 3-25: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call13_arity.php", line 36, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 28, characters 3-28: | ||
Too many arguments (Typing[4105]) | ||
File "unpack_call13_arity.php", line 36, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 29, characters 3-25: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call13_arity.php", line 37, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 30, characters 3-28: | ||
Too few arguments (Typing[4104]) | ||
File "unpack_call13_arity.php", line 37, characters 10-22: | ||
Definition is here | ||
File "unpack_call13_arity.php", line 31, characters 3-31: | ||
Too many arguments (Typing[4105]) | ||
File "unpack_call13_arity.php", line 37, characters 10-22: | ||
Definition is here |
Empty file.
@@ -1 +1,4 @@ | ||
No errors | ||
File "parent_construct1.php", line 36, characters 9-37: | ||
Too few arguments (Typing[4104]) | ||
File "parent_construct1.php", line 15, characters 19-29: | ||
Definition is here |