Skip to content

Commit 8b0a654

Browse files
Andrew Kennedymeta-codesync[bot]
authored andcommitted
Better typing for bitwise operations
Summary: Bitwise operations (`&`, `|` and `^`) are currently typed incorrectly in two ways: (1) When applied to arguments both of type `~int`, we produce `int`. This is wrong, because HHVM still accepts strings, so the `~` might hide a string type. (2) In the dynamic pass, we produce `dynamic` regardless of the argument types, because of a call to `Typing_utils.is_dynamic` that is interpreted as dynamic-aware subtyping in the dynamic pass. Instead, we now use a different approach of reusing the logic from SDT function calls, as though the bitwise op is a call to <<__SupportDynamicType>> function bitwise(int $x, int $y):int If interpreted strictly, this would produce `~int` if *either* of the operands is `~int` or `dynamic`. We can do slightly better, as we know that the operation will throw if one operand is `int` but the other is `string`. So a like is added only if *both* operands are `~int` or `dynamic`. Reviewed By: mheiber Differential Revision: D83841630 fbshipit-source-id: 57a12acbcf82d25eba632ee4ee50798b0071afa8
1 parent 807c5ae commit 8b0a654

File tree

8 files changed

+49
-40
lines changed

8 files changed

+49
-40
lines changed

hphp/hack/src/typing/typing_arithmetic.ml

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ let check_dynamic_or_enforce_int env p t r err =
4848
in
4949
Option.iter ty_err_opt ~f:(Typing_error_utils.add_typing_error ~env);
5050
let ty_mismatch = Option.map ty_err_opt ~f:Fn.(const (t, ty)) in
51-
(env, Typing_utils.is_dynamic env t, ty_mismatch)
51+
(env, Typing_defs.is_dynamic t, ty_mismatch)
5252

