hhvm / type-assert Goto Github PK
View Code? Open in Web Editor NEWHack library for converting untyped data to typed data.
License: Other
Hack library for converting untyped data to typed data.
License: Other
With the current capabilities of TypeAssert, we can derive from Facebook\TypeSpec\TypeSpec<T>
to implement validation for custom newtype
s. These specs compose just like the built-in specs.
__Private\from_type_structure<T>()
(and its friends like TypeSpec\of<T>()
) will however not know how to find our custom TypeSpecs. This means that you need to manually build the complex TypeSpec object via TypeSpec\xxx() calls in practice.
Do we want to offer the capability to supply your own TypeSpecs for your own newtype
s and have them be recognized by TypeSpec\of<T>()
and friends?
This has the major downside of revealing how TypeSpec\of<T>()
works and will prevent us from changing our implementation away from TypeStrucuture<T>
. The fact that we use TypeStrucuture<T>
is an implementation detail of this library.
I have created a PR which demonstrates how something like this may work.
I am not suggesting that this is the PR that adds this feature.
I just need to be able to point to some example code.
File "/builds/HRMWEB/easyEMPLOYER/vendor/fredemmott/type-assert/src/TypeAssert.php", line 81, characters 9-30:
'instanceof' cannot be used on a generic classname because types are erased at runtime (Typing[4162])
I just added // UNSAFE
in the method, but you may have a nicer way of doing it (like a FIXME
, I was just lazy). Was hoping that Hack would've been fixed before the release, but apparently not.
https://github.com/hhvm/type-assert/blob/master/src/TypeSpec/__Private/ShapeSpec.hack
Passing a dict with keys a and b to ShapeSpec coerceType of shape('a' => string)
drops b
. Is this intentional? The assert code path fails loudly for this.
eg
<?hh
$typed = TypeAssert::matchesTypeSpec(
TypeSpec::arrayOf(TypeSpec::string()),
$untyped,
);
Ideally the type_structure implementation should be changed to be a wrapper on top of this, as this isn't tied to undocumented/unsupported HHVM features
example:
final class A<reify T> {}
class B<reify T> {}
final class C<reify Ti, reify To> extends B<Ti> {}
<<__EntryPoint>>
function m(): void {
require_once __DIR__.'/vendor/autoload.hack';
\Facebook\AutoloadMap\initialize();
echo \Facebook\TypeSpec\of<C<string, A<int>>>()->toString();
}
expected output: C<string, A<int>>
actual output: C
use \FredEmmott\TypeAssert\TypeAssert;
type my_shape_t = shape(
'one' => bool,
'two' => array
);
$my_array = array ('one' => true, 'two' => array());
$shape = new ReflectionTypeAlias('my_shape_t');
$type_structure = $shape->getResolvedTypeStructure();
$assertion = TypeAssert::matchesTypeStructure($type_structure, $my_array);
#
# Throws this exception
# Fatal error: Uncaught exception 'FredEmmott\TypeAssert\IncorrectTypeException' with message 'Expected not-null, got null' in ~/code/include/type-assert/TypeAssert.php:72
#
The above example, I think, should evaluate correctly but the 'two' field gets read as null even though it is an empty array.
VarraySpec and DarraySpec are now nearly the same as VecSpec and DictSpec. There are some small differences in the traces that are generated on failure, and there's some redundant logic in the legacy specs (e.g. VarraySpec doesn't trust that a varray's keys are consecutive integers).
Let's get rid of VarraySpec and DarraySpec, and rename VarrayOrDarraySpec to VecOrDictSpec. We should also eliminate any other references to varray or darray in other types, like tuples.
This change will introduce some backwards incompatibility. It looks to me like assertType and coerceType are okay for these specs, but the type name will change, and maybe people are depending on that.
One warning, though: while varray and darray are gone, it is still possible to distinguish varray and vec typehints via reflection... That means that the TypeStructure kinds for varray, darray, and varray_or_darray still exist. It will be some time before we can clean that up, but treating the kinds homogeneously to vec, dict, and vec_or_dict will help us with that.
In my attempt to allow slackhq/hack-json-schema to run on hhvm 4.27, I found that the newer hhvm versions failed the test suite. After hours of debugging I pinned it down on this concept.
use namespace Facebook\TypeSpec;
use namespace Facebook\TypeAssert;
<<__EntryPoint>>
async function main_async(): Awaitable<void> {
require_once __DIR__.'/vendor/autoload.hack';
Facebook\AutoloadMap\initialize();
try {
$spec = TypeSpec\dict(TypeSpec\string(), TypeSpec\mixed());
$spec->assertType([1, 2, 3, 4]);
} catch (TypeAssert\TypeCoercionException $t) {
echo "You are running TypeAssert 3.6.1\n";
} catch (TypeAssert\IncorrectTypeException $t) {
echo "You are running TypeAssert 3.6.2\n";
}
}
In ObjectConstraint::check()
they catch TypeCoercionException to detect and fallback to an array check instead. This exception is now no longer caught. This caused a handful of test failures.
#11 is related - coercion mode will allow these to be used with JSON data, which won't return these.
Hello,
It's a great lib! I'm wondering if it would be possible to use it directly with a shape, here is my usecase:
$result = $db->table->find([
'id' => 1,
], shape(
'id' => int,
'data' => string,
));
and $result
would be typed with the projection. (more exactly array<T>
)
Thanks a lot :)
=hphpd> =Facebook\TypeCoerce\int('100');
=Facebook\TypeCoerce\int('100');
100
hphpd> =Facebook\TypeCoerce\int('-100');
=Facebook\TypeCoerce\int('-100');
Hit a php exception : exception 'Facebook\TypeAssert\TypeCoercionException' with message 'Could not coerce string to type int' ...
This is due to the use of ctype_digit()
which returns false for negative numbers.
We allow either arrays or vecs for tuples, and arrays or dicts for shapes. We should require they match the current runtime.
This makes migration slightly harder, but the 'typeassert may return a different value' thing it creates leads to more problems.
This regex /^(\d*\.)?\d+([eE]\d+)?$/ does not account for negative numbers.
Should be able to replace "\d+" with ints, etc
https://github.com/fredemmott/type-assert/blob/master/src/PrivateImpl/TypeStructureImpl.php is missing cases in the switch for the new hack array types (vec, keyset and dict). This makes the project fail type checking as the switch statement is non-exhaustive.
Asserts that a variable matches the given type structure; these can be arbitrary nested shapes. This is particular useful for dealing with JSON responses.
Test:
<?hh
require_once(__DIR__.'/../../../vendor/hh_autoload.php');
class X
{
const type Inner = shape('a' => int);
const type Outer = Container<self::Inner>;
public static function test(): mixed
{
$subj = [
['a' => 'completely normal int'],
];
return \Facebook\TypeAssert\matches_type_structure(type_structure(self::class, 'Outer'), $subj);
}
}
X::test();
Returns array but should throw IncorrectTypeException because of type mismatch (string instead of int). (Like Fred Emmott's typeassert: FredEmmott\TypeAssert\IncorrectTypeException' with message 'Expected type 'int', got type 'string'' inβ¦
)
Is it possible to get TypeStructure for for generic types?
For consistency with the Hack Standard Library.
Basic example:
class A
{
const type Something = shape('ints' => Container<int>);
}
\FredEmmott\TypeAssert\TypeAssert::matchesTypeStructure(
type_structure(A::class, 'Something'), []);
Result:
Catchable fatal error: Argument 2 passed to FredEmmott\TypeAssert\PrivateImpl\TypeStructureImpl::assertValueTypes() must implement interface HH\KeyedTraversable, null given in β¦/vendor/fredemmott/type-assert/src/PrivateImpl/TypeStructureImpl.php on line 179
HipHop VM 3.12.0-dev
Hi
Another issue with matches_type_structure() (\TypeCoerce\match_type_structure as well):
class X
{
const type Arr = Container<mixed>;
}
\Facebook\TypeAssert\matches_type_structure(type_structure(X::class, 'Arr'), []);
Throws Facebook\TypeAssert\IncorrectTypeException' with message 'Expected type 'HH\Container<T>', got type 'array'
But it shouldn't, right? In addition to Hack collections, PHP arrays are Containers (https://docs.hhvm.com/hack/reference/interface/HH.Container/)
Hi,
I noticed a difference between the return from type_structure and ReflectionTypeAlias::getTypeStructures(). Am I using it correctly ?
Thanks,
type_structure
array(2) {
["kind"]=>
int(14)
["fields"]=>
array(3) {
["a"]=>
array(1) {
["kind"]=>
int(4)
}
}
}
getTypeStructures
array(2) {
["kind"]=>
int(14)
["fields"]=>
array(3) {
["a"]=>
array(1) {
["value"]=>
array(1) {
["kind"]=>
int(4)
}
}
}
}
We're expecting to make darray an alias for dict, varray an alias for vec, and swap the backing store for shapes and tuples to dict/vec respectively in the next 2-8 weeks. Once that has happened in HHVM:
Probably not coming out until 3.17, but is in the nightlies already.
vendor/fredemmott/type-assert/src/PrivateImpl/TypeStructureImpl.php:25:13,23: Switch statement nonexhaustive; the following cases are missing: OF_VEC, OF_KEYSET, OF_DICT (Typing[4019])
/tmp/hh_server/hhi_c9b76cf/typestructure.hhi:16:6,22: Enum declared here
Is this on the roadmap? When a type doesn't match is it possible to emit the field name? Or maybe I am missing something on this lib. Thanks!
$shape_typespec->assertType(dict['a' => 0]); // shape('a' => 0)
$with_kc = TypeSpec\of<KeyedContainer<arraykey, shape('a' => int)>>();
$with_vec = TypeSpec\of<vec<shape('a' => int)>>();
$data = vec[dict['a' => 0]];
$with_kc->assertType($data)[0] is shape(...); // false
$with_vec->assertType($data)[0] is shape(...); // true
The next release of HHVM will eliminate "plain" PHP arrays. After this release:
We can use the HH\is_vec_or_varray and HH\is_dict_or_darray helpers to implement this logic. These helpers don't log, like type tests that distinguish PHP and Hack arrays do, since they're safe for the next steps of Hack Array Migration.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.