Skip to content
This repository was archived by the owner on Sep 1, 2023. It is now read-only.

Commit 46a628b

Browse files
committed
Add TypeSpec\varray() and TypeSpec\darray(), tests
1 parent e02ad70 commit 46a628b

File tree

6 files changed

+209
-23
lines changed

6 files changed

+209
-23
lines changed

src/TypeSpec.hack

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ function constvector<Tv>(TypeSpec<Tv> $inner): TypeSpec<\ConstVector<Tv>> {
5959
return new __Private\VectorSpec(\ConstVector::class, $inner);
6060
}
6161

62+
function darray<Tk as arraykey, Tv>(
63+
TypeSpec<Tk> $tsk,
64+
TypeSpec<Tv> $tsv,
65+
): TypeSpec<darray<Tk, Tv>> {
66+
return new __Private\DictLikeArraySpec('darray', $tsk, $tsv);
67+
}
68+
6269
function dict<Tk as arraykey, Tv>(
6370
TypeSpec<Tk> $tsk,
6471
TypeSpec<Tv> $tsv,
@@ -70,12 +77,13 @@ function dict_like_array<Tk as arraykey, Tv>(
7077
TypeSpec<Tk> $tsk,
7178
TypeSpec<Tv> $tsv,
7279
): TypeSpec<array<Tk, Tv>> {
73-
return new __Private\DictLikeArraySpec($tsk, $tsv);
80+
return new __Private\DictLikeArraySpec('array', $tsk, $tsv);
7481
}
7582

76-
function enum<Tinner as arraykey, T as /* HH_IGNORE_ERROR[2053] */ \HH\BuiltinEnum<Tinner>>(
77-
classname<T> $what,
78-
): TypeSpec<T> {
83+
function enum<
84+
Tinner as arraykey,
85+
T as /* HH_IGNORE_ERROR[2053] */ \HH\BuiltinEnum<Tinner>,
86+
>(classname<T> $what): TypeSpec<T> {
7987
return new __Private\EnumSpec($what);
8088
}
8189

@@ -147,15 +155,18 @@ function untyped_array(): TypeSpec<array> {
147155
return new __Private\UntypedArraySpec();
148156
}
149157

150-
function vec_like_array<Tv>(TypeSpec<Tv> $tsv): TypeSpec<array<Tv>> {
151-
return new __Private\VecLikeArraySpec($tsv);
158+
function varray<Tv>(TypeSpec<Tv> $tsv): TypeSpec<varray<Tv>> {
159+
return new __Private\VecLikeArraySpec('varray', $tsv);
152160
}
153161

154-
155162
function vec<Tv>(TypeSpec<Tv> $inner): TypeSpec<vec<Tv>> {
156163
return new __Private\VecSpec($inner);
157164
}
158165

166+
function vec_like_array<Tv>(TypeSpec<Tv> $tsv): TypeSpec<array<Tv>> {
167+
return new __Private\VecLikeArraySpec('array', $tsv);
168+
}
169+
159170
function vector<Tv>(TypeSpec<Tv> $inner): TypeSpec<Vector<Tv>> {
160171
return new __Private\VectorSpec(Vector::class, $inner);
161172
}

src/TypeSpec/__Private/DictLikeArraySpec.hack

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ final class DictLikeArraySpec<Tk as arraykey, Tv>
1919
extends TypeSpec<array<Tk, Tv>> {
2020

2121
public function __construct(
22+
private string $name,
2223
private TypeSpec<Tk> $tsk,
2324
private TypeSpec<Tv> $tsv,
2425
) {
@@ -29,13 +30,13 @@ final class DictLikeArraySpec<Tk as arraykey, Tv>
2930
if (!$value is KeyedTraversable<_, _>) {
3031
throw TypeCoercionException::withValue(
3132
$this->getTrace(),
32-
'array<Tk, Tv>',
33+
$this->name.'<Tk, Tv>',
3334
$value,
3435
);
3536
}
3637

37-
$kt = $this->getTrace()->withFrame('array<Tk, _>');
38-
$vt = $this->getTrace()->withFrame('array<_, Tv>');
38+
$kt = $this->getTrace()->withFrame($this->name.'<Tk, _>');
39+
$vt = $this->getTrace()->withFrame($this->name.'<_, Tv>');
3940

4041
return Dict\pull_with_key(
4142
$value,
@@ -50,13 +51,13 @@ final class DictLikeArraySpec<Tk as arraykey, Tv>
5051
if (!\is_array($value)) {
5152
throw IncorrectTypeException::withValue(
5253
$this->getTrace(),
53-
'array<Tk, Tv>',
54+
$this->name.'<Tk, Tv>',
5455
$value,
5556
);
5657
}
5758

58-
$kt = $this->getTrace()->withFrame('array<Tk, _>');
59-
$vt = $this->getTrace()->withFrame('array<_, Tv>');
59+
$kt = $this->getTrace()->withFrame($this->name.'<Tk, _>');
60+
$vt = $this->getTrace()->withFrame($this->name.'<_, Tv>');
6061

6162
return Dict\pull_with_key(
6263
$value,
@@ -69,7 +70,8 @@ final class DictLikeArraySpec<Tk as arraykey, Tv>
6970
<<__Override>>
7071
public function toString(): string {
7172
return Str\format(
72-
'array<%s, %s>',
73+
'%s<%s, %s>',
74+
$this->name,
7375
$this->tsk->toString(),
7476
$this->tsv->toString(),
7577
);

src/TypeSpec/__Private/VecLikeArraySpec.hack

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,20 @@ use type Facebook\TypeSpec\TypeSpec;
1515
use namespace HH\Lib\Vec;
1616

1717
final class VecLikeArraySpec<T> extends TypeSpec<array<T>> {
18-
public function __construct(private TypeSpec<T> $inner) {
18+
public function __construct(
19+
private string $name,
20+
private TypeSpec<T> $inner,
21+
) {
1922
}
2023

2124
<<__Override>>
2225
public function coerceType(mixed $value): array<T> {
2326
if (!$value is Traversable<_>) {
24-
throw
25-
TypeCoercionException::withValue($this->getTrace(), 'array<T>', $value);
27+
throw TypeCoercionException::withValue(
28+
$this->getTrace(),
29+
$this->name.'<T>',
30+
$value,
31+
);
2632
}
2733

2834
return Vec\map($value, $inner ==> $this->inner->coerceType($inner))
@@ -34,7 +40,7 @@ final class VecLikeArraySpec<T> extends TypeSpec<array<T>> {
3440
if (!\is_array($value)) {
3541
throw IncorrectTypeException::withValue(
3642
$this->getTrace(),
37-
'array<T>',
43+
$this->name.'<T>',
3844
$value,
3945
);
4046
}
@@ -53,12 +59,15 @@ final class VecLikeArraySpec<T> extends TypeSpec<array<T>> {
5359
$counter->next();
5460
$i = $counter->current();
5561
if ($k !== $i) {
56-
throw
57-
IncorrectTypeException::withValue($this->getTrace(), 'key '.$i, $k);
62+
throw IncorrectTypeException::withValue(
63+
$this->getTrace(),
64+
'key '.$i,
65+
$k,
66+
);
5867
}
5968
return $this
6069
->inner
61-
->withTrace($this->getTrace()->withFrame('array['.$i.']'))
70+
->withTrace($this->getTrace()->withFrame($this->name.'['.$i.']'))
6271
->assertType($inner);
6372
},
6473
)
@@ -67,6 +76,6 @@ final class VecLikeArraySpec<T> extends TypeSpec<array<T>> {
6776

6877
<<__Override>>
6978
public function toString(): string {
70-
return 'array<'.$this->inner->toString().'>';
79+
return $this->name.'<'.$this->inner->toString().'>';
7180
}
7281
}

src/TypeSpec/__Private/from_type_structure.hack

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,11 @@ function from_type_structure<T>(TypeStructure<T> $ts): TypeSpec<T> {
7575
return new UntypedArraySpec();
7676
case 1:
7777
/* HH_IGNORE_ERROR[4110] */
78-
return new VecLikeArraySpec(from_type_structure($generics[0]));
78+
return new VecLikeArraySpec('array', from_type_structure($generics[0]));
7979
case 2:
8080
/* HH_IGNORE_ERROR[4110] */
8181
return new DictLikeArraySpec(
82+
'array',
8283
from_type_structure($generics[0]),
8384
from_type_structure($generics[1]),
8485
);

tests/DArraySpecTest.hack

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2016, Fred Emmott
3+
* Copyright (c) 2017-present, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the MIT license found in the
7+
* LICENSE file in the root directory of this source tree.
8+
*
9+
*/
10+
11+
namespace Facebook\TypeAssert;
12+
13+
use namespace Facebook\TypeSpec;
14+
use type Facebook\TypeSpec\TypeSpec;
15+
use function Facebook\FBExpect\expect;
16+
17+
final class DArraySpecTest extends TypeSpecTest<darray<arraykey, mixed>> {
18+
<<__Override>>
19+
public function getTypeSpec(): TypeSpec<darray<arraykey, int>> {
20+
return TypeSpec\darray(TypeSpec\arraykey(), TypeSpec\int());
21+
}
22+
23+
<<__Override>>
24+
public function getValidCoercions(): vec<(mixed, darray<arraykey, int>)> {
25+
return vec[
26+
tuple(Map {'foo' => 123}, darray['foo' => 123]),
27+
tuple(ImmMap {'foo' => 123}, darray['foo' => 123]),
28+
tuple(dict['foo' => 123], darray['foo' => 123]),
29+
tuple(dict[], darray[]),
30+
tuple(vec[123], darray[0 => 123]),
31+
tuple(vec['123'], darray[0 => 123]),
32+
tuple(keyset['123'], darray['123' => 123]),
33+
tuple(keyset[123], darray[123 => 123]),
34+
tuple(varray[123], darray[0 => 123]),
35+
tuple(darray["123" => 123], darray['123' => 123]),
36+
];
37+
}
38+
39+
<<__Override>>
40+
public function getInvalidCoercions(): vec<(mixed)> {
41+
return vec[
42+
tuple(false),
43+
tuple(123),
44+
tuple(Map {'foo' => 'bar'}),
45+
];
46+
}
47+
48+
<<__Override>>
49+
public function getToStringExamples(
50+
): vec<(TypeSpec<darray<arraykey, mixed>>, string)> {
51+
return vec[
52+
tuple(
53+
TypeSpec\darray(TypeSpec\string(), TypeSpec\int()),
54+
'darray<string, int>',
55+
),
56+
tuple(
57+
TypeSpec\darray(TypeSpec\int(), TypeSpec\string()),
58+
'darray<int, string>',
59+
),
60+
tuple(
61+
TypeSpec\dict_like_array(TypeSpec\string(), TypeSpec\int()),
62+
'array<string, int>',
63+
),
64+
tuple(
65+
TypeSpec\dict_like_array(TypeSpec\int(), TypeSpec\string()),
66+
'array<int, string>',
67+
),
68+
69+
];
70+
}
71+
72+
public function testDictLikeArrayIsDArray(): void {
73+
$dict_like_array = (
74+
(): array<string, int> ==> TypeSpec\dict_like_array(
75+
TypeSpec\string(),
76+
TypeSpec\int(),
77+
)->assertType(darray['foo' => 123])
78+
)();
79+
expect($dict_like_array)->toEqual(darray['foo' => 123]);
80+
$darray_asserted = (
81+
(): darray<string, int> ==> TypeSpec\darray(
82+
TypeSpec\string(),
83+
TypeSpec\int(),
84+
)->assertType($dict_like_array)
85+
)();
86+
expect($darray_asserted)->toEqual($dict_like_array);
87+
$darray_verbatim = ((): darray<string, int> ==> $dict_like_array)();
88+
expect($darray_verbatim)->toEqual($dict_like_array);
89+
}
90+
}

tests/VArraySpecTest.hack

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2016, Fred Emmott
3+
* Copyright (c) 2017-present, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the MIT license found in the
7+
* LICENSE file in the root directory of this source tree.
8+
*
9+
*/
10+
11+
namespace Facebook\TypeAssert;
12+
13+
use namespace Facebook\TypeSpec;
14+
use type Facebook\TypeSpec\TypeSpec;
15+
use function Facebook\FBExpect\expect;
16+
17+
final class VArraySpecTest extends TypeSpecTest<varray<mixed>> {
18+
<<__Override>>
19+
public function getTypeSpec(): TypeSpec<varray<int>> {
20+
return TypeSpec\varray(TypeSpec\int());
21+
}
22+
23+
<<__Override>>
24+
public function getValidCoercions(): vec<(mixed, varray<int>)> {
25+
return vec[
26+
tuple(vec[], varray[]),
27+
tuple(vec['123'], varray[123]),
28+
tuple(varray['123'], varray[123]),
29+
tuple(varray[123], varray[123]),
30+
tuple(dict['foo' => '456'], varray[456]),
31+
tuple(Vector {123}, varray[123]),
32+
tuple(darray['foo' => 123], varray[123]),
33+
tuple(keyset['123'], varray[123]),
34+
];
35+
}
36+
37+
<<__Override>>
38+
public function getInvalidCoercions(): vec<(mixed)> {
39+
return vec[
40+
tuple(false),
41+
tuple(123),
42+
tuple(varray['foo']),
43+
tuple(vec['foo']),
44+
tuple(keyset['foo']),
45+
];
46+
}
47+
48+
<<__Override>>
49+
public function getToStringExamples(
50+
): vec<(TypeSpec<varray<mixed>>, string)> {
51+
return vec[
52+
tuple(TypeSpec\varray(TypeSpec\string()), 'varray<string>'),
53+
tuple(TypeSpec\varray(TypeSpec\int()), 'varray<int>'),
54+
tuple(TypeSpec\vec_like_array(TypeSpec\string()), 'array<string>'),
55+
tuple(TypeSpec\vec_like_array(TypeSpec\int()), 'array<int>'),
56+
];
57+
}
58+
59+
public function testVecLikeArrayIsVArray(): void {
60+
$vec_like_array = (
61+
(): array<int> ==>
62+
TypeSpec\vec_like_array(TypeSpec\int())->assertType(varray[123])
63+
)();
64+
expect($vec_like_array)->toEqual(varray[123]);
65+
$varray_asserted = (
66+
(): varray<int> ==>
67+
TypeSpec\varray(TypeSpec\int())->assertType($vec_like_array)
68+
)();
69+
expect($varray_asserted)->toEqual($vec_like_array);
70+
$varray_verbatim = ((): varray<int> ==> $vec_like_array)();
71+
expect($varray_verbatim)->toEqual($vec_like_array);
72+
}
73+
}

0 commit comments

Comments
 (0)