5353
(** [check_like_num p_exp p env ty] ensures that [ty] is a subtype of num or ~num.
5454
In the former case, it returns false and the type, in the latter, it returns
@@ -364,29 +364,38 @@ let binop p env bop p1 te1 ty1 p2 te2 ty2 =
364364
| Ast_defs.Amp
365365
| Ast_defs.Bar
366366
when not contains_any ->
367-
let (env, is_dynamic1, err_opt1) =
368-
check_dynamic_or_enforce_int
367+
(* Type-check a bitwise operation as if it's a call to a function of type
368+
* <<__SupportDynamicType>> function bitwise_math(int $x, int $y): int
369+
* With one samll improvement: if checking of *either* argument succeeds against int
370+
* rather than ~int, then return int, because we know that it will simply throw if
371+
* the other argument is not int at runtime.
372+
*)
373+
let (env, err_opt1, used_dynamic1) =
374+
Typing_argument.check_argument_type_against_parameter_type
375+
~ignore_readonly:false
376+
~dynamic_func:(Some Typing_argument.Supportdyn_function)
369377
env
370-
p
378+
(Typing_make_type.int (Reason.bitwise p1))
379+
p1
371380
ty1
372-
(Reason.bitwise p1)
373-
Typing_error.Callback.bitwise_math_invalid_argument
374381
in
375-
let (env, is_dynamic2, err_opt2) =
376-
check_dynamic_or_enforce_int
382+
let (env, err_opt2, used_dynamic2) =
383+
Typing_argument.check_argument_type_against_parameter_type
384+
~ignore_readonly:false
385+
~dynamic_func:(Some Typing_argument.Supportdyn_function)
377386
env
378-
p
387+
(Typing_make_type.int (Reason.bitwise p2))
388+
p2
379389
ty2
380-
(Reason.bitwise p2)
381-
Typing_error.Callback.bitwise_math_invalid_argument
382390
in
383-
let result_ty =
384-
if is_dynamic1 && is_dynamic2 then
385-
MakeType.dynamic (Reason.bitwise_dynamic p)
386-
else
387-
MakeType.int (Reason.bitwise_ret p)
388-
in
389-
make_result env te1 err_opt1 te2 err_opt2 result_ty
391+
make_result
392+
~is_like:(used_dynamic1 && used_dynamic2)
393+
env
394+
te1
395+
err_opt1
396+
te2
397+
err_opt2
398+
(MakeType.int (Reason.bitwise_ret p))
390399
| Ast_defs.Eqeq
391400
| Ast_defs.Diff ->
392401
begin
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?hh
22

33
function compound_assign_bitwise_and(Vector<int> $xs) : void {
4-
/* HH_FIXME[4423] */
4+
/* HH_FIXME[4110] */
55
$xs[0] &= 1.0;
66
}

hphp/hack/test/typecheck/dynamic/bad_math.php.exp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,20 @@ Typing error (Typing[4423])
8282
Expected `int` because this is used in an arithmetic operation
8383
File "bad_math.php", line 5, characters 33-33:
8484
But got `C`
85-
ERROR: File "bad_math.php", line 18, characters 3-8:
86-
Typing error (Typing[4423])
85+
ERROR: File "bad_math.php", line 18, characters 3-4:
86+
Invalid argument (Typing[4110])
8787
File "bad_math.php", line 18, characters 3-4:
8888
Expected `int` because this is used in a bitwise operation
8989
File "bad_math.php", line 5, characters 33-33:
9090
But got `C`
91-
ERROR: File "bad_math.php", line 19, characters 3-8:
92-
Typing error (Typing[4423])
91+
ERROR: File "bad_math.php", line 19, characters 3-4:
92+
Invalid argument (Typing[4110])
9393
File "bad_math.php", line 19, characters 3-4:
9494
Expected `int` because this is used in a bitwise operation
9595
File "bad_math.php", line 5, characters 33-33:
9696
But got `C`
97-
ERROR: File "bad_math.php", line 20, characters 3-8:
98-
Typing error (Typing[4423])
97+
ERROR: File "bad_math.php", line 20, characters 3-4:
98+
Invalid argument (Typing[4110])
9999
File "bad_math.php", line 20, characters 3-4:
100100
Expected `int` because this is used in a bitwise operation
101101
File "bad_math.php", line 5, characters 33-33:

hphp/hack/test/typecheck/dynamic/bitwise.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?hh
22

33
function testBitwise(dynamic $x): void {
4-
$y = $x & 5; // $y : num
4+
$y = $x & 5; // $y : int
55
hh_show($y);
6-
$y = $x | 5; // $y : num
6+
$y = $x | 5; // $y : int
77
hh_show($y);
8-
$y = $x ^ 5; // $y : num
8+
$y = $x ^ 5; // $y : int
99
hh_show($y);
10-
$y = $x >> 5; // $y : num
10+
$y = $x >> 5; // $y : int
1111
hh_show($y);
12-
$y = $x << 5; // $y : num
12+
$y = $x << 5; // $y : int
1313
hh_show($y);
14-
$y = $x ^ $x; // $y : dynamic
14+
$y = $x ^ $x; // $y : ~int
1515
hh_show($y);
1616
$y = ~$x; // $y : dynamic
1717
hh_show($y);

hphp/hack/test/typecheck/dynamic/bitwise.php.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ File "bitwise.php", line 11, characters 3-13:
99
File "bitwise.php", line 13, characters 3-13:
1010
int
1111
File "bitwise.php", line 15, characters 3-13:
12-
dynamic
12+
~int
1313
File "bitwise.php", line 17, characters 3-13:
1414
dynamic
1515
No errors

hphp/hack/test/typecheck/xor_bad1.php.exp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
ERROR: File "xor_bad1.php", line 13, characters 3-9:
2-
Typing error (Typing[4423])
1+
ERROR: File "xor_bad1.php", line 13, characters 8-9:
2+
Invalid argument (Typing[4110])
33
File "xor_bad1.php", line 13, characters 8-9:
44
Expected `int` because this is used in a bitwise operation
55
File "xor_bad1.php", line 12, characters 22-25:

hphp/hack/test/typecheck/xor_bad2.php.exp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
ERROR: File "xor_bad2.php", line 13, characters 3-9:
2-
Typing error (Typing[4423])
1+
ERROR: File "xor_bad2.php", line 13, characters 3-4:
2+
Invalid argument (Typing[4110])
33
File "xor_bad2.php", line 13, characters 3-4:
44
Expected `int` because this is used in a bitwise operation
55
File "xor_bad2.php", line 12, characters 14-17:

hphp/hack/test/typecheck/xor_bad3.php.exp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
ERROR: File "xor_bad3.php", line 13, characters 3-9:
2-
Typing error (Typing[4423])
1+
ERROR: File "xor_bad3.php", line 13, characters 3-4:
2+
Invalid argument (Typing[4110])
33
File "xor_bad3.php", line 13, characters 3-4:
44
Expected `int` because this is used in a bitwise operation
55
File "xor_bad3.php", line 12, characters 14-19:
66
But got `string`
7-
ERROR: File "xor_bad3.php", line 13, characters 3-9:
8-
Typing error (Typing[4423])
7+
ERROR: File "xor_bad3.php", line 13, characters 8-9:
8+
Invalid argument (Typing[4110])
99
File "xor_bad3.php", line 13, characters 8-9:
1010
Expected `int` because this is used in a bitwise operation
1111
File "xor_bad3.php", line 12, characters 25-30:

0 commit comments

Comments
 (0)