Repository navigation
Expand file tree
/
Copy pathAssignHandler.cpp
More file actions
4963 lines (4495 loc) · 230 KB
/
Copy pathAssignHandler.cpp
File metadata and controls
4963 lines (4495 loc) · 230 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* PHPStanTurbo\AssignHandler — native implementation of
* PHPStan\Analyser\ExprHandler\AssignHandler.
*
* A DI service (#[AutowiredService]): the constructor keeps the twin's
* arginfo so Nette autowires it. processExpr() is registered as the class's
* handler entry; the public methods other handlers call — prepareTarget(),
* applyWrite(), processVirtualAssign() — are exported as
* pt_assign_handler_prepare_target() / _apply_write() /
* _process_virtual_assign() (Engine.h conventions). The twin's closures are
* native closures capturing exactly what the PHP closures capture.
*
* MutatingScope, ExpressionResult, ExpressionResultStorage, ExpressionContext,
* VariableFlow, VariableFlowBuilder, SpecifiedTypes, TypeSpecifierContext,
* the holders, ExprPrinter, VariableHandler and the Type family are called
* through their direct entries; the collaborators that stay PHP for now
* (NodeScopeResolver, the helpers and the other handlers, PreparedAssignTarget,
* AssignTargetWalkMode, InternalThrowPoint, the reflections) through the
* helpers in the "PHP collaborators" block below, one per called method, so
* each switches to a direct entry in one place when its port lands.
*/
#include "support.h"
#include "generated/AssignHandler.h"
#include "generated/PreparedAssignTarget.h"
namespace slots = ptdecl::AssignHandler::slot;
namespace sigs = ptdecl::AssignHandler::sig;
#include "zv.h"
#include "TypeTraits.h"
#include "TypeOps.h"
#include "Engine.h"
#include "AcceptorValues.h"
#include <cstring>
#include <utility>
zend_class_entry *pt_ce_assign_handler = nullptr;
/* the twin's private constants */
#define PT_AH_TERNARY_ARM_EXCLUDED_VALUES_LIMIT 3
#define PT_AH_DERIVED_CONDITIONAL_EXPRESSIONS_LIMIT 16
#define PT_AH_ARRAY_DIM_FETCH_WRITE_DEPTH_LIMIT 5
/* the twin's ASSIGN_OP_BINARY_OPS: each AssignOp class with the BinaryOp
* computing the value it writes */
struct pt_ah_assign_op_binary_op {
int assignOpClass;
int binaryOpClass;
const char *assignOpName;
const char *binaryOpName;
};
static const pt_ah_assign_op_binary_op pt_ah_assign_op_binary_ops[] = {
{ PT_CLASS_ASSIGN_OP_BITWISE_AND, PT_CLASS_BITWISE_AND_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd", "PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd" },
{ PT_CLASS_ASSIGN_OP_BITWISE_OR, PT_CLASS_BITWISE_OR_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr", "PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr" },
{ PT_CLASS_ASSIGN_OP_BITWISE_XOR, PT_CLASS_BITWISE_XOR_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor", "PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor" },
{ PT_CLASS_COALESCE_ASSIGN_OP_EXPR, PT_CLASS_COALESCE_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Coalesce", "PhpParser\\Node\\Expr\\BinaryOp\\Coalesce" },
{ PT_CLASS_ASSIGN_OP_CONCAT, PT_CLASS_CONCAT_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Concat", "PhpParser\\Node\\Expr\\BinaryOp\\Concat" },
{ PT_CLASS_ASSIGN_OP_DIV, PT_CLASS_DIV_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Div", "PhpParser\\Node\\Expr\\BinaryOp\\Div" },
{ PT_CLASS_ASSIGN_OP_MINUS, PT_CLASS_BINARY_OP_MINUS, "PhpParser\\Node\\Expr\\AssignOp\\Minus", "PhpParser\\Node\\Expr\\BinaryOp\\Minus" },
{ PT_CLASS_ASSIGN_OP_MOD, PT_CLASS_MOD_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Mod", "PhpParser\\Node\\Expr\\BinaryOp\\Mod" },
{ PT_CLASS_ASSIGN_OP_MUL, PT_CLASS_MUL_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Mul", "PhpParser\\Node\\Expr\\BinaryOp\\Mul" },
{ PT_CLASS_ASSIGN_OP_PLUS, PT_CLASS_BINARY_OP_PLUS, "PhpParser\\Node\\Expr\\AssignOp\\Plus", "PhpParser\\Node\\Expr\\BinaryOp\\Plus" },
{ PT_CLASS_ASSIGN_OP_POW, PT_CLASS_POW_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\Pow", "PhpParser\\Node\\Expr\\BinaryOp\\Pow" },
{ PT_CLASS_ASSIGN_OP_SHIFT_LEFT, PT_CLASS_SHIFT_LEFT_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft", "PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft" },
{ PT_CLASS_ASSIGN_OP_SHIFT_RIGHT, PT_CLASS_SHIFT_RIGHT_EXPR, "PhpParser\\Node\\Expr\\AssignOp\\ShiftRight", "PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight" },
};
/* the constant's value: a persistent immutable map of interned strings, as
* the engine references a class constant for the process lifetime */
static void pt_ah_assign_op_binary_ops_constant(zval *out)
{
size_t count = sizeof(pt_ah_assign_op_binary_ops) / sizeof(pt_ah_assign_op_binary_ops[0]);
HashTable *map = (HashTable *) pemalloc(sizeof(HashTable), 1);
zend_hash_init(map, (uint32_t) count, NULL, NULL, 1);
for (size_t i = 0; i < count; i++) {
zval value;
ZVAL_INTERNED_STR(&value, zend_string_init_interned(pt_ah_assign_op_binary_ops[i].binaryOpName, strlen(pt_ah_assign_op_binary_ops[i].binaryOpName), 1));
zend_hash_add_new(map, zend_string_init_interned(pt_ah_assign_op_binary_ops[i].assignOpName, strlen(pt_ah_assign_op_binary_ops[i].assignOpName), 1), &value);
}
GC_ADD_FLAGS(map, IS_ARRAY_IMMUTABLE);
GC_SET_REFCOUNT(map, 2);
ZVAL_ARR(out, map);
Z_TYPE_INFO_P(out) = IS_ARRAY;
}
/* VariableWrite::KIND_ASSIGN / KIND_READ_MODIFY_WRITE */
#define PT_AH_KIND_ASSIGN 1
#define PT_AH_KIND_READ_MODIFY_WRITE 2
/* {{{ propagation macros: every producer returns UNDEF (or false) with an
* exception pending, which the enclosing zv::Val-returning body forwards */
#define AH_VAL(name, expr) \
zv::Val name = (expr); \
if (UNEXPECTED(name.isUndef())) return zv::Val()
#define AH_SET(name, expr) \
do { \
zv::Val ah_tmp_ = (expr); \
if (UNEXPECTED(ah_tmp_.isUndef())) return zv::Val(); \
(name) = std::move(ah_tmp_); \
} while (0)
#define AH_OK(expr) \
do { \
if (UNEXPECTED(!(expr))) return zv::Val(); \
} while (0)
/* the same for bodies returning bool (false = pending exception) */
#define AH_VALB(name, expr) \
zv::Val name = (expr); \
if (UNEXPECTED(name.isUndef())) return false
#define AH_SETB(name, expr) \
do { \
zv::Val ah_tmp_ = (expr); \
if (UNEXPECTED(ah_tmp_.isUndef())) return false; \
(name) = std::move(ah_tmp_); \
} while (0)
#define AH_OKB(expr) \
do { \
if (UNEXPECTED(!(expr))) return false; \
} while (0)
/* }}} */
namespace {
/* {{{ node access */
/* $value instanceof <class-map class> */
inline bool ahIs(zval *value, int classIdx)
{
if (Z_TYPE_P(value) != IS_OBJECT) return false;
/* pt_class() caches the entry (autoloading it once) where
* pt_class_loaded() would repeat the name lookup while the class is not
* declared yet; loading an AST or virtual node class has no observable
* effect */
zend_class_entry *ce = pt_class(classIdx);
return ce != NULL && instanceof_function(Z_OBJCE_P(value), ce);
}
/* $value instanceof <shadowing class> */
inline bool ahIsCe(zval *value, zend_class_entry *ce)
{
return Z_TYPE_P(value) == IS_OBJECT && ce != NULL && instanceof_function(Z_OBJCE_P(value), ce);
}
zval pt_ah_undef_zval;
/* a declared property of a node / value object (dereferenced; an UNDEF zval
* when the value is no object or its class declares no such property) */
zval *ahPropResolve(pt_property_site &site, zval *object, const char *name, size_t len)
{
if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
ZVAL_UNDEF(&pt_ah_undef_zval);
return &pt_ah_undef_zval;
}
zval *slot = pt_property_cached(site, Z_OBJ_P(object), name, len);
if (UNEXPECTED(slot == NULL)) {
ZVAL_UNDEF(&pt_ah_undef_zval);
return &pt_ah_undef_zval;
}
ZVAL_DEREF(slot);
return slot;
}
/* $object->name through a property site of its own (one per use) */
#define AH_PROP(object, name) ([](zval *ah_object_) -> zval * { static pt_property_site ah_site_; return ahPropResolve(ah_site_, ah_object_, PT_LC(#name)); }(object))
/* the string name of a Variable node, NULL when it is an Expr */
inline zend_string *ahVariableName(zval *variable)
{
zval *name = AH_PROP(variable, name);
return Z_TYPE_P(name) == IS_STRING ? Z_STR_P(name) : NULL;
}
/* $expr instanceof Variable && is_string($expr->name) */
inline zend_string *ahStringVariableName(zval *expr)
{
if (!ahIs(expr, PT_CLASS_VARIABLE)) return NULL;
return ahVariableName(expr);
}
/* $call->getArgs() of a CallLike (its raw args) — the table or NULL */
inline HashTable *ahArgs(zval *call)
{
zval *args = AH_PROP(call, args);
return Z_TYPE_P(args) == IS_ARRAY ? Z_ARRVAL_P(args) : NULL;
}
inline uint32_t ahArgCount(zval *call)
{
HashTable *args = ahArgs(call);
return args != NULL ? zend_hash_num_elements(args) : 0;
}
/* $call->getArgs()[$index]->value (an UNDEF zval when absent) */
inline zval *ahArgValue(zval *call, zend_ulong index)
{
HashTable *args = ahArgs(call);
zval *arg = args != NULL ? zend_hash_index_find(args, index) : NULL;
if (arg == NULL) {
ZVAL_UNDEF(&pt_ah_undef_zval);
return &pt_ah_undef_zval;
}
ZVAL_DEREF(arg);
return AH_PROP(arg, value);
}
/* $funcCall->name instanceof Name && $funcCall->name->toLowerString() ===
* $literal (strtolower() is ASCII-only, as the _ci comparison) */
inline bool ahNameIs(zval *name, const char *literal, size_t len)
{
if (!ahIs(name, PT_CLASS_NAME)) return false;
zval *string = AH_PROP(name, name);
return Z_TYPE_P(string) == IS_STRING && zend_binary_strcasecmp(Z_STRVAL_P(string), Z_STRLEN_P(string), literal, len) == 0;
}
/* spl_object_id() of a node */
inline zend_ulong ahObjectId(zval *object)
{
return (zend_ulong) Z_OBJ_HANDLE_P(object);
}
/* }}} */
/* {{{ values */
/* the PT_TRI_* value of a TrinaryLogic, IsSuperTypeOfResult or
* AcceptsResult (their yes()/maybe()/no()); -1 = pending exception */
zend_long ahTri(zval *value)
{
if (EXPECTED(Z_TYPE_P(value) == IS_OBJECT)) {
zend_object *object = Z_OBJ_P(value);
if (EXPECTED(object->ce == pt_ce_trinary)) return pt_trinary_value(object);
if (object->ce == pt_ce_is_super_type_of_result || object->ce == pt_ce_accepts_result) return pt_result_value(object);
zv::Val yes = pt_type_call(object, PT_LC("yes"), 0, NULL);
if (UNEXPECTED(yes.isUndef())) return -1;
if (zend_is_true(yes.raw())) return PT_TRI_YES;
zv::Val no = pt_type_call(object, PT_LC("no"), 0, NULL);
if (UNEXPECTED(no.isUndef())) return -1;
return zend_is_true(no.raw()) ? PT_TRI_NO : PT_TRI_MAYBE;
}
zend_throw_error(NULL, "Call to a member function yes() on %s", zend_zval_value_name(value));
return -1;
}
/* a borrowed TrinaryLogic singleton */
inline zval *ahTrinary(zend_long value)
{
return pt_trinary_singleton(value);
}
/* $type->method(...$argv) on a Type (the op's direct entry when the class
* registered it); UNDEF = pending exception */
inline zv::Val ahTypeOp(zval *type, pt_type_op_id op, uint32_t argc, zval *argv)
{
if (UNEXPECTED(Z_TYPE_P(type) != IS_OBJECT)) {
zend_throw_error(NULL, "Call to a member function %s() on %s", pt_type_op_infos[op].lcname, zend_zval_value_name(type));
return zv::Val();
}
return pt_type_op(Z_OBJ_P(type), op, argc, argv);
}
/* the PT_TRI_* value of a trinary-returning op; -1 = pending exception */
inline zend_long ahTypeOpTri(zval *type, pt_type_op_id op, uint32_t argc, zval *argv)
{
zv::Val result = ahTypeOp(type, op, argc, argv);
if (UNEXPECTED(result.isUndef())) return -1;
return ahTri(result.raw());
}
/* $object->method(...$argv) by name */
inline zv::Val ahCall(zval *object, const char *lcname, size_t len, uint32_t argc, zval *argv)
{
if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
zend_throw_error(NULL, "Call to a member function %s() on %s", lcname, zend_zval_value_name(object));
return zv::Val();
}
return pt_type_call(Z_OBJ_P(object), lcname, len, argc, argv);
}
/* the PT_TRI_* value of a trinary-returning method by name; -1 = pending
* exception */
inline zend_long ahCallTri(zval *object, const char *lcname, size_t len, uint32_t argc, zval *argv)
{
zv::Val result = ahCall(object, lcname, len, argc, argv);
if (UNEXPECTED(result.isUndef())) return -1;
return ahTri(result.raw());
}
/* $a->equals($b); false = pending exception */
[[nodiscard]] inline bool ahEquals(zval *a, zval *b, bool &out)
{
zv::Val result = ahTypeOp(a, PT_OP_EQUALS, 1, b);
if (UNEXPECTED(result.isUndef())) return false;
out = Z_TYPE_P(result.raw()) == IS_TRUE;
return true;
}
/* $into = array_merge($into, $more) */
[[nodiscard]] bool ahMerge(zv::Val &into, zval *more)
{
if (UNEXPECTED(Z_TYPE_P(more) != IS_ARRAY)) {
zend_type_error("array_merge(): Argument #2 must be of type array, %s given", zend_zval_value_name(more));
return false;
}
HashTable *intoTable = Z_ARRVAL_P(into.raw());
HashTable *moreTable = Z_ARRVAL_P(more);
bool intoIsList = HT_IS_PACKED(intoTable) && HT_IS_WITHOUT_HOLES(intoTable);
if (zend_hash_num_elements(moreTable) == 0 && (intoIsList || zend_hash_num_elements(intoTable) == 0)) {
if (zend_hash_num_elements(intoTable) == 0) into = zv::Val(zv::Arr::empty());
return true;
}
if (zend_hash_num_elements(intoTable) == 0 && HT_IS_PACKED(moreTable) && HT_IS_WITHOUT_HOLES(moreTable)) {
into = zv::Val::copyOf(zv::Ref(more));
return true;
}
zv::Arr merged = zv::Arr::create(zend_hash_num_elements(intoTable) + zend_hash_num_elements(moreTable));
for (HashTable *table : { intoTable, moreTable }) {
for (auto entry : zv::TableRef(table)) {
if (entry.hasStringKey()) {
merged.set(entry.stringKey(), zv::Val::copyOf(entry.value()));
} else {
merged.push(entry.value());
}
}
}
into = zv::Val(std::move(merged));
return true;
}
/* $list[] = $value on an owned array value */
inline void ahPush(zv::Val &list, zv::Val value)
{
zval *raw = list.raw();
SEPARATE_ARRAY(raw);
zval v = value.take();
zend_hash_next_index_insert(Z_ARRVAL_P(raw), &v);
}
inline void ahPushRef(zv::Val &list, zval *value)
{
zval *raw = list.raw();
SEPARATE_ARRAY(raw);
Z_TRY_ADDREF_P(value);
zend_hash_next_index_insert(Z_ARRVAL_P(raw), value);
}
/* $table[$index] = $value on an owned array value */
inline void ahSetIndex(zv::Val &table, zend_ulong index, zval *value)
{
zval *raw = table.raw();
SEPARATE_ARRAY(raw);
Z_TRY_ADDREF_P(value);
zend_hash_index_update(Z_ARRVAL_P(raw), index, value);
}
/* $table[$key] = $value (symtable semantics) on an owned array value */
inline void ahSetKey(zv::Val &table, zend_string *key, zval *value)
{
zval *raw = table.raw();
SEPARATE_ARRAY(raw);
Z_TRY_ADDREF_P(value);
zend_symtable_update(Z_ARRVAL_P(raw), key, value);
}
/* [$a, $b] */
inline zv::Val ahPair(zval *a, zval *b)
{
zv::Arr pair = zv::Arr::create(2);
pair.push(zv::Ref(a));
pair.push(zv::Ref(b));
return zv::Val(std::move(pair));
}
inline zv::Val ahEmptyArray()
{
return zv::Val(zv::Arr::empty());
}
inline zv::Val ahNull()
{
return zv::Val::null();
}
/* $scope->hasVariableType($name)->no() ? new ErrorType() : $scope->getVariableType($name) */
zv::Val ahVariableTypeOrError(zval *scope, zend_string *name)
{
AH_VAL(has, pt_mutating_scope_has_variable_type(Z_OBJ_P(scope), name));
zend_long hasValue = ahTri(has.raw());
if (UNEXPECTED(hasValue < 0)) return zv::Val();
if (hasValue == PT_TRI_NO) return pt_type_new_error_type();
return pt_mutating_scope_get_variable_type(Z_OBJ_P(scope), name);
}
/* $scope->nativeTypesPromoted; false = pending exception */
[[nodiscard]] inline bool ahPromoted(zval *scope, bool &out)
{
return pt_mutating_scope_native_types_promoted(Z_OBJ_P(scope), out);
}
/* $result->getTypeOnScope($scope, $scope->nativeTypesPromoted) */
zv::Val ahTypeOnScope(zval *result, zval *scope)
{
bool promoted;
AH_OK(ahPromoted(scope, promoted));
return pt_expression_result_get_type_on_scope(result, scope, promoted);
}
/* $nativeTypesPromoted ? $scope->doNotTreatPhpDocTypesAsCertain() : $scope */
zv::Val ahFlavourScope(zval *scope, bool nativeTypesPromoted)
{
if (nativeTypesPromoted) return pt_mutating_scope_do_not_treat_phpdoc_types_as_certain(Z_OBJ_P(scope));
return zv::Val::copyOf(zv::Ref(scope));
}
/* $write->getId() of a VariableWrite: the slot of the PHP class, the method
* otherwise */
zv::Val ahVariableWriteId(zval *write)
{
bool error = false;
const pt_variable_write_slots *writeSlots = pt_variable_write_slots_of(Z_OBJ_P(write), error);
if (writeSlots != NULL) return zv::Val::copyOf(zv::ObjRef(write).propAtOffset(writeSlots->id));
if (UNEXPECTED(error)) return zv::Val();
return pt_type_call(Z_OBJ_P(write), PT_LC("getid"), 0, NULL);
}
/* }}} */
/* $result->getScope() / ->getThrowPoints() / ->getImpurePoints() as owned
* values (the borrowed AnalyserValues.h readers, copied) */
inline zv::Val ahResultRead(zval *value, zv::Val &hold)
{
if (UNEXPECTED(value == NULL)) return zv::Val();
if (!hold.isUndef()) return std::move(hold);
return zv::Val::copyOf(zv::Ref(value));
}
inline zv::Val ahResultScope(zval *result)
{
zv::Val hold;
zval *value = pt_expression_result_scope(result, hold);
return ahResultRead(value, hold);
}
inline zv::Val ahResultThrowPoints(zval *result)
{
zv::Val hold;
zval *value = pt_expression_result_throw_points(result, hold);
return ahResultRead(value, hold);
}
inline zv::Val ahResultImpurePoints(zval *result)
{
zv::Val hold;
zval *value = pt_expression_result_impure_points(result, hold);
return ahResultRead(value, hold);
}
/* {{{ the collaborators — the native ones through their direct entries, the
* PHP ones through one cached method site each (switch them to direct entries
* once they are ported) */
/* $nodeScopeResolver->processExprNode($stmt, $expr, $scope, $storage, $nodeCallback, $context) */
zv::Val nsrProcessExprNode(zval *nsr, zval *stmt, zval *expr, zval *scope, zval *storage, zval *nodeCallback, zval *context)
{
return pt_node_scope_resolver_process_expr_node(nsr, stmt, expr, scope, storage, nodeCallback, context);
}
/* $nodeScopeResolver->callNodeCallback($nodeCallback, $node, $scope, $storage); false = pending exception */
[[nodiscard]] bool nsrCallNodeCallback(zval *nsr, zval *nodeCallback, zval *node, zval *scope, zval *storage)
{
return pt_node_scope_resolver_call_node_callback(nsr, nodeCallback, node, scope, storage);
}
/* $nodeScopeResolver->storeExpressionResult($storage, $expr, $result); false = pending exception */
[[nodiscard]] bool nsrStoreExpressionResult(zval *nsr, zval *storage, zval *expr, zval *result)
{
return pt_node_scope_resolver_store_expression_result(nsr, storage, expr, result);
}
/* $nodeScopeResolver->getAssignedVariables($expr) */
zv::Val nsrGetAssignedVariables(zval *nsr, zval *expr)
{
return pt_node_scope_resolver_get_assigned_variables(nsr, expr);
}
/* $nodeScopeResolver->observingTemplateArgumentFrame($scope) */
zv::Val nsrObservingTemplateArgumentFrame(zval *nsr, zval *scope)
{
return pt_node_scope_resolver_observing_template_argument_frame(nsr, scope);
}
/* $nodeScopeResolver->lookForSetAllowedUndefinedExpressions($scope, $expr) */
zv::Val nsrLookForSetAllowedUndefinedExpressions(zval *nsr, zval *scope, zval *expr)
{
return pt_node_scope_resolver_look_for_set_allowed_undefined_expressions(nsr, scope, expr);
}
/* $nodeScopeResolver->readStoredResult($expr, $storage) */
zv::Val nsrReadStoredResult(zval *nsr, zval *expr, zval *storage)
{
return pt_node_scope_resolver_read_stored_result(nsr, expr, storage);
}
/* $nodeScopeResolver->readTypeOfMaybeStored($expr, $scope) */
zv::Val nsrReadTypeOfMaybeStored(zval *nsr, zval *expr, zval *scope)
{
return pt_node_scope_resolver_read_type_of_maybe_stored(nsr, expr, scope);
}
/* $nodeScopeResolver->findScopeStateType($expr, $scope) */
zv::Val nsrFindScopeStateType(zval *nsr, zval *expr, zval *scope)
{
return pt_node_scope_resolver_find_scope_state_type(nsr, expr, scope);
}
/* $nodeScopeResolver->processSyntheticOnDemand($expr, $scope) */
zv::Val nsrProcessSyntheticOnDemand(zval *nsr, zval *expr, zval *scope)
{
return pt_node_scope_resolver_process_synthetic_on_demand(nsr, expr, scope);
}
/* $nodeScopeResolver->readScopeStateOrSyntheticType($expr, $scope) */
zv::Val nsrReadScopeStateOrSyntheticType(zval *nsr, zval *expr, zval *scope)
{
return pt_node_scope_resolver_read_scope_state_or_synthetic_type(nsr, expr, scope);
}
/* $nodeScopeResolver->processExprOnDemand($expr, $scope, $storage) */
zv::Val nsrProcessExprOnDemand(zval *nsr, zval *expr, zval *scope, zval *storage)
{
return pt_node_scope_resolver_process_expr_on_demand(nsr, expr, scope, storage);
}
/* $nonNullabilityHelper->ensureNonNullability($scope, $expr)->getScope() */
zv::Val nnhEnsureNonNullabilityScope(zval *helper, zval *scope, zval *expr)
{
static pt_method_site scopeSite;
AH_VAL(result, pt_non_nullability_helper_ensure_non_nullability(helper, scope, expr));
return pt_call_method_cached(scopeSite, Z_OBJ_P(result.raw()), PT_LC("getscope"), 0, NULL);
}
/* $arrayDimFetchHandler->composeResult($nodeScopeResolver, $stmt, $expr, $dimResult, $varResult, $storage, $context, $beforeScope) */
zv::Val adfhComposeResult(zval *handler, zval *nsr, zval *stmt, zval *expr, zval *dimResult, zval *varResult, zval *storage, zval *context, zval *beforeScope)
{
return pt_array_dim_fetch_handler_compose_result(handler, nsr, stmt, expr, dimResult, varResult, storage, context, beforeScope);
}
/* $propertyFetchHandler->composeResult($nodeScopeResolver, $expr, $varResult, $nameResult, $scopeBeforeVar, $beforeScope) */
zv::Val pfhComposeResult(zval *handler, zval *nsr, zval *expr, zval *varResult, zval *nameResult, zval *scopeBeforeVar, zval *beforeScope)
{
return pt_property_fetch_handler_compose_result(handler, nsr, expr, varResult, nameResult, scopeBeforeVar, beforeScope);
}
/* $staticPropertyFetchHandler->composeResult($expr, $classResult, $nameResult, $beforeScope) */
zv::Val spfhComposeResult(zval *handler, zval *expr, zval *classResult, zval *nameResult, zval *beforeScope)
{
return pt_static_property_fetch_handler_compose_result(handler, expr, classResult, nameResult, beforeScope);
}
/* $defaultNarrowingHelper->createSubjectTypes($s, $subject, $subjectResult, $type, $context) */
zv::Val dnhCreateSubjectTypes(zval *helper, zval *scope, zval *subject, zval *subjectResult, zval *type, zval *context)
{
return pt_default_narrowing_helper_create_subject_types(helper, scope, subject, subjectResult, type, context);
}
/* $defaultNarrowingHelper->specifyDefaultTypes($expr, $context) */
zv::Val dnhSpecifyDefaultTypes(zval *helper, zval *expr, zval *context)
{
return pt_default_narrowing_helper_specify_default_types(helper, expr, context);
}
/* $defaultNarrowingHelper->specifyTypesForNode($scope, $node, $context) */
zv::Val dnhSpecifyTypesForNode(zval *helper, zval *scope, zval *node, zval *context)
{
return pt_default_narrowing_helper_specify_types_for_node(helper, scope, node, context);
}
/* $defaultNarrowingHelper->captureChainResults($node, $storage, $chainResults) — $chainResults by reference; false = pending exception */
[[nodiscard]] bool dnhCaptureChainResults(zval *helper, zval *node, zval *storage, zv::Val &chainResults)
{
zval reference;
ZVAL_NEW_REF(&reference, chainResults.raw());
ZVAL_UNDEF(chainResults.raw());
bool ok = pt_default_narrowing_helper_capture_chain_results(helper, node, storage, &reference);
chainResults = zv::Val::copyOf(zv::Ref(Z_REFVAL(reference)));
zval_ptr_dtor(&reference);
return ok;
}
/* $identicalNarrowingHelper->captureFirstArgResult($side, $storage) */
zv::Val inhCaptureFirstArgResult(zval *helper, zval *side, zval *storage)
{
return pt_identical_narrowing_helper_capture_first_arg_result(helper, side, storage);
}
/* $identicalNarrowingHelper->specifyIdenticalAgainstType($subject, $subjectResult, $constantExpr, $constantType, $context, $evaluationScope, $subjectArgResult, $identicalTypeCallback) */
zv::Val inhSpecifyIdenticalAgainstType(zval *helper, zval *subject, zval *subjectResult, zval *constantExpr, zval *constantType, zval *context, zval *evaluationScope, zval *subjectArgResult, zval *identicalTypeCallback)
{
return pt_identical_narrowing_helper_specify_identical_against_type(helper, subject, subjectResult, constantExpr, constantType, context, evaluationScope, subjectArgResult, identicalTypeCallback);
}
/* $ternaryHandler->getCapturedResults($expr) */
zv::Val thGetCapturedResults(zval *handler, zval *expr)
{
return pt_ternary_handler_get_captured_results(handler, expr);
}
/* $matchHandler->getCapturedArmScopesAndTypes($expr) (MatchHandler.cpp) */
zv::Val mhGetCapturedArmScopesAndTypes(zval *handler, zval *expr)
{
return pt_match_handler_get_captured_arm_scopes_and_types(handler, expr);
}
/* $varAnnotationProcessor->processVarAnnotation($scope, $variableNames, $stmt, $changed) — $changed by reference */
zv::Val vapProcessVarAnnotation(zval *processor, zval *scope, zval *variableNames, zval *stmt, bool &changed)
{
return pt_var_annotation_processor_process_var_annotation(processor, scope, variableNames, stmt, &changed);
}
/* $arrayUnpackingHelper->getImplicitIndexCount($type) */
zv::Val auhGetImplicitIndexCount(zval *helper, zval *type)
{
static pt_method_site site;
return pt_call_method_cached(site, Z_OBJ_P(helper), PT_LC("getimplicitindexcount"), 1, type);
}
/* $statementsHandler->processStmtVarAnnotation($nodeScopeResolver, $scope, $storage, $stmt, $defaultExpr, $nodeCallback) */
zv::Val shProcessStmtVarAnnotation(zval *handler, zval *nsr, zval *scope, zval *storage, zval *stmt, zval *defaultExpr, zval *nodeCallback)
{
return pt_statements_handler_process_stmt_var_annotation(handler, nsr, scope, storage, stmt, defaultExpr, nodeCallback);
}
/* $templateArgumentObserver->collectSend($declared, $actual) */
zv::Val taoCollectSend(zval *observer, zval *declared, zval *actual)
{
return pt_template_argument_observer_collect_send(observer, declared, actual);
}
/* $templateArgumentObserver->collectArgument($parameterType, $argumentType) */
zv::Val taoCollectArgument(zval *observer, zval *parameterType, zval *argumentType)
{
return pt_template_argument_observer_collect_argument(observer, parameterType, argumentType, false);
}
/* TemplateArgumentConstraints::createEmpty() */
zv::Val tacCreateEmpty()
{
return pt_template_argument_constraints_create_empty();
}
/* $constraints->merge($other) */
zv::Val tacMerge(zval *constraints, zval *other)
{
return pt_template_argument_constraints_merge(constraints, other);
}
/* $methodThrowPointHelper->getThrowPointsForCallOnType($scope, $context, $calledOnType, $methodCall) */
zv::Val mtphGetThrowPointsForCallOnType(zval *helper, zval *scope, zval *context, zval *calledOnType, zval *methodCall)
{
return pt_method_throw_point_helper_get_throw_points_for_call_on_type(helper, scope, context, calledOnType, methodCall);
}
/* $propertyHookThrowPointsResolver->getThrowPointsFromPropertyHook($scope, $propertyFetch, $propertyReflection, 'set') */
zv::Val phtprGetThrowPointsFromSetHook(zval *resolver, zval *scope, zval *propertyFetch, zval *propertyReflection)
{
zv::Str hookType = zv::Str::adopt(zend_string_init(PT_LC("set"), 0));
return pt_property_hook_throw_points_resolver_get_throw_points_from_property_hook(resolver, scope, propertyFetch, propertyReflection, hookType.get());
}
/* $propertyReflectionFinder->findPropertyReflectionFromNodeWithHolderType($propertyFetch, $propertyHolderType, $scope) */
zv::Val prfFindPropertyReflectionFromNodeWithHolderType(zval *finder, zval *propertyFetch, zval *propertyHolderType, zval *scope)
{
static pt_method_site site;
zv::Args argv{propertyFetch, propertyHolderType, scope};
return pt_call_method_cached(site, Z_OBJ_P(finder), PT_LC("findpropertyreflectionfromnodewithholdertype"), 3, argv);
}
/* $virtualExprResultHelper->createTypeExprResult($scope, $expr) */
zv::Val vehCreateTypeExprResult(zval *helper, zval *scope, zval *expr)
{
return pt_virtual_expr_result_helper_create_type_expr_result(helper, scope, expr);
}
/* $phpVersion->supportsPropertyHooks(); false = pending exception */
[[nodiscard]] bool phpVersionSupportsPropertyHooks(zval *phpVersion, bool &out)
{
return pt_php_version_supports_property_hooks(phpVersion, out);
}
/* VirtualAssignNodeCallback::create($nodeCallback) */
zv::Val vancCreate(zval *nodeCallback)
{
static pt_method_site site;
return pt_call_static_cached(site, PT_CLASS_VIRTUAL_ASSIGN_NODE_CALLBACK, PT_LC("create"), 1, nodeCallback);
}
/* InternalThrowPoint::createImplicit($scope, $node) */
zv::Val itpCreateImplicit(zval *scope, zval *node)
{
return pt_internal_throw_point_create_implicit(scope, node);
}
/* InternalThrowPoint::createExplicit($scope, $type, $node, $canContainAnyThrowable) */
zv::Val itpCreateExplicit(zval *scope, zval *type, zval *node, bool canContainAnyThrowable)
{
return pt_internal_throw_point_create_explicit(scope, type, node, canContainAnyThrowable);
}
/* AssignTargetWalkMode::assign() / virtualAssign() */
zv::Val walkModeAssign()
{
return pt_assign_target_walk_mode_new(true, false, false);
}
zv::Val walkModeVirtualAssign()
{
return pt_assign_target_walk_mode_new(false, false, false);
}
/* $mode->enterExpressionAssign() / producesTargetReadResult() /
* issetSemanticsForRead() (the slots of the native class; a foreign mode's
* getter cannot fail in a way the twin would observe) */
inline bool walkModeEnterExpressionAssign(zval *mode)
{
bool out = false;
(void) pt_assign_target_walk_mode_enter_expression_assign(mode, out);
return out;
}
inline bool walkModeProducesTargetReadResult(zval *mode)
{
bool out = false;
(void) pt_assign_target_walk_mode_produces_target_read_result(mode, out);
return out;
}
inline bool walkModeIssetSemanticsForRead(zval *mode)
{
bool out = false;
(void) pt_assign_target_walk_mode_isset_semantics_for_read(mode, out);
return out;
}
/* new NoopNodeCallback() */
zv::Val newNoopNodeCallback()
{
return pt_type_new(PT_CLASS_NOOP_NODE_CALLBACK, 0, NULL);
}
/* (new NodeFinder())->findInstanceOf([$node], Variable::class) */
zv::Val nodeFinderFindVariables(zval *node)
{
static pt_method_site site;
AH_VAL(finder, pt_type_new(PT_CLASS_NODE_FINDER, 0, NULL));
zend_class_entry *variableCe = pt_class(PT_CLASS_VARIABLE);
if (UNEXPECTED(variableCe == NULL)) return zv::Val();
zv::Arr nodes = zv::Arr::create(1);
nodes.push(zv::Ref(node));
zv::Val className = zv::Val::string(variableCe->name);
zv::Args argv{nodes.raw(), className.raw()};
return pt_call_method_cached(site, Z_OBJ_P(finder.raw()), PT_LC("findinstanceof"), 2, argv);
}
/* {{{ PreparedAssignTarget — the final class's constructor and its private
* slots (read by name through one property site each: the declared order of
* the PHP twin and of a later native port agree, but the offsets are
* resolved rather than assumed) */
struct PreparedTarget
{
const char *kind;
size_t kindLen;
zval *var;
zval *assignedExpr;
zval *beforeScope;
zval *scope;
bool enterExpressionAssign;
bool isAssignOp;
bool hasYield;
zval *throwPoints;
zval *impurePoints;
bool isAlwaysTerminating;
zval *rootVar = NULL;
zval *varResult = NULL;
zval *dimFetchStack = NULL;
zval *assignedPropertyExpr = NULL;
zval *offsetTypes = NULL;
zval *offsetNativeTypes = NULL;
zval *existingOffsetTypes = NULL;
zval *existingOffsetNativeTypes = NULL;
zval *offsetSetTargetResult = NULL;
zval *objectResult = NULL;
zval *propertyName = NULL;
zval *propertyHolderType = NULL;
zval *targetReadResult = NULL;
zval *targetChainResults = NULL;
zval *variableNameResult = NULL;
zval *dependencies = NULL;
};
/* new PreparedAssignTarget(...) */
zv::Val preparedAssignTargetNew(const PreparedTarget &t)
{
zval null = {};
ZVAL_NULL(&null);
zval emptyArray;
ZVAL_EMPTY_ARRAY(&emptyArray);
auto orNull = [&](zval *value) { return value != NULL ? value : &null; };
zv::Val kind = zv::Val::string(t.kind, t.kindLen);
zv::Args argv{
kind.raw(), t.var, t.assignedExpr, t.beforeScope, t.scope, t.enterExpressionAssign, t.isAssignOp, t.hasYield, t.throwPoints, t.impurePoints, t.isAlwaysTerminating,
orNull(t.rootVar), orNull(t.varResult), orNull(t.dimFetchStack), orNull(t.assignedPropertyExpr), orNull(t.offsetTypes), orNull(t.offsetNativeTypes), orNull(t.existingOffsetTypes), orNull(t.existingOffsetNativeTypes), orNull(t.offsetSetTargetResult), orNull(t.objectResult), orNull(t.propertyName), orNull(t.propertyHolderType), orNull(t.targetReadResult), t.targetChainResults != NULL ? t.targetChainResults : &emptyArray, orNull(t.variableNameResult),
orNull(t.dependencies),
};
return pt_prepared_assign_target_new(27, argv);
}
/* the getters: the borrowed slots of the native class (its private
* properties by name for any other object — never in a live walk) */
inline zval *ahTargetSlot(zval *target, uint32_t slot, pt_property_site &site, const char *name, size_t len)
{
if (EXPECTED(Z_TYPE_P(target) == IS_OBJECT && Z_OBJCE_P(target) == pt_ce_prepared_assign_target)) return OBJ_PROP_NUM(Z_OBJ_P(target), slot);
return ahPropResolve(site, target, name, len);
}
#define AH_TARGET(target, name) ([](zval *ah_target_) -> zval * { static pt_property_site ah_site_; return ahTargetSlot(ah_target_, ptdecl::PreparedAssignTarget::slot::name, ah_site_, PT_LC(#name)); }(target))
/* $result->getDependencies(), owned (PHP null for null); UNDEF = pending exception */
zv::Val ahResultDependencies(zval *result)
{
zv::Val hold;
zval *dependencies = pt_expression_result_dependencies(result, hold);
if (UNEXPECTED(dependencies == NULL)) return zv::Val();
return zv::Val::copyOf(zv::Ref(dependencies));
}
/* a getter that throws ShouldNotHappenException on null; NULL = pending exception */
inline zval *ahRequire(zval *value)
{
if (UNEXPECTED(Z_TYPE_P(value) == IS_NULL || Z_TYPE_P(value) == IS_UNDEF)) {
pt_throw_should_not_happen();
return NULL;
}
return value;
}
/* }}} */
/* {{{ node and value constructors */
/* new Variable($name) */
zv::Val newVariable(zend_string *name)
{
zv::Args argv{name};
return pt_type_new(PT_CLASS_VARIABLE, 1, argv);
}
/* new ArrayDimFetch($var, $dim) */
zv::Val newArrayDimFetch(zval *var, zval *dim)
{
zv::Args argv{var, dim};
return pt_type_new(PT_CLASS_ARRAY_DIM_FETCH, 2, argv);
}
/* new TypeExpr($type) */
zv::Val newTypeExpr(zval *type)
{
return pt_type_new(PT_CLASS_TYPE_EXPR, 1, type);
}
/* new NativeTypeExpr($phpdocType, $nativeType) */
zv::Val newNativeTypeExpr(zval *phpdocType, zval *nativeType)
{
zv::Args argv{phpdocType, nativeType};
return pt_type_new(PT_CLASS_NATIVE_TYPE_EXPR, 2, argv);
}
/* new SetExistingOffsetValueTypeExpr($var, $dim, $value) / new SetOffsetValueTypeExpr($var, $dim, $value) */
zv::Val newSetExistingOffsetValueTypeExpr(zval *var, zval *dim, zval *value)
{
zv::Args argv{var, dim, value};
return pt_type_new(PT_CLASS_SET_EXISTING_OFFSET_VALUE_TYPE_EXPR, 3, argv);
}
zv::Val newSetOffsetValueTypeExpr(zval *var, zval *dim, zval *value)
{
zv::Args argv{var, dim, value};
return pt_type_new(PT_CLASS_SET_OFFSET_VALUE_TYPE_EXPR, 3, argv);
}
/* new IntertwinedVariableByReferenceWithExpr($variableName, $expr, $assignedExpr) */
zv::Val newIntertwined(zend_string *variableName, zval *expr, zval *assignedExpr)
{
zv::Args argv{variableName, expr, assignedExpr};
return pt_type_new(PT_CLASS_INTERTWINED_VAR, 3, argv);
}
/* new MethodCall($var, $name) */
zv::Val newMethodCall(zval *var, const char *name, size_t len)
{
zv::Val nameValue = zv::Val::string(name, len);
zv::Args argv{var, nameValue.raw()};
return pt_type_new(PT_CLASS_METHOD_CALL, 2, argv);
}
/* new VariableAssignNode($variable, $assignedExpr) */
zv::Val newVariableAssignNode(zval *variable, zval *assignedExpr)
{
zv::Args argv{variable, assignedExpr};
return pt_type_new(PT_CLASS_VARIABLE_ASSIGN_NODE, 2, argv);
}
/* new PropertyAssignNode($propertyFetch, $assignedExpr, $assignOp) */
zv::Val newPropertyAssignNode(zval *propertyFetch, zval *assignedExpr, bool assignOp)
{
zv::Args argv{propertyFetch, assignedExpr, assignOp};
return pt_type_new(PT_CLASS_PROPERTY_ASSIGN_NODE, 3, argv);
}
/* new ImpurePoint($scope, $node, $identifier, $description, $certain) */
zv::Val newImpurePoint(zval *scope, zval *node, zval *identifier, zval *description, bool certain)
{
return pt_impure_point_new(scope, node, Z_STR_P(identifier), Z_STR_P(description), certain);
}
/* new ObjectType($className) */
zv::Val newObjectType(const char *className, size_t len)
{
zv::Val name = zv::Val::string(className, len);
return pt_type_new_object_type(name.raw());
}
/* new ConstantArrayType([], []) */
zv::Val newEmptyConstantArrayType()
{
zval out;
zval keys;
zval values;
ZVAL_EMPTY_ARRAY(&keys);
ZVAL_EMPTY_ARRAY(&values);
if (UNEXPECTED(!pt_constant_array_type_new(&out, &keys, &values))) return zv::Val();
return zv::Val::adopt(out);
}
/* new NonEmptyArrayType() / new AccessoryArrayListType() / new NeverType() / new NullType() / new BooleanType() / new IntegerType() */
zv::Val newNonEmptyArrayType()
{
zval out;
if (UNEXPECTED(!pt_non_empty_array_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newAccessoryArrayListType()
{
zval out;
if (UNEXPECTED(!pt_accessory_array_list_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newNeverType()
{
zval out;
if (UNEXPECTED(!pt_never_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newNullType()
{
zval out;
if (UNEXPECTED(!pt_null_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newBooleanType()
{
zval out;
if (UNEXPECTED(!pt_boolean_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newIntegerType()
{
zval out;
if (UNEXPECTED(!pt_integer_type_new(&out))) return zv::Val();
return zv::Val::adopt(out);
}
zv::Val newConstantBooleanType(bool value)
{
zval out;
if (UNEXPECTED(!pt_constant_boolean_type_new(&out, value))) return zv::Val();
return zv::Val::adopt(out);
}