From 8277728c56b5b66e7ae8bbfb250690302b4f6974 Mon Sep 17 00:00:00 2001 From: James Wu Date: Thu, 3 Feb 2022 19:45:33 -0800 Subject: [PATCH] Add HH\Readonly\Shapes class Summary: Since we aren't planning on supporting readonly polymorphism (due to the increase in complexity to the language of adding such a feature), we'll likely want some interim Readonly\ namespace versions of common functions in Shapes. These don't pollute the main systemlib namespace, and mostly just call directly into their original Shapes class counterparts, which to me feel like the least invasive way to add this without introducing too much technical debt/cognitive load. We can incrementally remove these if we do decide to add polymorphism for readonly, but right now the tradeoffs of doing so would certainly be too much complexity without TIC. So we should expect these functions to be around for a while. Feedback and concerns appreciated! Reviewed By: oulgen Differential Revision: D33730938 fbshipit-source-id: 3948731bb9055de7378ed35e058596e5de307f34 --- hphp/system/php/lang/readonly.ns.php | 123 +++++++++++++-------- hphp/system/php/misc/idx.php | 2 +- hphp/test/slow/readonly/readonly_shapes_ext.php | 18 +++ .../slow/readonly/readonly_shapes_ext.php.expectf | 11 ++ 4 files changed, 107 insertions(+), 47 deletions(-) rewrite hphp/system/php/lang/readonly.ns.php (86%) create mode 100644 hphp/test/slow/readonly/readonly_shapes_ext.php create mode 100644 hphp/test/slow/readonly/readonly_shapes_ext.php.expectf diff --git a/hphp/system/php/lang/readonly.ns.php b/hphp/system/php/lang/readonly.ns.php dissimilarity index 86% index 45a124a3f9c..c7930a9ac73 100644 --- a/hphp/system/php/lang/readonly.ns.php +++ b/hphp/system/php/lang/readonly.ns.php @@ -1,46 +1,77 @@ -> - -namespace HH\Readonly { - -/** - * Converts a readonly value type into a mutable one. - * Value types include numerics, strings, bools, null and Hack arrays of value - * types. - */ -<<__IgnoreReadonlyLocalErrors>> -function as_mut(readonly T $x)[]: T { - if (is_value_type(readonly $x)) { - return $x; - } - throw new \InvalidArgumentException(__FUNCTION__.' expects a value type'); -} - -function is_value_type(readonly mixed $x)[]: bool { - if ($x is string || $x is int || $x is float || $x is bool || $x is null) { - return true; - } - if ($x is \HH\AnyArray) { - foreach ($x as $v) { - if (!is_value_type($v)) { - return false; - } - } - return true; - } - return false; -} - -/** - * Converts a readonly value to into a mutable one but omits validation for the - * purposes of performance. - * This function takes advantage of non-enforcement of readonly is SystemLib - * and is not safe. - */ -<<__IgnoreReadonlyLocalErrors>> -function as_mut_without_validation(readonly T $x)[]: T { - return $x; -} - -} +> + function as_mut(readonly T $x)[]: T { + if (is_value_type(readonly $x)) { + return $x; + } + throw new \InvalidArgumentException(__FUNCTION__.' expects a value type'); + } + + function is_value_type(readonly mixed $x)[]: bool { + if ($x is string || $x is int || $x is float || $x is bool || $x is null) { + return true; + } + if ($x is \HH\AnyArray) { + foreach ($x as $v) { + if (!is_value_type($v)) { + return false; + } + } + return true; + } + return false; + } + + /** + * Converts a readonly value to into a mutable one but omits validation for the + * purposes of performance. + * This function takes advantage of non-enforcement of readonly is SystemLib + * and is not safe. + */ + <<__IgnoreReadonlyLocalErrors>> + function as_mut_without_validation(readonly T $x)[]: T { + return $x; + } + + /* + Readonly versions of Shape helper functions + Shapes::toArray and Shapes::at are copied because of their simplicity, but most other functions + are ported directly to their counterparts in HH\Shapes (see ext_shapes.php) + */ + abstract final class Shapes { + <<__IsFoldable, __IgnoreReadonlyLocalErrors>> + public static function idx( + readonly ?darray $shape, + readonly arraykey $index, + readonly mixed $default = null, + )[]: readonly mixed { + return \HH\Shapes::idx($shape, $index, $default); + } + + public static function at( + readonly darray $shape, + readonly arraykey $index, + )[]: readonly mixed { + return $shape[$index]; + } + + public static function toArray(readonly darray $shape)[]: readonly darray { + return $shape; + } + + <<__IgnoreReadonlyLocalErrors>> + public static function toDict(readonly darray $shape)[]: readonly dict { + return \HH\Shapes::toDict($shape); + } + } + +} diff --git a/hphp/system/php/misc/idx.php b/hphp/system/php/misc/idx.php index 2ed900214f5..b3c72816280 100644 --- a/hphp/system/php/misc/idx.php +++ b/hphp/system/php/misc/idx.php @@ -125,7 +125,7 @@ function idx($arr, $idx, $default=null)[] { return $default; } <<__IgnoreReadonlyLocalErrors>> -function idx_readonly(readonly $arr, $idx, $default=null)[] : readonly Tv { +function idx_readonly(readonly $arr, readonly $idx, readonly $default=null)[] : readonly Tv { return readonly idx($arr, $idx, $default); } diff --git a/hphp/test/slow/readonly/readonly_shapes_ext.php b/hphp/test/slow/readonly/readonly_shapes_ext.php new file mode 100644 index 00000000000..b8367b32418 --- /dev/null +++ b/hphp/test/slow/readonly/readonly_shapes_ext.php @@ -0,0 +1,18 @@ +> +async function foo(): Awaitable { + $x = readonly shape("foo" => 5); + $y = readonly HH\Readonly\Shapes::toDict($x); + var_dump($y); + $z = readonly HH\Readonly\Shapes::idx($x, "foo"); + var_dump($z); + $null = readonly HH\Readonly\Shapes::idx($x, "bar"); + var_dump($null); + $w = readonly HH\Readonly\Shapes::toArray($x); + var_dump($w); + $a = readonly HH\Readonly\Shapes::at($x, "foo"); + var_dump($a); + +} diff --git a/hphp/test/slow/readonly/readonly_shapes_ext.php.expectf b/hphp/test/slow/readonly/readonly_shapes_ext.php.expectf new file mode 100644 index 00000000000..4645e90c20d --- /dev/null +++ b/hphp/test/slow/readonly/readonly_shapes_ext.php.expectf @@ -0,0 +1,11 @@ +dict(1) { + ["foo"]=> + int(5) +} +int(5) +NULL +dict(1) { + ["foo"]=> + int(5) +} +int(5) -- 2.11.4.GIT