Add hh_expect and hh_expect_equivalent pseudo function for testing
commit140ffb5c7ab7637547ee3b0278fdea6416fe7f83
authorScott Owens <sowens@fb.com>
Wed, 10 Nov 2021 13:56:57 +0000 (10 05:56 -0800)
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>
Wed, 10 Nov 2021 13:58:31 +0000 (10 05:58 -0800)
tree014f8086a08a4bb086027b54044963d9729164f1
parent5f9346ed2438ea99c5040292015059ae3f14a97f
Add hh_expect and hh_expect_equivalent pseudo function for testing

Summary:
Calling `hh_expect<t>(e)` checks that the type of `e` is a sub-type of `t`. This is intended for use in tests of the type checker. It is a more streamlined version of defining function `function expect_int(int $i) : void` or having to define a more generic `function expect<T>(T $x) : void`.

Calling `hh_expect_equivalent<t>(e)` checks that the type of `e` is both a sub-type and super-type of `t`, i.e., that they are equivalent up-to subtyping. This is intended for use in tests of the type checker where you need to check that the type is exactly something. It is more self-contained than using `hh_show` and checking that the printed output is the desired type, and more readable than the equivalent idiom that doesn't rely on special syntax:
```
function expect<T>(T $x):void { }
...
  $w = Vector { e };
  expect<Vector<C>>($w);
}
```

This will support testing primitive operations, for example `[]` on `vec`. I need to check that `vec<t>[e]` is exactly `t`. It is a type checker bug if it starts returning a subtype of `t` (soundness) or supertype (completeness).

There is some flexibility in the design. Here we are just using sub-typing to make the given type both an upper and lower bound of the expression's type. That means that is the expression has an unsolved type variable in its type, the `hh_expect_equivalent` could succeed because the type variable _can_ be instantiated to satisfy the expected type, not that it _must_ be instantiated that way. For example,
```
  $v = Vector {};
  hh_expect_equivalent<Vector<int>>($v);
```

Even for fully resolved types, `hh_expect_equivalent` can differ from using `hh_show` to test. For example, if we were testing type union operations, we might want to check for the exact type syntactically, and not up-to-sub-typing equivalence:
```
if (...) {
  $x = 1;
} else {
  $x = "1";
}
hh_expect_equivalent<arraykey>($x);
```
With the current implementation of `hh_expect_equivalent` this will pass even if internally union failed to simplify the type of `$x` (what we'd like to be testing for), and so `$x : string | int`.

Reviewed By: madgen

Differential Revision: D32178417

fbshipit-source-id: b23cc645cf976a4e20d48baabd7164d63e3d6e01
16 files changed:
hphp/hack/src/errors/error_codes.ml
hphp/hack/src/errors/errors.ml
hphp/hack/src/errors/errors.mli
hphp/hack/src/hh_single_ai.ml
hphp/hack/src/hh_single_complete.ml
hphp/hack/src/hh_single_type_check.ml
hphp/hack/src/naming/naming_special_names.ml
hphp/hack/src/naming/naming_special_names.rs
hphp/hack/src/oxidized/gen/error_codes.rs
hphp/hack/src/parser/lowerer/desugar_expression_tree.rs
hphp/hack/src/typing/typing.ml
hphp/hack/test/enum_class_label/typing/closure.php.exp
hphp/hack/test/typecheck/hh_expect.php [new file with mode: 0644]
hphp/hack/test/typecheck/hh_expect.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/hh_expect_tyvar.php [new file with mode: 0644]
hphp/hack/test/typecheck/hh_expect_tyvar.php.exp [new file with mode: 0644]