Skip to content

Commit

Permalink
Enforce like types in type hint positions
Browse files Browse the repository at this point in the history
Summary: As part of the spec for sound dynamic, we said we want `~T` to enforce as `T`, a departure from our original approach which had it enforce as mixed (but as D40516837 (9e8c173) shows, wasn't happening for reified generics). This way, changing a declaration from `int` to `~int` doesn't cause the code to lose enforcement. The "enforce as mixed" idea came to mind from trying to replace `mixed/dynamic` with like types, but we're introducing TANY_MARKER to deal with those.

Reviewed By: andrewjkennedy

Differential Revision: D40516838

fbshipit-source-id: ec2f0b16edb0398af541ece1f181dd9c4a3ad49b
  • Loading branch information
vassilmladenov authored and facebook-github-bot committed Oct 21, 2022
1 parent 201e947 commit ad1dbd1
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 18 deletions.
5 changes: 2 additions & 3 deletions hphp/hack/src/hackc/emitter/emit_type_hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,7 @@ fn hint_to_type_constraint<'arena>(
) -> Result<Constraint<'arena>> {
let Hint(_, hint) = h;
Ok(match &**hint {
Hdynamic | Hlike(_) | Hfun(_) | Hunion(_) | Hintersection(_) | Hmixed => {
Constraint::default()
}
Hdynamic | Hfun(_) | Hunion(_) | Hintersection(_) | Hmixed => Constraint::default(),
Haccess(_, _) => Constraint::make(
Just("".into()),
TypeConstraintFlags::ExtendedHint | TypeConstraintFlags::TypeConstant,
Expand All @@ -227,6 +225,7 @@ fn hint_to_type_constraint<'arena>(
t,
TypeConstraintFlags::Soft | TypeConstraintFlags::ExtendedHint,
)?,
Hlike(h) => hint_to_type_constraint(alloc, kind, tparams, skipawaitable, h)?,
Herr | Hany => {
return Err(Error::unrecoverable(
"This should be an error caught in naming",
Expand Down
2 changes: 1 addition & 1 deletion hphp/test/slow/like_types/awaitable1.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Error: async functions must return an Awaitable.
*/
async function f(mixed $x): ~Awaitable<int> {
async function f(mixed $x): <<__Soft>> ~Awaitable<int> {
return $x;
}

Expand Down
4 changes: 2 additions & 2 deletions hphp/test/slow/like_types/awaitable2.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?hh

/**
* Like-types are treated as mixed, allowing any return value.
* Like-types are enforced at their inner type, so this enforces as Awaitable<int>
*/
async function f(mixed $x): Awaitable<~int> {
async function f(mixed $x): Awaitable<<<__Soft>> ~int> {
return $x;
}

Expand Down
18 changes: 16 additions & 2 deletions hphp/test/slow/like_types/awaitable2.php.expectf
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
int(1)

Warning: Value returned from async function f() must be of type @int, float given in %s/test/slow/like_types/awaitable2.php on line 7
float(1.5)

Warning: Value returned from async function f() must be of type @int, string given in %s/test/slow/like_types/awaitable2.php on line 7
string(3) "foo"

Warning: Value returned from async function f() must be of type @int, bool given in %s/test/slow/like_types/awaitable2.php on line 7
bool(false)
resource(%d) of type (stream)

Warning: Value returned from async function f() must be of type @int, File given in %s/test/slow/like_types/awaitable2.php on line 7
resource(4) of type (stream)

Warning: Value returned from async function f() must be of type @int, stdClass given in %s/test/slow/like_types/awaitable2.php on line 7
object(stdClass) (0) {
}

Warning: Value returned from async function f() must be of type @int, HH\vec given in %s/test/slow/like_types/awaitable2.php on line 7
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Value returned from async function f() must be of type @int, HH\dict given in %s/test/slow/like_types/awaitable2.php on line 7
dict(2) {
["a"]=>
int(1)
["b"]=>
int(2)
}
}
5 changes: 2 additions & 3 deletions hphp/test/slow/like_types/awaitable3.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?hh

/**
* For non-async functions, a like-Awaitable acts like any other type; it's
* not enforced.
* For non-async functions, a like-Awaitable acts like any other like type, enforced at the inner type.
*/
function f(mixed $x): ~Awaitable<int> {
function f(mixed $x): <<__Soft>> ~Awaitable<int> {
return $x;
}

Expand Down
15 changes: 15 additions & 0 deletions hphp/test/slow/like_types/awaitable3.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
Warning: Value returned from function f() must be of type @HH\Awaitable, int given in %s/test/slow/like_types/awaitable3.php on line 7
int(1)

Warning: Value returned from function f() must be of type @HH\Awaitable, float given in %s/test/slow/like_types/awaitable3.php on line 7
float(1.5)

Warning: Value returned from function f() must be of type @HH\Awaitable, string given in %s/test/slow/like_types/awaitable3.php on line 7
string(3) "foo"

Warning: Value returned from function f() must be of type @HH\Awaitable, bool given in %s/test/slow/like_types/awaitable3.php on line 7
bool(false)

Warning: Value returned from function f() must be of type @HH\Awaitable, File given in %s/test/slow/like_types/awaitable3.php on line 7
resource(4) of type (stream)

Warning: Value returned from function f() must be of type @HH\Awaitable, stdClass given in %s/test/slow/like_types/awaitable3.php on line 7
object(stdClass) (0) {
}

Warning: Value returned from function f() must be of type @HH\Awaitable, HH\vec given in %s/test/slow/like_types/awaitable3.php on line 7
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Value returned from function f() must be of type @HH\Awaitable, HH\dict given in %s/test/slow/like_types/awaitable3.php on line 7
dict(2) {
["a"]=>
int(1)
Expand Down
4 changes: 2 additions & 2 deletions hphp/test/slow/like_types/parameter.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?hh

/**
* Like-types are treated as mixed, allowing any argument value.
* Like-types are enforced at their inner type.
*/
function f(~int $x): void {
function f(<<__Soft>> ~int $x): void {
var_dump($x);
}

Expand Down
14 changes: 14 additions & 0 deletions hphp/test/slow/like_types/parameter.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
int(1)

Warning: Argument 1 to f() must be of type @int, float given in %s/test/slow/like_types/parameter.php on line 13
float(1.5)

Warning: Argument 1 to f() must be of type @int, string given in %s/test/slow/like_types/parameter.php on line 14
string(3) "foo"

Warning: Argument 1 to f() must be of type @int, bool given in %s/test/slow/like_types/parameter.php on line 15
bool(false)

Warning: Argument 1 to f() must be of type @int, File given in %s/test/slow/like_types/parameter.php on line 16
resource(4) of type (stream)

Warning: Argument 1 to f() must be of type @int, stdClass given in %s/test/slow/like_types/parameter.php on line 17
object(stdClass) (0) {
}

Warning: Argument 1 to f() must be of type @int, HH\vec given in %s/test/slow/like_types/parameter.php on line 18
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Argument 1 to f() must be of type @int, HH\dict given in %s/test/slow/like_types/parameter.php on line 19
dict(2) {
["a"]=>
int(1)
Expand Down
4 changes: 2 additions & 2 deletions hphp/test/slow/like_types/parameter_alias.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?hh

/**
* Like-types are treated as mixed, allowing any argument value.
* Like-types are enforced at their inner type.
*/
function f(MyAlias $x): void {
function f(<<__Soft>> MyAlias $x): void {
var_dump($x);
}

Expand Down
14 changes: 14 additions & 0 deletions hphp/test/slow/like_types/parameter_alias.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
int(1)

Warning: Argument 1 to f() must be of type @MyAlias, float given in %s/test/slow/like_types/parameter_alias.php on line 15
float(1.5)

Warning: Argument 1 to f() must be of type @MyAlias, string given in %s/test/slow/like_types/parameter_alias.php on line 16
string(3) "foo"

Warning: Argument 1 to f() must be of type @MyAlias, bool given in %s/test/slow/like_types/parameter_alias.php on line 17
bool(false)

Warning: Argument 1 to f() must be of type @MyAlias, File given in %s/test/slow/like_types/parameter_alias.php on line 18
resource(4) of type (stream)

Warning: Argument 1 to f() must be of type @MyAlias, stdClass given in %s/test/slow/like_types/parameter_alias.php on line 19
object(stdClass) (0) {
}

Warning: Argument 1 to f() must be of type @MyAlias, HH\vec given in %s/test/slow/like_types/parameter_alias.php on line 20
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Argument 1 to f() must be of type @MyAlias, HH\dict given in %s/test/slow/like_types/parameter_alias.php on line 21
dict(2) {
["a"]=>
int(1)
Expand Down
2 changes: 1 addition & 1 deletion hphp/test/slow/like_types/property.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?hh

final class C {
private ~int $x = 1;
<<__Soft>> private ~int $x = 1;
public function setX(mixed $x): this {
// Like-types are treated as mixed, allowing any property value.
$this->x = $x;
Expand Down
14 changes: 14 additions & 0 deletions hphp/test/slow/like_types/property.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
int(1)

Warning: Property 'C::x' declared as type @int, float assigned in %s/test/slow/like_types/property.php on line 7
float(1.5)

Warning: Property 'C::x' declared as type @int, string assigned in %s/test/slow/like_types/property.php on line 7
string(3) "foo"

Warning: Property 'C::x' declared as type @int, bool assigned in %s/test/slow/like_types/property.php on line 7
bool(false)

Warning: Property 'C::x' declared as type @int, File assigned in %s/test/slow/like_types/property.php on line 7
resource(4) of type (stream)

Warning: Property 'C::x' declared as type @int, stdClass assigned in %s/test/slow/like_types/property.php on line 7
object(stdClass) (0) {
}

Warning: Property 'C::x' declared as type @int, HH\vec assigned in %s/test/slow/like_types/property.php on line 7
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Property 'C::x' declared as type @int, HH\dict assigned in %s/test/slow/like_types/property.php on line 7
dict(2) {
["a"]=>
int(1)
Expand Down
2 changes: 1 addition & 1 deletion hphp/test/slow/like_types/return.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?hh

function f(mixed $x): ~int {
function f(mixed $x): <<__Soft>> ~int {
return $x;
}

Expand Down
14 changes: 14 additions & 0 deletions hphp/test/slow/like_types/return.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
int(1)

Warning: Value returned from function f() must be of type @int, float given in %s/test/slow/like_types/return.php on line 4
float(1.5)

Warning: Value returned from function f() must be of type @int, string given in %s/test/slow/like_types/return.php on line 4
string(3) "foo"

Warning: Value returned from function f() must be of type @int, bool given in %s/test/slow/like_types/return.php on line 4
bool(false)

Warning: Value returned from function f() must be of type @int, File given in %s/test/slow/like_types/return.php on line 4
resource(4) of type (stream)

Warning: Value returned from function f() must be of type @int, stdClass given in %s/test/slow/like_types/return.php on line 4
object(stdClass) (0) {
}

Warning: Value returned from function f() must be of type @int, HH\vec given in %s/test/slow/like_types/return.php on line 4
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Value returned from function f() must be of type @int, HH\dict given in %s/test/slow/like_types/return.php on line 4
dict(2) {
["a"]=>
int(1)
Expand Down
2 changes: 1 addition & 1 deletion hphp/test/slow/like_types/return_alias.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?hh

function f(mixed $x): MyAlias {
function f(mixed $x): <<__Soft>> MyAlias {
return $x;
}

Expand Down
14 changes: 14 additions & 0 deletions hphp/test/slow/like_types/return_alias.php.expectf
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
int(1)

Warning: Value returned from function f() must be of type @MyAlias, float given in %s/test/slow/like_types/return_alias.php on line 4
float(1.5)

Warning: Value returned from function f() must be of type @MyAlias, string given in %s/test/slow/like_types/return_alias.php on line 4
string(3) "foo"

Warning: Value returned from function f() must be of type @MyAlias, bool given in %s/test/slow/like_types/return_alias.php on line 4
bool(false)

Warning: Value returned from function f() must be of type @MyAlias, File given in %s/test/slow/like_types/return_alias.php on line 4
resource(4) of type (stream)

Warning: Value returned from function f() must be of type @MyAlias, stdClass given in %s/test/slow/like_types/return_alias.php on line 4
object(stdClass) (0) {
}

Warning: Value returned from function f() must be of type @MyAlias, HH\vec given in %s/test/slow/like_types/return_alias.php on line 4
vec(3) {
int(1)
int(2)
int(3)
}

Warning: Value returned from function f() must be of type @MyAlias, HH\dict given in %s/test/slow/like_types/return_alias.php on line 4
dict(2) {
["a"]=>
int(1)
Expand Down
2 changes: 2 additions & 0 deletions hphp/test/slow/sound_dynamic/like_int.php.expectf
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
===== ~int =====
$li: 4

Warning: Argument 1 to f_like() must be of type @int, string given in %s/test/slow/sound_dynamic/like_int.php on line 17
$li: not like int
$t: 4 [reified]

Expand Down

0 comments on commit ad1dbd1

Please sign in to comment.