HHVM 3.29
HHVM 3.29 is released! This release has a large amount of changes in the typechecker; these mostly are now raising type errors for situations that already failed at runtime, or banning rare cases that make the type system unsound.
Breaking Changes
- [typechecker] correct inferred types for variables assigned in loops
- [typechecker] ban using traits in interfaces (previously failed at runtime, but typechecked fine)
- [typechecker] ban generic static properties, as the generic is unresolved until the class is instantiated
- [typechecker] keywords are case sensitive again (e.g.
new
is valid,NEW
is not) - [typechecker] ban using various keywords as identifiers, e.g.
class true {}
is not valid - [typechecker] improved typing of array append - e.g.
$x = vec[]; $x[] = 'a string';
now gets you avec<string>
- [typechecker] ban instance methods on abstract final classes
- [typechecker] the
Throwable
class is now sealed to theException
andError
classes - [typechecker] ban
await
in pseudomains - [typechecker] ban constructor parameter promotion in traits and interfaces
- [typechecker] re-ban anonymous classes; was un-banned by parser replacement
- [typechecker] ban the empty string as a shape key
- [typechecker] make sure that properties are consistently static or non-static across the hierarchy. Previously a runtime error.
- [typechecker] ban taking references to array literals. Previously a runtime error.
- [typechecker] ban taking references to expressions including
?->
operator. Previously a runtime error. - [typechecker] ban
::class
on the RHS ofinstanceof
expressions; uneeded. - [typechecker] require visibility specifiers for properties again; was un-banned by parser replacement
- [typechecker] ban
await
in non-async lambdas. Previously a runtime error. - [typechecker] ban truthiness checks on objects that are not
Container
s orSimpleXMLElement
s - [typechecker] ban impossible types (e.g.
abstract final
classes) as shape field types - [typechecker] fix typechecking of
case
statements that are after adefault
statement - [typechecker] ban the
(object)
cast (convert tostdClass
) in strict mode - [typechecker+HackC] ban the
<>
operator in Hack -the equivalent!=
operator is still available- migration included in HHAST:hhast-migrate --ltgt-to-ne
- [typechecker] ban methods without a name. Previously a runtime error.
- [typechecker] infer better types for
Shapes::toDict()
, in the same way asShapes::toArray()
- for example, if all the fields are strings, you can get adict<string, string>
- [runtime] removed support for
/e
modifier (eval) forpreg_replace()
. Deprecated in PHP 5.5, removed from 7.0. Usepreg_replace_callback()
instead. - [runtime]
stream_await()
will throw anInvalidOperationException
if called on an unawaitable file descriptor. This includes actual on-disk files on Linux, as they are not supported by epoll. We recommend that callers attempt tostream_await()
, and handle this exception if neccessary. The stream metadata can not be used to identify whether or not a stream is awaitable - for example,hhvm foo.php
has an awaitableSTDIN
, buthhvm foo.php < myfile
has an awaitableSTDIN
on MacOS (kqueue) but not on Linux (epoll). In prior releases, behavior varied; the most common result was writing an error toSTDOUT
, and the awaitable not resolving, with request timeout eventually being reached. - [hackc] ban variable variables (
$$foo
) in Hack code (previously required by the typechecker) - [hackc] colons are now required again after ‘case’ and ‘default’ labels (previously required by the typechecker)
Features
- [hackfmt] added support for
// hackfmt-ignore
comments, to turn off formatting for a node - [typechecker] null checks on
Shapes::idx()
results now refine the type of the shape - add support for typed user attributes
Typed User Attributes
Currently, <<Attributes>>
are unchecked, except if they start with __
(indicating a builtin), and can contain any amount of static expressions of any type; it was possible to whitelist valid attribute names via user_attributes=foo,bar
, but not to provide any additional checking.
We have addressed these problems by introducing typed user attributes, where attributes are represented by classes and objects; the parameters of an attribute must be valid for the class constructor, and the objects can be retrived via reflection.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?hh // strict
namespace MyTestFramework {
final class DataProvider implements \HH\MethodAttribute {
public function __construct(public string $function) {
}
}
}
namespace MyThingBeingTested {
use type MyTestFramework\DataProvider;
final class MyTest extends MyTestFramework\TestCase {
<<DataProvider('provideFoo')>>
public function testFoo(): void {
}
<<DataProvider(123)>> // type error, not a string
public function testBar(): void {
}
<<DataProvider('foo', 'bar')>> // type error, too many arguments
public function testBaz(): void {
}
}
<<DataProvider('foo')>> // type error, can't use DataProvider on functions, only methods
function doStuff(): void {
}
}
Attributes can be retrieved via reflection:
1
2
3
4
<?hh
$rc = new ReflectionClass('C');
$my_attr = $rc->getAttributeClass(MyAttribute::class);
invariant($my_attr is MyAttribute, 'we get an instance of the class');
Attribute classes implement at least one of these interfaces:
ClassAttribute
EnumAttribute
TypeAliasAttribute
FunctionAttribute
MethodAttribute
InstancePropertyAttribute
StaticPropertyAttribute
ParameterAttribute
In 3.29, it is possible to declare attributes with this form, and if done, they were validated. In 3.30, declaring all attributes will be required, and it is possible to require this in 3.29 by setting an empty whitelist in .hhconfig
:
1
user_attributes=
Other Highlights
- [typechecker] correct handling of
is
expressions in pipe expressions - [typechecker] fix handling of
as
expressions inlist
assignments, e.g.list($a, $b) = $mixed as (int, int);
- [typechecker+HackC] support unambiguous
as
expressions inforeach
, e.g.foreach(f($x as nonnull) as $y)
- [runtime] async curl functions are now natively async again
- [runtime] handle EINTR (e.g. Xenon) while invoking HackC
- [runtime]
<<__LateInit>>
now works correctly for private properties on abstract classes
Upcoming Changes
- [typechecker] remove support for type refinement via
is_bool()
,is_int()
etc. This is currently opt-in via thedisable_primitive_refinement
.hhconfig
option - typed user attributes will be required. This is currently opt-in via the
user_attributes=
.hhconfig
option