Fix Type::operator<= with specializations
[hiphop-php.git] / hphp / runtime / test / type.cpp
blob55066faefef8fc4ffd80c2d7a83898fde7f5dfc4
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include <unordered_set>
19 #include <folly/portability/GTest.h>
20 #include <folly/ScopeGuard.h>
22 #include "hphp/runtime/base/array-data.h"
23 #include "hphp/runtime/base/array-init.h"
24 #include "hphp/runtime/base/repo-auth-type-array.h"
25 #include "hphp/runtime/test/bespoke-layout-mock.h"
26 #include "hphp/runtime/vm/jit/array-layout.h"
27 #include "hphp/runtime/vm/jit/guard-constraint.h"
28 #include "hphp/runtime/vm/jit/print.h"
29 #include "hphp/runtime/vm/jit/type.h"
31 // for specialized object tests to get some real VM::Class
32 #include "hphp/system/systemlib.h"
35 namespace HPHP { namespace jit {
37 namespace {
39 std::unordered_set<Type> allTypes() {
40 std::unordered_set<Type> r;
41 #define IRT(name, ...) r.insert(T##name);
42 #define IRTP(name, ...) IRT(name)
43 #define IRTL(name, ...) IRT(name)
44 #define IRTM(name, ...) IRT(name)
45 #define IRTX(name, ...) IRT(name)
46 IR_TYPES
47 #undef IRT
48 #undef IRTP
49 #undef IRTL
50 #undef IRTM
51 #undef IRTX
52 return r;
57 TEST(Type, Equality) {
58 EXPECT_NE(TCls, TPtrToObj);
59 EXPECT_NE(TLazyCls, TPtrToObj);
60 EXPECT_NE(TCls, TLvalToObj);
61 EXPECT_NE(TLazyCls, TLvalToObj);
62 EXPECT_NE(TCls, TMemToObj);
63 EXPECT_NE(TLazyCls, TMemToObj);
66 TEST(Type, Null) {
67 EXPECT_TRUE(TUninit <= TNull);
68 EXPECT_TRUE(TInitNull <= TNull);
69 EXPECT_FALSE(TBool <= TNull);
70 EXPECT_FALSE(TNull <= TInitNull);
71 EXPECT_NE(TNull, TUninit);
72 EXPECT_NE(TNull, TInitNull);
74 EXPECT_TRUE(TNull.needsReg());
75 EXPECT_FALSE(TUninit.needsReg());
76 EXPECT_FALSE(TInitNull.needsReg());
79 TEST(Type, KnownDataType) {
80 auto trueTypes = {
81 TInt,
82 TStaticStr,
83 TCountedStr,
84 TStr,
85 TObj,
86 TDbl,
87 TVec,
88 TPersistentVec,
89 TStaticVec,
90 TCountedVec,
91 TDict,
92 TPersistentDict,
93 TStaticDict,
94 TCountedDict,
95 TKeyset,
96 TPersistentKeyset,
97 TStaticKeyset,
98 TCountedKeyset,
99 TRes,
100 TBool,
101 TLazyCls,
102 TUninit,
103 TInitNull
105 for (auto t : trueTypes) {
106 EXPECT_TRUE(t.isKnownDataType())
107 << t.toString() << ".isKnownDataType()";
109 auto falseTypes = {
110 TNull,
111 TCell,
112 TInt | TDbl,
113 TArrLike,
114 TPersistentArrLike
116 for (auto t : falseTypes) {
117 EXPECT_FALSE(t.isKnownDataType())
118 << "!" << t.toString() << ".isKnownDataType()";
122 TEST(Type, ArrayLayout) {
123 auto const top = ArrayLayout::Top();
124 auto const vanilla = ArrayLayout::Vanilla();
125 auto const bespoke = ArrayLayout::Bespoke();
126 auto const bottom = ArrayLayout::Bottom();
127 auto const foo = ArrayLayout{
128 bespoke::testing::makeDummyLayout("foo", {ArrayLayout::Bespoke()})
131 EXPECT_EQ("Top", top.describe());
132 EXPECT_EQ("Vanilla", vanilla.describe());
133 EXPECT_EQ("Bespoke", bespoke.describe());
134 EXPECT_EQ("Bottom", bottom.describe());
135 EXPECT_EQ("foo", foo.describe());
137 EXPECT_EQ(top, top);
138 EXPECT_EQ(vanilla, vanilla);
139 EXPECT_EQ(bespoke, bespoke);
140 EXPECT_EQ(bottom, bottom);
141 EXPECT_EQ(foo, foo);
143 EXPECT_NE(top, vanilla);
144 EXPECT_NE(top, bespoke);
145 EXPECT_NE(top, bottom);
146 EXPECT_NE(top, foo);
147 EXPECT_NE(vanilla, bespoke);
148 EXPECT_NE(vanilla, bottom);
149 EXPECT_NE(vanilla, foo);
150 EXPECT_NE(bespoke, bottom);
151 EXPECT_NE(bespoke, foo);
152 EXPECT_NE(bottom, foo);
154 EXPECT_TRUE(top <= top);
155 EXPECT_FALSE(top <= vanilla);
156 EXPECT_FALSE(top <= bespoke);
157 EXPECT_FALSE(top <= bottom);
158 EXPECT_FALSE(top <= foo);
159 EXPECT_TRUE(vanilla <= top);
160 EXPECT_TRUE(vanilla <= vanilla);
161 EXPECT_FALSE(vanilla <= bespoke);
162 EXPECT_FALSE(vanilla <= bottom);
163 EXPECT_FALSE(vanilla <= foo);
164 EXPECT_TRUE(bespoke <= top);
165 EXPECT_FALSE(bespoke <= vanilla);
166 EXPECT_TRUE(bespoke <= bespoke);
167 EXPECT_FALSE(bespoke <= bottom);
168 EXPECT_FALSE(bespoke <= foo);
169 EXPECT_TRUE(bottom <= top);
170 EXPECT_TRUE(bottom <= vanilla);
171 EXPECT_TRUE(bottom <= bespoke);
172 EXPECT_TRUE(bottom <= bottom);
173 EXPECT_TRUE(bottom <= foo);
174 EXPECT_TRUE(foo <= top);
175 EXPECT_FALSE(foo <= vanilla);
176 EXPECT_TRUE(foo <= bespoke);
177 EXPECT_FALSE(foo <= bottom);
178 EXPECT_TRUE(foo <= foo);
180 EXPECT_EQ(top | top, top);
181 EXPECT_EQ(top | vanilla, top);
182 EXPECT_EQ(top | bespoke, top);
183 EXPECT_EQ(top | bottom, top);
184 EXPECT_EQ(top | foo, top);
185 EXPECT_EQ(vanilla | top, top);
186 EXPECT_EQ(vanilla | vanilla, vanilla);
187 EXPECT_EQ(vanilla | bespoke, top);
188 EXPECT_EQ(vanilla | bottom, vanilla);
189 EXPECT_EQ(vanilla | foo, top);
190 EXPECT_EQ(bespoke | top, top);
191 EXPECT_EQ(bespoke | vanilla, top);
192 EXPECT_EQ(bespoke | bespoke, bespoke);
193 EXPECT_EQ(bespoke | bottom, bespoke);
194 EXPECT_EQ(bespoke | foo, bespoke);
195 EXPECT_EQ(bottom | top, top);
196 EXPECT_EQ(bottom | vanilla, vanilla);
197 EXPECT_EQ(bottom | bespoke, bespoke);
198 EXPECT_EQ(bottom | bottom, bottom);
199 EXPECT_EQ(bottom | foo, foo);
200 EXPECT_EQ(foo | top, top);
201 EXPECT_EQ(foo | vanilla, top);
202 EXPECT_EQ(foo | bespoke, bespoke);
203 EXPECT_EQ(foo | bottom, foo);
204 EXPECT_EQ(foo | foo, foo);
206 EXPECT_EQ(top & top, top);
207 EXPECT_EQ(top & vanilla, vanilla);
208 EXPECT_EQ(top & bespoke, bespoke);
209 EXPECT_EQ(top & bottom, bottom);
210 EXPECT_EQ(top & foo, foo);
211 EXPECT_EQ(vanilla & top, vanilla);
212 EXPECT_EQ(vanilla & vanilla, vanilla);
213 EXPECT_EQ(vanilla & bespoke, bottom);
214 EXPECT_EQ(vanilla & bottom, bottom);
215 EXPECT_EQ(vanilla & foo, bottom);
216 EXPECT_EQ(bespoke & top, bespoke);
217 EXPECT_EQ(bespoke & vanilla, bottom);
218 EXPECT_EQ(bespoke & bespoke, bespoke);
219 EXPECT_EQ(bespoke & bottom, bottom);
220 EXPECT_EQ(bespoke & foo, foo);
221 EXPECT_EQ(bottom & top, bottom);
222 EXPECT_EQ(bottom & vanilla, bottom);
223 EXPECT_EQ(bottom & bespoke, bottom);
224 EXPECT_EQ(bottom & bottom, bottom);
225 EXPECT_EQ(bottom & foo, bottom);
226 EXPECT_EQ(foo & top, foo);
227 EXPECT_EQ(foo & vanilla, bottom);
228 EXPECT_EQ(foo & bespoke, foo);
229 EXPECT_EQ(foo & bottom, bottom);
230 EXPECT_EQ(foo & foo, foo);
233 TEST(Type, ToString) {
234 EXPECT_EQ("Int", TInt.toString());
235 EXPECT_EQ("Cell", TCell.toString());
237 EXPECT_EQ("Vec", TVec.toString());
238 EXPECT_EQ("Dict", TDict.toString());
239 EXPECT_EQ("Keyset", TKeyset.toString());
241 EXPECT_EQ("LazyCls", TLazyCls.toString());
243 auto const sub = Type::SubObj(SystemLib::s_HH_IteratorClass);
244 auto const exact = Type::ExactObj(SystemLib::s_HH_IteratorClass);
246 EXPECT_EQ("Obj<=HH\\Iterator", sub.toString());
247 EXPECT_EQ("Obj=HH\\Iterator", exact.toString());
248 EXPECT_EQ("PtrToStr", TPtrToStr.toString());
249 EXPECT_EQ("LvalToStr", TLvalToStr.toString());
251 EXPECT_EQ("PtrTo{Prop|MIS|MMisc|Other|Field}Cell",
252 (TPtrToMembCell - TPtrToElemCell).toString());
253 EXPECT_EQ("LvalTo{Prop|MIS|MMisc|Other|Field}Cell",
254 (TLvalToMembCell - TLvalToElemCell).toString());
255 EXPECT_EQ("PtrToMembCell", TPtrToMembCell.toString());
256 EXPECT_EQ("LvalToMembCell", TLvalToMembCell.toString());
257 EXPECT_EQ("MemToInt", TMemToInt.toString());
258 EXPECT_EQ("PtrTo{Str|Int}|LvalTo{Str|Int}",
259 (TMemToInt | TMemToStr).toString());
261 EXPECT_EQ("PtrTo{Int|StaticStr}|{Int|StaticStr}",
262 (TInt | TPtrToStaticStr).toString());
263 EXPECT_EQ("LvalTo{Int|StaticStr}|{Int|StaticStr}",
264 (TInt | TLvalToStaticStr).toString());
265 EXPECT_EQ("{Obj<=HH\\Iterator|Int}", (TInt | sub).toString());
267 EXPECT_EQ("Cls<=HH\\Iterator",
268 Type::SubCls(SystemLib::s_HH_IteratorClass).toString());
269 EXPECT_EQ("Cls=HH\\Iterator",
270 Type::ExactCls(SystemLib::s_HH_IteratorClass).toString());
272 EXPECT_EQ("{ABC|Func}", (TABC | TFunc).toString());
274 EXPECT_EQ("InitNull", TInitNull.constValString());
276 EXPECT_EQ("InitCell", TInitCell.toString());
277 EXPECT_EQ("PtrToInitCell", TInitCell.ptr(Ptr::Ptr).toString());
278 EXPECT_EQ("PtrToFrameInitCell", TPtrToFrameInitCell.toString());
279 EXPECT_EQ("LvalToFrameInitCell", TLvalToFrameInitCell.toString());
281 auto const ptrCns = Type::cns((TypedValue*)0xba5eba11, TPtrToMembInitNull);
282 EXPECT_EQ("PtrToMembInitNull<TV: 0xba5eba11>", ptrCns.toString());
283 EXPECT_EQ("TV: 0xba5eba11", ptrCns.constValString());
286 TEST(Type, Ptr) {
287 EXPECT_TRUE(TPtrToInt <= TPtrToCell);
289 EXPECT_EQ(TPtrToInt, TInt.ptr(Ptr::Ptr));
290 EXPECT_EQ(TPtrToCell, TCell.ptr(Ptr::Ptr));
291 EXPECT_EQ(TInt, TPtrToInt.deref());
293 EXPECT_EQ(TPtrToInt, TPtrToInt - TInt);
294 EXPECT_EQ(TInt, (TPtrToInt | TInt) - TPtrToInt);
295 EXPECT_EQ(TPtrToUncountedInit, TPtrToUncounted - TPtrToUninit);
297 auto const t = TPtrToInt | TPtrToStr | TInt | TStr;
298 EXPECT_EQ(t, t - TPtrToInt);
299 EXPECT_EQ(t, t - TInt);
300 EXPECT_EQ(TPtrToInt | TPtrToStr, t - (TInt | TStr));
301 EXPECT_EQ(TInt | TStr, t - (TPtrToInt | TPtrToStr));
303 EXPECT_EQ(TBottom, TPtrToInt & TInt);
304 auto const a1 = TVec.ptr(Ptr::Frame);
305 auto const a2 = TDict.ptr(Ptr::Frame);
306 EXPECT_EQ(TBottom, a1 & a2);
307 EXPECT_EQ(a1, a1 - a2);
309 EXPECT_EQ(TPtrToLazyCls, TLazyCls.ptr(Ptr::Ptr));
310 EXPECT_EQ(TLazyCls, TPtrToLazyCls.deref());
311 EXPECT_EQ(TBottom, TPtrToLazyCls & TLazyCls);
313 EXPECT_EQ(TBottom, TBottom.deref());
315 auto const vanillaSpec = ArraySpec(ArrayLayout::Vanilla());
316 auto const vecData = ArrayData::GetScalarArray(make_vec_array(1, 2, 3, 4));
317 auto const ptrToConstVec = Type::cns(vecData).ptr(Ptr::Ptr);
318 EXPECT_TRUE(ptrToConstVec < TPtrToStaticVec);
319 EXPECT_FALSE(ptrToConstVec.hasConstVal());
320 EXPECT_TRUE(ptrToConstVec.isSpecialized());
321 EXPECT_EQ(TPtrToStaticVec, ptrToConstVec.unspecialize());
322 EXPECT_EQ(vanillaSpec, ptrToConstVec.arrSpec());
324 auto const ptrToStaticVanillaVec = TStaticVec.narrowToVanilla().ptr(Ptr::Ptr);
325 EXPECT_TRUE(ptrToStaticVanillaVec < TPtrToStaticVec);
326 EXPECT_FALSE(ptrToStaticVanillaVec.hasConstVal());
327 EXPECT_TRUE(ptrToStaticVanillaVec.isSpecialized());
328 EXPECT_EQ(TPtrToStaticVec, ptrToStaticVanillaVec.unspecialize());
329 EXPECT_EQ(vanillaSpec, ptrToStaticVanillaVec.arrSpec());
331 auto const ptrToStaticVec = TStaticVec.ptr(Ptr::Ptr);
332 EXPECT_EQ(TPtrToStaticVec, ptrToStaticVec);
333 EXPECT_FALSE(ptrToStaticVec.hasConstVal());
334 EXPECT_FALSE(ptrToStaticVec.isSpecialized());
335 EXPECT_EQ(TPtrToStaticVec, ptrToStaticVec.unspecialize());
336 EXPECT_EQ(ArraySpec::Top(), ptrToStaticVec.arrSpec());
338 auto const ptrToVanillaVec = TVanillaVec.ptr(Ptr::Ptr);
339 EXPECT_TRUE(ptrToVanillaVec < TPtrToVec);
340 EXPECT_FALSE(ptrToVanillaVec.hasConstVal());
341 EXPECT_TRUE(ptrToVanillaVec.isSpecialized());
342 EXPECT_EQ(TPtrToVec, ptrToVanillaVec.unspecialize());
343 EXPECT_EQ(vanillaSpec, ptrToVanillaVec.arrSpec());
345 auto const ptrToVec = TVec.ptr(Ptr::Ptr);
346 EXPECT_EQ(TPtrToVec, ptrToVec);
347 EXPECT_FALSE(ptrToVec.hasConstVal());
348 EXPECT_FALSE(ptrToVec.isSpecialized());
349 EXPECT_EQ(TPtrToVec, ptrToVec.unspecialize());
350 EXPECT_EQ(ArraySpec::Top(), ptrToVec.arrSpec());
352 auto ptrToExactObj =
353 Type::ExactObj(SystemLib::s_HH_IteratorClass).ptr(Ptr::Ptr);
354 auto exactClassSpec =
355 ClassSpec(SystemLib::s_HH_IteratorClass, ClassSpec::ExactTag{});
356 EXPECT_FALSE(ptrToExactObj.hasConstVal());
357 EXPECT_TRUE(ptrToExactObj.isSpecialized());
358 EXPECT_EQ(TPtrToObj, ptrToExactObj.unspecialize());
359 EXPECT_EQ(exactClassSpec, ptrToExactObj.clsSpec());
361 auto ptrToSubObj = Type::SubObj(SystemLib::s_HH_IteratorClass).ptr(Ptr::Ptr);
362 auto subClassSpec =
363 ClassSpec(SystemLib::s_HH_IteratorClass, ClassSpec::SubTag{});
364 EXPECT_FALSE(ptrToSubObj.hasConstVal());
365 EXPECT_TRUE(ptrToSubObj.isSpecialized());
366 EXPECT_EQ(TPtrToObj, ptrToSubObj.unspecialize());
367 EXPECT_EQ(subClassSpec, ptrToSubObj.clsSpec());
370 TEST(Type, Lval) {
371 EXPECT_TRUE(TLvalToInt <= TLvalToCell);
373 EXPECT_EQ(TInt, TLvalToInt.deref());
375 EXPECT_EQ(TLvalToInt, TLvalToInt - TInt);
376 EXPECT_EQ(TInt, (TLvalToInt | TInt) - TLvalToInt);
377 EXPECT_EQ(TLvalToUncountedInit, TLvalToUncounted - TLvalToUninit);
379 auto const t = TLvalToInt | TLvalToStr | TInt | TStr;
380 EXPECT_EQ(t, t - TLvalToInt);
381 EXPECT_EQ(t, t - TInt);
382 EXPECT_EQ(TLvalToInt | TLvalToStr, t - (TInt | TStr));
383 EXPECT_EQ(TInt | TStr, t - (TLvalToInt | TLvalToStr));
385 EXPECT_EQ(TBottom, TLvalToInt & TInt);
388 TEST(Type, Mem) {
389 EXPECT_TRUE(TMemToInt <= TMemToCell);
391 EXPECT_EQ(TInt, TMemToInt.deref());
393 EXPECT_EQ(TMemToInt, TMemToInt - TInt);
394 EXPECT_EQ(TInt, (TMemToInt | TInt) - TMemToInt);
395 EXPECT_EQ(TMemToUncountedInit, TMemToUncounted - TMemToUninit);
397 auto const t = TMemToInt | TMemToStr | TInt | TStr;
398 EXPECT_EQ(t, t - TMemToInt);
399 EXPECT_EQ(t, t - TInt);
400 EXPECT_EQ(TMemToInt | TMemToStr, t - (TInt | TStr));
401 EXPECT_EQ(TInt | TStr, t - (TMemToInt | TMemToStr));
403 EXPECT_EQ(TBottom, TMemToInt & TInt);
406 TEST(Type, MemPtrLval) {
407 EXPECT_TRUE(TPtrToInt <= TMemToCell);
408 EXPECT_TRUE(TLvalToInt <= TMemToCell);
409 EXPECT_FALSE(TInt <= TMemToCell);
411 EXPECT_EQ(TBottom, TPtrToInt & TLvalToInt);
412 EXPECT_EQ(TBottom, TPtrToCell & TLvalToCell);
413 EXPECT_EQ(TPtrToInt, TPtrToInt & TMemToCell);
415 EXPECT_EQ(TPtrToInt, TMemToInt - TLvalToInt);
416 EXPECT_EQ(TLvalToInt, TMemToInt - TPtrToInt);
418 auto const t = TInt | TPtrToInt | TLvalToInt;
419 EXPECT_EQ(TInt, t - (TPtrToInt | TLvalToInt));
420 EXPECT_EQ(TPtrToInt, t - (TInt | TLvalToInt));
421 EXPECT_EQ(TLvalToInt, t - (TInt | TPtrToInt));
422 EXPECT_EQ(TPtrToInt | TLvalToInt, t - TInt);
423 EXPECT_EQ(TInt | TLvalToInt, t - TPtrToInt);
424 EXPECT_EQ(TInt | TPtrToInt, t - TLvalToInt);
426 EXPECT_EQ(t | TStr | TMemToStr, t | TStr);
427 EXPECT_EQ(t | TStr | TMemToStr, (t | TStr) - TLvalToInt);
429 EXPECT_EQ(TLvalToUncounted, TLvalToUncounted - TPtrToUninit);
432 TEST(Type, Subtypes) {
433 Type numbers = TDbl | TInt;
434 EXPECT_EQ("{Dbl|Int}", numbers.toString());
435 EXPECT_TRUE(TDbl <= numbers);
436 EXPECT_TRUE(TInt <= numbers);
437 EXPECT_FALSE(TBool <= numbers);
439 EXPECT_TRUE(TFunc <= TCell);
440 EXPECT_FALSE(TTCA <= TCell);
442 EXPECT_TRUE(TVec <= TArrLike);
443 EXPECT_TRUE(TDict <= TArrLike);
444 EXPECT_TRUE(TKeyset <= TArrLike);
446 Type funcOrlcls = TFunc | TLazyCls;
447 EXPECT_EQ("{Func|LazyCls}", funcOrlcls.toString());
448 EXPECT_TRUE(TLazyCls <= funcOrlcls);
449 EXPECT_FALSE(TCls <= funcOrlcls);
452 TEST(Type, Top) {
453 for (auto t : allTypes()) {
454 EXPECT_TRUE(t <= TTop);
456 for (auto t : allTypes()) {
457 if (t == TTop) continue;
458 EXPECT_FALSE(TTop <= t);
462 namespace {
463 inline bool fits(Type t, GuardConstraint gc) {
464 return typeFitsConstraint(t, gc);
468 TEST(Type, GuardConstraints) {
469 EXPECT_TRUE(fits(TCell, DataTypeGeneric));
470 EXPECT_FALSE(fits(TCell, DataTypeCountnessInit));
471 EXPECT_FALSE(fits(TCell, DataTypeSpecific));
473 EXPECT_TRUE(fits(TCell, {DataTypeGeneric}));
475 auto const vanillaConstraint =
476 GuardConstraint(DataTypeSpecialized).setArrayLayoutSensitive();
477 EXPECT_FALSE(fits(TCell, vanillaConstraint));
478 EXPECT_FALSE(fits(TArrLike, vanillaConstraint));
479 EXPECT_FALSE(fits(TVec, vanillaConstraint));
480 EXPECT_FALSE(fits(TVanillaArrLike, vanillaConstraint));
481 EXPECT_TRUE(fits(TVanillaVec, vanillaConstraint));
484 TEST(Type, RelaxType) {
485 auto gc = GuardConstraint{DataTypeSpecialized};
486 gc.setDesiredClass(SystemLib::s_HH_IteratorClass);
487 gc.category = DataTypeSpecialized;
488 auto subIter = Type::SubObj(SystemLib::s_HH_IteratorClass);
489 EXPECT_EQ("Obj<=HH\\Iterator", subIter.toString());
490 EXPECT_EQ(subIter, relaxType(subIter, gc.category));
493 TEST(Type, RelaxConstraint) {
494 EXPECT_EQ(GuardConstraint(DataTypeCountnessInit),
495 relaxConstraint(GuardConstraint{DataTypeSpecific}, TCell, TDict));
498 TEST(Type, Specialized) {
499 EXPECT_LE(TVanillaArrLike, TArrLike);
500 EXPECT_LT(TVanillaArrLike, TArrLike);
501 EXPECT_FALSE(TArrLike <= TVanillaArrLike);
502 EXPECT_LT(TVanillaArrLike, TArrLike | TObj);
503 EXPECT_EQ(TVanillaArrLike, TVanillaArrLike & (TArrLike | TCounted));
504 EXPECT_GE(TVanillaArrLike, TBottom);
505 EXPECT_GT(TVanillaArrLike, TBottom);
507 EXPECT_TRUE(TInt <= (TVanillaArrLike | TInt));
509 EXPECT_EQ(TBottom, TVanillaArrLike & TObj);
510 EXPECT_EQ(TBottom, TVanillaArrLike - TArrLike);
512 auto const vecData = ArrayData::GetScalarArray(make_vec_array(1, 2, 3, 4));
513 auto const dictData = ArrayData::GetScalarArray(make_dict_array(1, 1, 2, 2));
514 auto const constVec = Type::cns(vecData);
515 auto const constDict = Type::cns(dictData);
517 // Basic checks on constant array types.
519 EXPECT_TRUE(constDict.hasConstVal());
520 EXPECT_TRUE(constDict <= TArrLike);
521 EXPECT_TRUE(constDict <= TDict);
522 EXPECT_TRUE(constDict < TDict);
523 EXPECT_TRUE(constDict <= TStaticDict);
524 EXPECT_TRUE(constDict < TStaticDict);
525 EXPECT_FALSE(constDict <= TVec);
527 EXPECT_TRUE(constVec.hasConstVal());
528 EXPECT_TRUE(constVec <= TArrLike);
529 EXPECT_TRUE(constVec <= TVec);
530 EXPECT_TRUE(constVec < TVec);
531 EXPECT_TRUE(constVec <= TStaticVec);
532 EXPECT_TRUE(constVec < TStaticVec);
533 EXPECT_FALSE(constVec <= TDict);
535 // For some difference types, we are pessimistic: we had better not narrow
536 // these differences to TBottom, but we can't represent them finely.
537 EXPECT_EQ(TStaticVec, TStaticVec - constVec);
538 EXPECT_EQ(TBottom, constVec - TStaticVec);
539 EXPECT_EQ(constDict, constDict - TStaticVec);
540 EXPECT_EQ(TBottom, constDict - TDict);
542 // Checking specialization dropping. We cannot specialize on two dimensions
543 // (e.g. array-like and object) at the same time.
544 EXPECT_EQ(TStaticVec | TObj, constVec | TObj);
545 auto const subIter = Type::SubObj(SystemLib::s_HH_IteratorClass);
546 EXPECT_EQ(TVec | TObj, TVec | subIter);
548 auto const vecOrInt = TVec | TInt;
549 EXPECT_EQ(TInt, vecOrInt - TArrLike);
550 EXPECT_EQ(TInt, vecOrInt - TVec);
551 EXPECT_EQ(TVec, vecOrInt - TInt);
552 EXPECT_EQ(TPtrToVec, TPtrToVec - constVec.ptr(Ptr::Ptr));
554 auto const iterOrStr = subIter | TStr;
555 EXPECT_EQ(TStr, iterOrStr - TObj);
556 EXPECT_EQ(TStr, iterOrStr - subIter);
557 EXPECT_EQ(subIter, iterOrStr - TStr);
558 EXPECT_EQ(TPtrToObj, TPtrToObj - subIter.ptr(Ptr::Ptr));
560 auto const subCls = Type::SubCls(SystemLib::s_HH_IteratorClass);
561 EXPECT_EQ(TCls, TCls - subCls);
563 auto const lclsOrStr = TLazyCls | TStr;
564 EXPECT_EQ(TStr, lclsOrStr - TLazyCls);
565 EXPECT_EQ(TLazyCls, lclsOrStr - TStr);
568 TEST(Type, ArrayFitsSpec) {
569 auto const nonempty = RepoAuthType::Array::Empty::No;
570 auto const maybe_empty = RepoAuthType::Array::Empty::Maybe;
571 auto const str_rat = RepoAuthType(RepoAuthType::Tag::Str);
572 auto const int_rat = RepoAuthType(RepoAuthType::Tag::Int);
574 ArrayTypeTable::Builder builder;
575 auto const rat1 = builder.tuple(nonempty, {int_rat, int_rat});
576 auto const rat2 = builder.tuple(maybe_empty, {int_rat, str_rat});
577 auto const rat3 = builder.packed(nonempty, int_rat);
579 auto const ratType1 = Type::Vec(rat1);
580 auto const ratType2 = Type::Vec(rat2);
581 auto const ratType3 = Type::Vec(rat3);
583 auto const vec1 = ArrayData::GetScalarArray(make_vec_array(2, 3));
584 auto const vec2 = ArrayData::GetScalarArray(make_vec_array(2, ""));
585 auto const vec3 = ArrayData::GetScalarArray(make_vec_array(2, 3, 5));
587 DictInit dict_init1{2};
588 dict_init1.set((int64_t)0, 2);
589 dict_init1.set((int64_t)1, 3);
590 auto const dict1 = ArrayData::GetScalarArray(dict_init1.toArray());
592 DictInit dict_init2{2};
593 dict_init2.set(17, 2);
594 dict_init2.set(19, 3);
595 auto const dict2 = ArrayData::GetScalarArray(dict_init2.toArray());
597 EXPECT_FALSE(Type::cns(staticEmptyVec()) <= ratType1);
598 EXPECT_TRUE(Type::cns(staticEmptyVec()) <= ratType2);
599 EXPECT_FALSE(Type::cns(staticEmptyVec()) <= ratType3);
601 EXPECT_TRUE(Type::cns(vec1) <= ratType1);
602 EXPECT_FALSE(Type::cns(vec1) <= ratType2);
603 EXPECT_TRUE(Type::cns(vec1) <= ratType3);
605 EXPECT_FALSE(Type::cns(vec2) <= ratType1);
606 EXPECT_TRUE(Type::cns(vec2) <= ratType2);
607 EXPECT_FALSE(Type::cns(vec2) <= ratType3);
609 EXPECT_FALSE(Type::cns(vec3) <= ratType1);
610 EXPECT_FALSE(Type::cns(vec3) <= ratType2);
611 EXPECT_TRUE(Type::cns(vec3) <= ratType3);
613 EXPECT_FALSE(Type::cns(dict1) <= ratType1);
614 EXPECT_FALSE(Type::cns(dict1) <= ratType2);
615 EXPECT_FALSE(Type::cns(dict1) <= ratType3);
617 EXPECT_FALSE(Type::cns(dict2) <= ratType1);
618 EXPECT_FALSE(Type::cns(dict2) <= ratType2);
619 EXPECT_FALSE(Type::cns(dict2) <= ratType3);
621 EXPECT_LE(TUninit, ratType1 | TNull);
622 EXPECT_FALSE((ratType1 | TNull) <= TUninit);
624 EXPECT_LE(TUninit, ratType3 | TNull);
625 EXPECT_FALSE((ratType3 | TNull) <= TUninit);
628 TEST(Type, SpecializedArrays) {
629 EXPECT_FALSE(TArrLike.isSpecialized());
630 EXPECT_FALSE(TArrLike.arrSpec());
631 EXPECT_FALSE(TArrLike.arrSpec().vanilla());
633 auto const const_array = Type::cns(staticEmptyVec());
634 EXPECT_TRUE(const_array.isSpecialized());
635 EXPECT_TRUE(const_array.arrSpec());
636 EXPECT_TRUE(const_array.arrSpec().vanilla());
638 EXPECT_FALSE(TDict.isSpecialized());
639 EXPECT_FALSE(TDict.arrSpec());
640 EXPECT_FALSE(TDict.arrSpec().vanilla());
642 auto const const_dict = Type::cns(staticEmptyDictArray());
643 EXPECT_TRUE(const_dict.isSpecialized());
644 EXPECT_TRUE(const_dict.arrSpec());
645 EXPECT_TRUE(const_dict.arrSpec().vanilla());
648 TEST(Type, SpecializedObjects) {
649 auto const A = SystemLib::s_HH_IteratorClass;
650 auto const B = SystemLib::s_HH_TraversableClass;
651 EXPECT_TRUE(A->classof(B));
653 auto const obj = TObj;
654 auto const exactA = Type::ExactObj(A);
655 auto const exactB = Type::ExactObj(B);
656 auto const subA = Type::SubObj(A);
657 auto const subB = Type::SubObj(B);
659 EXPECT_EQ(exactA.clsSpec().cls(), A);
660 EXPECT_EQ(subA.clsSpec().cls(), A);
662 EXPECT_EQ(exactA.clsSpec().exactCls(), A);
663 EXPECT_EQ(subA.clsSpec().exactCls(), nullptr);
665 EXPECT_LE(exactA, exactA);
666 EXPECT_LE(subA, subA);
668 EXPECT_LT(exactA, obj);
669 EXPECT_LT(subA, obj);
671 EXPECT_LE(TBottom, subA);
672 EXPECT_LE(TBottom, exactA);
674 EXPECT_LT(exactA, subA);
676 EXPECT_LT(exactA, subB);
677 EXPECT_LT(subA, subB);
679 EXPECT_FALSE(exactA <= exactB);
680 EXPECT_FALSE(subA <= exactB);
682 EXPECT_EQ(exactA & subA, exactA);
683 EXPECT_EQ(subA & exactA, exactA);
684 EXPECT_EQ(exactB & subB, exactB);
685 EXPECT_EQ(subB & exactB, exactB);
687 EXPECT_EQ(TObj, TObj - subA); // conservative
688 EXPECT_EQ(subA, subA - exactA); // conservative
691 TEST(Type, SpecializedClass) {
692 auto const A = SystemLib::s_HH_IteratorClass;
693 auto const B = SystemLib::s_HH_TraversableClass;
695 EXPECT_TRUE(A->classof(B));
697 auto const cls = TCls;
698 auto const exactA = Type::ExactCls(A);
699 auto const exactB = Type::ExactCls(B);
700 auto const subA = Type::SubCls(A);
701 auto const subB = Type::SubCls(B);
703 EXPECT_EQ(exactA.clsSpec().exactCls(), A);
704 EXPECT_EQ(subA.clsSpec().cls(), A);
705 EXPECT_EQ(subA.clsSpec().exactCls(), nullptr);
707 EXPECT_LE(exactA, exactA);
708 EXPECT_LE(subA, subA);
710 EXPECT_LT(exactA, cls);
711 EXPECT_LT(subA, cls);
713 EXPECT_LE(TBottom, exactA);
714 EXPECT_LE(TBottom, subA);
716 EXPECT_LT(exactA, subA);
718 EXPECT_LT(exactA, subB);
719 EXPECT_LT(subA, subB);
721 EXPECT_FALSE(exactA <= exactB);
722 EXPECT_FALSE(subA <= exactB);
724 EXPECT_EQ(exactA & subA, exactA);
725 EXPECT_EQ(subA & exactA, exactA);
726 EXPECT_EQ(exactB & subB, exactB);
727 EXPECT_EQ(subB & exactB, exactB);
729 EXPECT_EQ(cls, cls - subA); // conservative
730 EXPECT_EQ(subA, subA - exactA); // conservative
732 EXPECT_LE(TUninit, exactA | TNull);
733 EXPECT_FALSE((exactA | TNull) <= TUninit);
735 EXPECT_LE(TUninit, subA | TNull);
736 EXPECT_FALSE((subA | TNull) <= TUninit);
739 TEST(Type, Const) {
740 auto five = Type::cns(5);
741 auto fiveArr = five | TArrLike;
742 EXPECT_LT(five, TInt);
743 EXPECT_NE(five, TInt);
744 EXPECT_TRUE(five.hasConstVal());
745 EXPECT_EQ(5, five.intVal());
746 EXPECT_TRUE(five.hasConstVal(TInt));
747 EXPECT_TRUE(five.hasConstVal(5));
748 EXPECT_FALSE(five.hasConstVal(5.0));
749 EXPECT_TRUE(TCell.maybe(five));
750 EXPECT_EQ(TInt, five | TInt);
751 EXPECT_EQ(TInt, five | Type::cns(10));
752 EXPECT_EQ(five, five | Type::cns(5));
753 EXPECT_EQ(five, Type::cns(5) & five);
754 EXPECT_EQ(five, five & TInt);
755 EXPECT_EQ(five, TCell & five);
756 EXPECT_EQ("Int<5>", five.toString());
757 EXPECT_EQ(five, five - TArrLike);
758 EXPECT_EQ(five, five - Type::cns(1));
759 EXPECT_EQ(TInt, TInt - five); // conservative
760 EXPECT_EQ(TInt, fiveArr - TArrLike);
761 EXPECT_EQ(fiveArr, fiveArr - five);
762 EXPECT_EQ(TArrLike, fiveArr - TInt);
763 EXPECT_EQ(TBottom, five - TInt);
764 EXPECT_EQ(TBottom, five - five);
765 EXPECT_EQ(TPtrToCell,
766 (TPtrToCell|TNullptr) - TNullptr);
767 EXPECT_EQ(TInt, five.dropConstVal());
768 EXPECT_TRUE(!five.maybe(Type::cns(2)));
770 auto True = Type::cns(true);
771 EXPECT_EQ("Bool<true>", True.toString());
772 EXPECT_LT(True, TBool);
773 EXPECT_NE(True, TBool);
774 EXPECT_TRUE(True.hasConstVal());
775 EXPECT_TRUE(True.boolVal());
776 EXPECT_TRUE(TUncounted.maybe(True));
777 EXPECT_FALSE(five <= True);
778 EXPECT_FALSE(five > True);
780 EXPECT_TRUE(!five.maybe(True));
781 EXPECT_EQ(TInt | TBool, five | True);
782 EXPECT_EQ(TBottom, five & True);
783 EXPECT_EQ(Type::cns(false), TBool - True);
785 auto const arrData = ArrayData::GetScalarArray(make_dict_array(1, 2, 3, 4));
786 auto const constArray = Type::cns(arrData);
788 EXPECT_EQ(constArray, constArray & TDict);
789 EXPECT_TRUE(constArray <= constArray);
790 EXPECT_TRUE(constArray <= TDict);
791 EXPECT_TRUE(constArray < TDict);
792 EXPECT_FALSE(TDict <= constArray);
793 EXPECT_FALSE(TDict <= TVec);
795 ArrayTypeTable::Builder ratBuilder;
796 auto const rat1 = ratBuilder.packed(RepoAuthType::Array::Empty::No,
797 RepoAuthType(RepoAuthType::Tag::Str));
798 auto const ratArray1 = Type::Dict(rat1);
799 auto const rat2 = ratBuilder.packed(RepoAuthType::Array::Empty::No,
800 RepoAuthType(RepoAuthType::Tag::Int));
801 auto const ratArray2 = Type::Dict(rat2);
802 EXPECT_EQ(ratArray1, ratArray1 & ratArray2);
803 EXPECT_EQ(ratArray1, ratArray2 & ratArray1);
804 EXPECT_TRUE(ratArray1 <= TArrLike);
805 EXPECT_TRUE(ratArray1 < TArrLike);
806 EXPECT_TRUE(ratArray1 <= TDict);
807 EXPECT_TRUE(ratArray1 < TDict);
808 EXPECT_TRUE(ratArray1 <= ratArray1);
809 EXPECT_TRUE(ratArray1 < (TDict|TObj));
810 EXPECT_FALSE(ratArray1 < ratArray2);
811 EXPECT_NE(ratArray1, ratArray2);
813 auto const vanillaRat = ratArray1 & TVanillaArrLike;
814 EXPECT_EQ("ArrLike=Vanilla", TVanillaArrLike.toString());
815 EXPECT_EQ("Dict=Vanilla:N([Str])", vanillaRat.toString());
816 EXPECT_TRUE(vanillaRat <= TVanillaArrLike);
817 EXPECT_TRUE(vanillaRat < TVanillaArrLike);
818 EXPECT_TRUE(vanillaRat <= TVanillaDict);
819 EXPECT_TRUE(vanillaRat < TVanillaDict);
820 EXPECT_TRUE(vanillaRat <= ratArray1);
821 EXPECT_TRUE(vanillaRat < ratArray1);
822 EXPECT_TRUE(vanillaRat.arrSpec().vanilla());
824 auto const narrowedRat = ratArray1.narrowToVanilla();
825 EXPECT_EQ("Dict=N([Str])", ratArray1.toString());
826 EXPECT_EQ("Dict=Vanilla:N([Str])", narrowedRat.toString());
827 EXPECT_TRUE(narrowedRat < ratArray1);
828 EXPECT_TRUE(narrowedRat <= ratArray1);
829 EXPECT_FALSE(ratArray1 < narrowedRat);
830 EXPECT_FALSE(ratArray1 <= narrowedRat);
831 EXPECT_EQ(narrowedRat, ratArray1 & TVanillaArrLike);
832 EXPECT_FALSE(ratArray1.arrSpec().vanilla());
834 auto const vec = make_vec_array(1, 2, 3, 4);
835 auto const vecData = ArrayData::GetScalarArray(std::move(vec));
836 auto const constVec = Type::cns(vecData);
837 EXPECT_TRUE(constVec < TVec);
839 auto const dict = make_dict_array(1, 1, 2, 2, 3, 3, 4, 4);
840 auto const dictData = ArrayData::GetScalarArray(std::move(dict));
841 auto const constDict = Type::cns(dictData);
842 EXPECT_TRUE(constDict < TDict);
844 auto const keyset = make_keyset_array(1, 2, 3, 4);
845 auto const keysetData = ArrayData::GetScalarArray(std::move(keyset));
846 auto const constKeyset = Type::cns(keysetData);
847 EXPECT_TRUE(constKeyset < TKeyset);
849 auto constLazyCls = Type::cns(LazyClassData::create(makeStaticString("Foo")));
850 EXPECT_TRUE(constLazyCls < TLazyCls);
851 EXPECT_TRUE(constLazyCls.hasConstVal());
852 EXPECT_FALSE(TLazyCls.hasConstVal());
853 EXPECT_EQ(TLazyCls | TBool, constLazyCls | True);
854 EXPECT_EQ(TBottom, constLazyCls & True);
857 TEST(Type, NarrowToVanilla) {
858 EXPECT_EQ("Vec=Vanilla", TVec.narrowToVanilla().toString());
859 EXPECT_EQ("{Dict|Vec}=Vanilla", (TVec|TDict).narrowToVanilla().toString());
860 EXPECT_EQ("{Vec=Vanilla|Int}", (TVec|TInt).narrowToVanilla().toString());
861 EXPECT_EQ("{Vec|Obj}", (TVec|TObj).narrowToVanilla().toString());
864 TEST(Type, VanillaArray) {
865 EXPECT_EQ("ArrLike=Vanilla", TVanillaArrLike.toString());
866 EXPECT_TRUE(TVanillaArrLike <= TArrLike);
867 EXPECT_TRUE(TVanillaArrLike < TArrLike);
868 EXPECT_FALSE(TVanillaArrLike.arrSpec().type());
869 EXPECT_TRUE(TVanillaArrLike.arrSpec().vanilla());
872 TEST(Type, VanillaVec) {
873 EXPECT_EQ("Vec", TVec.toString());
874 EXPECT_FALSE(TVec.arrSpec().type());
875 EXPECT_FALSE(TVec.arrSpec().vanilla());
877 EXPECT_EQ("Vec=Vanilla", TVanillaVec.toString());
878 EXPECT_FALSE(TVanillaVec.arrSpec().type());
879 EXPECT_TRUE(TVanillaVec.arrSpec().vanilla());
880 EXPECT_EQ(TVanillaVec, TVec & TVanillaVec);
881 EXPECT_EQ(TVanillaVec, TVec.narrowToVanilla());
883 EXPECT_FALSE(TVec <= TVanillaVec);
884 EXPECT_TRUE(TVanillaVec <= TVec);
885 EXPECT_FALSE(TVec < TVanillaVec);
886 EXPECT_TRUE(TVanillaVec < TVec);
889 TEST(Type, BespokeVec) {
890 auto const foo_layout = ArrayLayout{
891 bespoke::testing::makeDummyLayout("foo", {ArrayLayout::Bespoke()})
893 auto const bar_layout = ArrayLayout{
894 bespoke::testing::makeDummyLayout("bar", {ArrayLayout::Bespoke()})
897 auto const vecFoo = TVec.narrowToLayout(foo_layout);
898 EXPECT_EQ("Vec=foo", vecFoo.toString());
899 EXPECT_FALSE(TVec <= vecFoo);
900 EXPECT_FALSE(TVanillaVec <= vecFoo);
901 EXPECT_FALSE(vecFoo <= TVanillaVec);
902 EXPECT_EQ(vecFoo | TVanillaVec, TVec);
903 EXPECT_EQ(TVanillaVec & vecFoo, TBottom);
904 EXPECT_EQ(vecFoo | TVec, TVec);
905 EXPECT_EQ(vecFoo & TVec, vecFoo);
907 auto const vecBar = TVec.narrowToLayout(bar_layout);
908 EXPECT_EQ("Vec=bar", vecBar.toString());
910 auto const vecVanillaBar = TVanillaVec.narrowToLayout(bar_layout);
911 EXPECT_EQ(TBottom, vecVanillaBar);
914 TEST(Type, BespokeVecRAT) {
915 RO::EvalBespokeArrayLikeMode = 2;
916 auto const foo_layout = ArrayLayout{
917 bespoke::testing::makeDummyLayout("foo", {ArrayLayout::Bespoke()})
919 auto const bar_layout = ArrayLayout{
920 bespoke::testing::makeDummyLayout("bar", {ArrayLayout::Bespoke()})
922 bespoke::selectBespokeLayouts();
924 ArrayTypeTable::Builder ratBuilder;
925 auto const rat = ratBuilder.packed(RepoAuthType::Array::Empty::No,
926 RepoAuthType(RepoAuthType::Tag::Str));
927 auto const vecRat = Type::Vec(rat);
928 EXPECT_EQ("Vec=N([Str])", vecRat.toString());
929 auto const vecRatBespoke = vecRat.narrowToLayout(foo_layout);
930 EXPECT_EQ("Vec=foo:N([Str])", vecRatBespoke.toString());
931 auto const vecRatVanilla = vecRat.narrowToVanilla();
932 EXPECT_EQ("Vec=Vanilla:N([Str])", vecRatVanilla.toString());
934 EXPECT_EQ(TBottom, vecRatBespoke.narrowToVanilla());
935 EXPECT_EQ(TBottom, vecRatVanilla.narrowToLayout(foo_layout));
936 EXPECT_EQ(TBottom, vecRatBespoke.narrowToLayout(bar_layout));
939 TEST(Type, VanillaVecRAT) {
940 ArrayTypeTable::Builder ratBuilder;
941 auto const rat = ratBuilder.packed(RepoAuthType::Array::Empty::No,
942 RepoAuthType(RepoAuthType::Tag::Str));
943 auto const vecRat = Type::Vec(rat);
944 EXPECT_EQ("Vec=N([Str])", vecRat.toString());
945 EXPECT_TRUE(vecRat.arrSpec().type());
946 EXPECT_FALSE(vecRat.arrSpec().vanilla());
948 auto const vanillaVecRat = vecRat.narrowToVanilla();
949 EXPECT_EQ("Vec=Vanilla:N([Str])", vanillaVecRat.toString());
950 EXPECT_TRUE(vanillaVecRat.arrSpec().type());
951 EXPECT_TRUE(vanillaVecRat.arrSpec().vanilla());
952 EXPECT_EQ(vanillaVecRat, vecRat & TVanillaVec);
954 EXPECT_FALSE(TVec <= vecRat);
955 EXPECT_TRUE(vecRat <= TVec);
956 EXPECT_FALSE(TVec < vecRat);
957 EXPECT_TRUE(vecRat < TVec);
959 EXPECT_TRUE(vanillaVecRat <= TVec);
960 EXPECT_TRUE(vanillaVecRat < TVec);
961 EXPECT_TRUE(vanillaVecRat <= vecRat);
962 EXPECT_FALSE(vecRat < vanillaVecRat);
963 EXPECT_TRUE(vanillaVecRat <= TVanillaVec);
964 EXPECT_TRUE(vanillaVecRat < TVanillaVec);
966 EXPECT_TRUE(vanillaVecRat <= TVanillaVec);
967 EXPECT_FALSE(vecRat <= TVanillaVec);
968 EXPECT_TRUE(vanillaVecRat < TVanillaVec);
969 EXPECT_FALSE(vecRat < TVanillaVec);
972 TEST(Type, BespokeHierarchy) {
974 * top(L)
975 * / \
976 * foo(L) baz
977 * | \ / \
978 * bar bat(L) ter
980 RO::EvalBespokeArrayLikeMode = 2;
981 bespoke::Layout::ClearHierarchy();
982 auto const foo_layout = ArrayLayout{
983 bespoke::testing::makeDummyAbstractLayout("foo", {ArrayLayout::Bespoke()})
985 auto const baz_layout = ArrayLayout{
986 bespoke::testing::makeDummyAbstractLayout("baz", {ArrayLayout::Bespoke()})
988 auto const bar_layout = ArrayLayout{
989 bespoke::testing::makeDummyLayout("bar", {foo_layout})
991 auto const bat_layout = ArrayLayout{
992 bespoke::testing::makeDummyLayout("bat", {foo_layout, baz_layout})
994 auto const ter_layout = ArrayLayout{
995 bespoke::testing::makeDummyLayout("ter", {baz_layout})
997 bespoke::selectBespokeLayouts();
999 auto const top = TVec.narrowToLayout(ArrayLayout::Bespoke());
1000 auto const foo = TVec.narrowToLayout(foo_layout);
1001 auto const baz = TVec.narrowToLayout(baz_layout);
1002 auto const bar = TVec.narrowToLayout(bar_layout);
1003 auto const bat = TVec.narrowToLayout(bat_layout);
1004 auto const ter = TVec.narrowToLayout(ter_layout);
1005 auto const bot = TBottom;
1007 // Subtypes
1008 EXPECT_TRUE(top <= top);
1009 EXPECT_TRUE(foo <= top);
1010 EXPECT_TRUE(baz <= top);
1011 EXPECT_TRUE(bar <= top);
1012 EXPECT_TRUE(bat <= top);
1013 EXPECT_TRUE(ter <= top);
1015 EXPECT_FALSE(top <= foo);
1016 EXPECT_TRUE(foo <= foo);
1017 EXPECT_FALSE(baz <= foo);
1018 EXPECT_TRUE(bar <= foo);
1019 EXPECT_TRUE(bat <= foo);
1020 EXPECT_FALSE(ter <= foo);
1022 EXPECT_FALSE(top <= bar);
1023 EXPECT_FALSE(foo <= bar);
1024 EXPECT_FALSE(baz <= bar);
1025 EXPECT_TRUE(bar <= bar);
1026 EXPECT_FALSE(bat <= bar);
1027 EXPECT_FALSE(ter <= bar);
1029 EXPECT_FALSE(top <= bat);
1030 EXPECT_FALSE(foo <= bat);
1031 EXPECT_FALSE(baz <= bat);
1032 EXPECT_FALSE(bar <= bat);
1033 EXPECT_TRUE(bat <= bat);
1034 EXPECT_FALSE(ter <= bat);
1036 EXPECT_FALSE(top <= baz);
1037 EXPECT_FALSE(foo <= baz);
1038 EXPECT_TRUE(baz <= baz);
1039 EXPECT_FALSE(bar <= baz);
1040 EXPECT_TRUE(bat <= baz);
1041 EXPECT_TRUE(ter <= baz);
1043 EXPECT_FALSE(top <= ter);
1044 EXPECT_FALSE(foo <= ter);
1045 EXPECT_FALSE(baz <= ter);
1046 EXPECT_FALSE(bar <= ter);
1047 EXPECT_FALSE(bat <= ter);
1048 EXPECT_TRUE(ter <= ter);
1050 EXPECT_TRUE(bot <= top);
1051 EXPECT_TRUE(bot <= foo);
1052 EXPECT_TRUE(bot <= baz);
1053 EXPECT_TRUE(bot <= bar);
1054 EXPECT_TRUE(bot <= bat);
1055 EXPECT_TRUE(bot <= ter);
1057 // Joins
1058 EXPECT_EQ(top, top | top);
1059 EXPECT_EQ(top, top | foo);
1060 EXPECT_EQ(top, top | baz);
1061 EXPECT_EQ(top, top | bar);
1062 EXPECT_EQ(top, top | bat);
1063 EXPECT_EQ(top, top | ter);
1065 EXPECT_EQ(top, foo | top);
1066 EXPECT_EQ(foo, foo | foo);
1067 EXPECT_EQ(top, foo | baz);
1068 EXPECT_EQ(foo, foo | bar);
1069 EXPECT_EQ(foo, foo | bat);
1070 EXPECT_EQ(top, foo | ter);
1072 EXPECT_EQ(top, baz | top);
1073 EXPECT_EQ(top, baz | foo);
1074 EXPECT_EQ(baz, baz | baz);
1075 EXPECT_EQ(top, baz | bar);
1076 EXPECT_EQ(baz, baz | bat);
1077 EXPECT_EQ(baz, baz | ter);
1079 EXPECT_EQ(top, bar | top);
1080 EXPECT_EQ(foo, bar | foo);
1081 EXPECT_EQ(top, bar | baz);
1082 EXPECT_EQ(bar, bar | bar);
1083 EXPECT_EQ(foo, bar | bat);
1084 EXPECT_EQ(top, bar | ter);
1086 EXPECT_EQ(top, bat | top);
1087 EXPECT_EQ(foo, bat | foo);
1088 EXPECT_EQ(baz, bat | baz);
1089 EXPECT_EQ(foo, bat | bar);
1090 EXPECT_EQ(bat, bat | bat);
1091 EXPECT_EQ(baz, bat | ter);
1093 EXPECT_EQ(top, ter | top);
1094 EXPECT_EQ(top, ter | foo);
1095 EXPECT_EQ(baz, ter | baz);
1096 EXPECT_EQ(top, ter | bar);
1097 EXPECT_EQ(baz, ter | bat);
1098 EXPECT_EQ(ter, ter | ter);
1100 // Meets
1101 EXPECT_EQ(top, top & top);
1102 EXPECT_EQ(foo, top & foo);
1103 EXPECT_EQ(baz, top & baz);
1104 EXPECT_EQ(bar, top & bar);
1105 EXPECT_EQ(bat, top & bat);
1106 EXPECT_EQ(ter, top & ter);
1108 EXPECT_EQ(foo, foo & top);
1109 EXPECT_EQ(foo, foo & foo);
1110 EXPECT_EQ(bat, foo & baz);
1111 EXPECT_EQ(bar, foo & bar);
1112 EXPECT_EQ(bat, foo & bat);
1113 EXPECT_EQ(bot, foo & ter);
1115 EXPECT_EQ(baz, baz & top);
1116 EXPECT_EQ(bat, baz & foo);
1117 EXPECT_EQ(baz, baz & baz);
1118 EXPECT_EQ(bot, baz & bar);
1119 EXPECT_EQ(bat, baz & bat);
1120 EXPECT_EQ(ter, baz & ter);
1122 EXPECT_EQ(bar, bar & top);
1123 EXPECT_EQ(bar, bar & foo);
1124 EXPECT_EQ(bot, bar & baz);
1125 EXPECT_EQ(bar, bar & bar);
1126 EXPECT_EQ(bot, bar & bat);
1127 EXPECT_EQ(bot, bar & ter);
1129 EXPECT_EQ(bat, bat & top);
1130 EXPECT_EQ(bat, bat & foo);
1131 EXPECT_EQ(bat, bat & baz);
1132 EXPECT_EQ(bot, bat & bar);
1133 EXPECT_EQ(bat, bat & bat);
1134 EXPECT_EQ(bot, bat & ter);
1136 EXPECT_EQ(ter, ter & top);
1137 EXPECT_EQ(bot, ter & foo);
1138 EXPECT_EQ(ter, ter & baz);
1139 EXPECT_EQ(bot, ter & bar);
1140 EXPECT_EQ(bot, ter & bat);
1141 EXPECT_EQ(ter, ter & ter);
1144 TEST(Type, BespokeRanges) {
1146 * top(L)
1147 * / \
1148 * foo(L) baz
1149 * | \ / \
1150 * bar bat(L) ter
1152 * qop
1154 RO::EvalBespokeArrayLikeMode = 2;
1155 bespoke::Layout::ClearHierarchy();
1156 auto const foo_layout = ArrayLayout{
1157 bespoke::testing::makeDummyAbstractLayout("foo", {ArrayLayout::Bespoke()})
1159 auto const baz_layout = ArrayLayout{
1160 bespoke::testing::makeDummyAbstractLayout("baz", {ArrayLayout::Bespoke()})
1162 auto const bar_layout = ArrayLayout{
1163 bespoke::testing::makeDummyAbstractLayout("bar", {foo_layout})
1165 auto const bat_layout = ArrayLayout{
1166 bespoke::testing::makeDummyLayout("bat", {foo_layout, baz_layout})
1168 auto const ter_layout = ArrayLayout{
1169 bespoke::testing::makeDummyLayout("ter", {baz_layout})
1171 auto const qop_layout = ArrayLayout{
1172 bespoke::testing::makeDummyLayout("qup", {bar_layout})
1174 bespoke::selectBespokeLayouts();
1176 foo_layout.bespokeLayoutTest();
1177 baz_layout.bespokeLayoutTest();
1178 bar_layout.bespokeLayoutTest();
1179 bat_layout.bespokeLayoutTest();
1180 ter_layout.bespokeLayoutTest();
1181 qop_layout.bespokeLayoutTest();
1184 TEST(Type, PtrKinds) {
1185 auto const frameCell = TCell.ptr(Ptr::Frame);
1186 auto const frameUninit = TUninit.ptr(Ptr::Frame);
1187 auto const frameBool = TBool.ptr(Ptr::Frame);
1188 auto const unknownBool = TBool.ptr(Ptr::Ptr);
1189 auto const unknownCell = TCell.ptr(Ptr::Ptr);
1190 auto const stackObj = TObj.ptr(Ptr::Stk);
1191 auto const stackBool = TBool.ptr(Ptr::Stk);
1193 EXPECT_EQ("PtrToFrameCell", frameCell.toString());
1194 EXPECT_EQ("PtrToFrameBool", frameBool.toString());
1195 EXPECT_EQ("PtrToBool", unknownBool.toString());
1196 EXPECT_EQ("PtrToStkObj", stackObj.toString());
1197 EXPECT_EQ("Nullptr|PtrToPropCell",
1198 (TPtrToPropCell|TNullptr).toString());
1199 EXPECT_EQ("Nullptr|PtrToFieldCell",
1200 (TPtrToFieldCell|TNullptr).toString());
1202 EXPECT_EQ(Ptr::Frame, (frameUninit|frameBool).ptrKind());
1204 EXPECT_TRUE(frameBool <= unknownBool);
1205 EXPECT_TRUE(frameBool <= frameCell);
1206 EXPECT_FALSE(frameBool <= frameUninit);
1207 EXPECT_TRUE(frameBool.maybe(frameCell));
1208 EXPECT_TRUE(frameBool.maybe(unknownBool));
1209 EXPECT_TRUE(!frameUninit.maybe(frameBool));
1210 EXPECT_TRUE(frameUninit.maybe(frameCell));
1211 EXPECT_TRUE(!frameUninit.maybe(unknownBool));
1212 EXPECT_TRUE(!TPtrToUninit.maybe(TPtrToBool));
1213 EXPECT_FALSE(unknownBool <= frameBool);
1214 EXPECT_EQ(unknownBool, frameBool | unknownBool);
1216 EXPECT_EQ(unknownCell, frameCell | unknownBool);
1218 EXPECT_EQ(TBottom, frameBool & stackBool);
1219 EXPECT_EQ(frameBool, frameBool & unknownBool);
1221 EXPECT_EQ(Ptr::Prop,
1222 (TPtrToPropCell|TNullptr).ptrKind());
1223 EXPECT_EQ(TPtrToPropCell,
1224 (TPtrToPropCell|TNullptr) - TNullptr);
1225 EXPECT_EQ(Ptr::Field,
1226 (TPtrToFieldCell|TNullptr).ptrKind());
1227 EXPECT_EQ(TPtrToFieldCell,
1228 (TPtrToFieldCell|TNullptr) - TNullptr);
1230 auto const frameCellOrCell = frameCell | TCell;
1231 auto const stackOrArrOrInt = TArrLike.ptr(Ptr::Stk) | TInt;
1232 EXPECT_EQ(TInt | TArrLike, frameCellOrCell & stackOrArrOrInt);
1235 TEST(Type, ConstantPtrTypes) {
1236 std::vector<TypedValue> dicts;
1237 for (auto const key : {"foo", "bar"}) {
1238 DictInit dinit{1};
1239 dinit.set(StringData::Make(key), make_tv<KindOfBoolean>(true));
1240 auto const dict = dinit.toArray();
1241 VanillaDict::as(dict.get())->onSetEvalScalar();
1242 auto const static_dict = VanillaDict::CopyStatic(dict.get());
1243 dicts.push_back(make_persistent_array_like_tv(static_dict));
1246 // In typical iterator usage, the constant pointer may point to an invalid
1247 // TypedValue that's off the end of the array being iterated over.
1248 auto const arr_type1 = Type::cns(dicts[0]);
1249 auto const arr_type2 = Type::cns(dicts[1]);
1250 auto const tv = &dicts[2];
1251 auto const spec_ptr_type = (arr_type1 | arr_type2).ptr(Ptr::Elem);
1252 auto const base_ptr_type = spec_ptr_type.unspecialize();
1253 auto const cons_ptr_type = Type::cns(tv, spec_ptr_type);
1255 EXPECT_EQ("PtrToElemStaticDict=Vanilla", spec_ptr_type.toString());
1256 EXPECT_EQ("PtrToElemStaticDict", base_ptr_type.toString());
1257 auto const str = folly::format("PtrToElemStaticDict<TV: {}>", tv).str();
1258 EXPECT_EQ(str, cons_ptr_type.toString());
1260 // The specialized ptr type is not constant. The constant ptr type is not
1261 // specialized, because we can't represent both.
1262 EXPECT_TRUE(spec_ptr_type.isSpecialized());
1263 EXPECT_FALSE(spec_ptr_type.hasConstVal());
1264 EXPECT_FALSE(base_ptr_type.isSpecialized());
1265 EXPECT_FALSE(base_ptr_type.hasConstVal());
1266 EXPECT_FALSE(cons_ptr_type.isSpecialized());
1267 EXPECT_TRUE(cons_ptr_type.hasConstVal());
1269 // Because of these representation issues, the intersection of these two
1270 // types should just return the constant pointer type alone.
1271 EXPECT_FALSE(cons_ptr_type <= spec_ptr_type);
1272 EXPECT_TRUE(cons_ptr_type <= base_ptr_type);
1273 EXPECT_EQ(cons_ptr_type, cons_ptr_type & spec_ptr_type);
1274 EXPECT_EQ(cons_ptr_type, spec_ptr_type & cons_ptr_type);
1275 EXPECT_EQ(base_ptr_type, cons_ptr_type | spec_ptr_type);
1276 EXPECT_EQ(base_ptr_type, spec_ptr_type | cons_ptr_type);