Don't raise warning when converting fun() pointer to bool
[hiphop-php.git] / hphp / runtime / base / tv-conversions.cpp
blobeb1d9a96c5ac0cd154464ac7906c887942d80907
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 "hphp/runtime/base/array-data.h"
18 #include "hphp/runtime/base/array-init.h"
19 #include "hphp/runtime/base/array-iterator.h"
20 #include "hphp/runtime/base/collections.h"
21 #include "hphp/runtime/base/datatype.h"
22 #include "hphp/runtime/base/double-to-int64.h"
23 #include "hphp/runtime/base/dummy-resource.h"
24 #include "hphp/runtime/base/mixed-array.h"
25 #include "hphp/runtime/base/object-data.h"
26 #include "hphp/runtime/base/packed-array.h"
27 #include "hphp/runtime/base/resource-data.h"
28 #include "hphp/runtime/base/runtime-error.h"
29 #include "hphp/runtime/base/runtime-option.h"
30 #include "hphp/runtime/base/set-array.h"
31 #include "hphp/runtime/base/string-data.h"
32 #include "hphp/runtime/base/tv-mutate.h"
33 #include "hphp/runtime/base/tv-refcount.h"
34 #include "hphp/runtime/base/tv-variant.h"
35 #include "hphp/runtime/base/tv-val.h"
36 #include "hphp/runtime/base/type-array.h"
37 #include "hphp/runtime/base/type-object.h"
38 #include "hphp/runtime/base/type-string.h"
39 #include "hphp/runtime/base/type-variant.h"
40 #include "hphp/runtime/base/typed-value.h"
42 #include "hphp/runtime/vm/class-meth-data-ref.h"
43 #include "hphp/runtime/vm/func.h"
44 #include "hphp/runtime/vm/vm-regs.h"
46 #include "hphp/system/systemlib.h"
48 #include "hphp/util/assertions.h"
50 namespace HPHP {
52 ///////////////////////////////////////////////////////////////////////////////
54 template<typename T>
55 enable_if_lval_t<T, void> tvCastToBooleanInPlace(T tv) {
56 assertx(tvIsPlausible(*tv));
57 bool b;
59 do {
60 switch (type(tv)) {
61 case KindOfUninit:
62 case KindOfNull:
63 b = false;
64 continue;
66 case KindOfBoolean:
67 return;
69 case KindOfInt64:
70 b = (val(tv).num != 0LL);
71 continue;
73 case KindOfDouble:
74 b = (val(tv).dbl != 0);
75 continue;
77 case KindOfPersistentString:
78 b = val(tv).pstr->toBoolean();
79 continue;
81 case KindOfString:
82 b = val(tv).pstr->toBoolean();
83 tvDecRefStr(tv);
84 continue;
86 case KindOfPersistentDArray:
87 case KindOfPersistentVArray:
88 case KindOfPersistentVec:
89 case KindOfPersistentDict:
90 case KindOfPersistentKeyset:
91 case KindOfPersistentArray:
92 b = !val(tv).parr->empty();
93 continue;
95 case KindOfVec:
96 case KindOfDict:
97 case KindOfKeyset:
98 case KindOfDArray:
99 case KindOfVArray:
100 case KindOfArray:
101 b = !val(tv).parr->empty();
102 tvDecRefArr(tv);
103 continue;
105 case KindOfObject:
106 b = val(tv).pobj->toBoolean();
107 tvDecRefObj(tv);
108 continue;
110 case KindOfResource:
111 b = val(tv).pres->data()->o_toBoolean();
112 tvDecRefRes(tv);
113 continue;
115 case KindOfClsMeth:
116 tvDecRefClsMeth(tv);
117 case KindOfFunc:
118 case KindOfClass:
119 b = true;
120 continue;
122 case KindOfRecord:
123 raise_convert_record_to_type("bool");
125 not_reached();
126 } while (0);
128 val(tv).num = b;
129 type(tv) = KindOfBoolean;
132 bool tvCastToBoolean(TypedValue tv) {
133 assertx(tvIsPlausible(tv));
134 return tvToBool(tv);
137 template<typename T>
138 enable_if_lval_t<T, void> tvCastToDoubleInPlace(T tv) {
139 assertx(tvIsPlausible(*tv));
140 double d;
142 do {
143 switch (type(tv)) {
144 case KindOfUninit:
145 case KindOfNull:
146 d = 0.0;
147 continue;
149 case KindOfBoolean:
150 assertx(val(tv).num == 0LL || val(tv).num == 1LL);
151 // fallthru
152 case KindOfInt64:
153 d = (double)(val(tv).num);
154 continue;
156 case KindOfDouble:
157 return;
159 case KindOfPersistentString:
160 d = val(tv).pstr->toDouble();
161 continue;
163 case KindOfString:
164 d = val(tv).pstr->toDouble();
165 tvDecRefStr(tv);
166 continue;
168 case KindOfPersistentDArray:
169 case KindOfPersistentVArray:
170 case KindOfPersistentVec:
171 case KindOfPersistentDict:
172 case KindOfPersistentKeyset:
173 case KindOfPersistentArray:
174 d = val(tv).parr->empty() ? 0 : 1;
175 continue;
177 case KindOfVec:
178 case KindOfDict:
179 case KindOfKeyset:
180 case KindOfDArray:
181 case KindOfVArray:
182 case KindOfArray:
183 d = val(tv).parr->empty() ? 0 : 1;
184 tvDecRefArr(tv);
185 continue;
187 case KindOfObject:
188 d = val(tv).pobj->toDouble();
189 tvDecRefObj(tv);
190 continue;
192 case KindOfResource:
193 d = val(tv).pres->data()->o_toDouble();
194 tvDecRefRes(tv);
195 continue;
197 case KindOfFunc:
198 if (RuntimeOption::EvalRaiseFuncConversionWarning) {
199 raise_warning("Func to double conversion");
201 d = val(tv).pfunc->name()->toDouble();
202 continue;
204 case KindOfClass:
205 d = classToStringHelper(val(tv).pclass)->toDouble();
206 continue;
208 case KindOfClsMeth:
209 raiseClsMethConvertWarningHelper("double");
210 d = 1.0;
211 tvDecRefClsMeth(tv);
212 continue;
214 case KindOfRecord:
215 raise_convert_record_to_type("double");
217 not_reached();
218 } while (0);
220 val(tv).dbl = d;
221 type(tv) = KindOfDouble;
224 template<typename T>
225 enable_if_lval_t<T, void> tvCastToInt64InPlace(T tv) {
226 assertx(tvIsPlausible(*tv));
227 assertx(tvIsPlausible(*tv));
228 int64_t i;
230 do {
231 switch (type(tv)) {
232 case KindOfUninit:
233 case KindOfNull:
234 val(tv).num = 0LL;
235 // fallthru
236 case KindOfBoolean:
237 assertx(val(tv).num == 0LL || val(tv).num == 1LL);
238 type(tv) = KindOfInt64;
239 // fallthru
240 case KindOfInt64:
241 return;
243 case KindOfDouble:
244 i = double_to_int64(val(tv).dbl);
245 continue;
247 case KindOfPersistentString:
248 i = val(tv).pstr->toInt64();
249 continue;
251 case KindOfString:
252 i = val(tv).pstr->toInt64();
253 tvDecRefStr(tv);
254 continue;
256 case KindOfPersistentDArray:
257 case KindOfPersistentVArray:
258 case KindOfPersistentVec:
259 case KindOfPersistentDict:
260 case KindOfPersistentKeyset:
261 case KindOfPersistentArray:
262 i = val(tv).parr->empty() ? 0 : 1;
263 continue;
265 case KindOfVec:
266 case KindOfDict:
267 case KindOfKeyset:
268 case KindOfDArray:
269 case KindOfVArray:
270 case KindOfArray:
271 i = val(tv).parr->empty() ? 0 : 1;
272 tvDecRefArr(tv);
273 continue;
275 case KindOfObject:
276 i = val(tv).pobj->toInt64();
277 tvDecRefObj(tv);
278 continue;
280 case KindOfResource:
281 i = val(tv).pres->data()->o_toInt64();
282 tvDecRefRes(tv);
283 continue;
285 case KindOfFunc:
286 i = funcToInt64Helper(val(tv).pfunc);
287 continue;
289 case KindOfClass:
290 i = classToStringHelper(val(tv).pclass)->toInt64();
291 continue;
293 case KindOfClsMeth:
294 raiseClsMethConvertWarningHelper("int");
295 i = 1;
296 tvDecRefClsMeth(tv);
297 continue;
299 case KindOfRecord:
300 raise_convert_record_to_type("int");
302 not_reached();
303 } while (0);
305 val(tv).num = i;
306 type(tv) = KindOfInt64;
309 int64_t tvCastToInt64(TypedValue tv) {
310 assertx(tvIsPlausible(tv));
311 return tvToInt(tv);
314 double tvCastToDouble(TypedValue tv) {
315 assertx(tvIsPlausible(tv));
316 switch (tv.m_type) {
317 case KindOfUninit:
318 case KindOfNull:
319 return 0;
321 case KindOfBoolean:
322 assertx(tv.m_data.num == 0LL || tv.m_data.num == 1LL);
323 // fallthru
324 case KindOfInt64:
325 return (double)(tv.m_data.num);
327 case KindOfDouble:
328 return tv.m_data.dbl;
330 case KindOfPersistentString:
331 case KindOfString:
332 return tv.m_data.pstr->toDouble();
334 case KindOfPersistentDArray:
335 case KindOfDArray:
336 case KindOfPersistentVArray:
337 case KindOfVArray:
338 case KindOfPersistentVec:
339 case KindOfVec:
340 case KindOfPersistentDict:
341 case KindOfDict:
342 case KindOfPersistentKeyset:
343 case KindOfKeyset:
344 case KindOfPersistentArray:
345 case KindOfArray:
346 return tv.m_data.parr->empty() ? 0.0 : 1.0;
348 case KindOfObject:
349 return tv.m_data.pobj->toDouble();
351 case KindOfResource:
352 return tv.m_data.pres->data()->o_toDouble();
354 case KindOfFunc:
355 if (RuntimeOption::EvalRaiseFuncConversionWarning) {
356 raise_warning("Func to double conversion");
358 return tv.m_data.pfunc->name()->toDouble();
360 case KindOfClass:
361 return classToStringHelper(tv.m_data.pclass)->toDouble();
363 case KindOfClsMeth:
364 raiseClsMethConvertWarningHelper("double");
365 return 1.0;
367 case KindOfRecord:
368 raise_convert_record_to_type("double");
370 not_reached();
373 const StaticString
374 s_1("1"),
375 s_scalar("scalar");
377 template<typename T>
378 enable_if_lval_t<T, void> tvCastToStringInPlace(T tv) {
379 assertx(tvIsPlausible(*tv));
381 auto string = [&](StringData* s) {
382 type(tv) = KindOfString;
383 val(tv).pstr = s;
385 auto persistentString = [&](StringData* s) {
386 assertx(!s->isRefCounted());
387 type(tv) = KindOfPersistentString;
388 val(tv).pstr = s;
391 switch (type(tv)) {
392 case KindOfUninit:
393 case KindOfNull:
394 return persistentString(staticEmptyString());
396 case KindOfBoolean:
397 return persistentString(val(tv).num ? s_1.get() : staticEmptyString());
399 case KindOfInt64:
400 return string(buildStringData(val(tv).num));
402 case KindOfDouble:
403 return string(buildStringData(val(tv).dbl));
405 case KindOfPersistentString:
406 case KindOfString:
407 return;
409 case KindOfVec:
410 case KindOfPersistentVec:
411 raise_notice("Vec to string conversion");
412 if (type(tv) == KindOfVec) tvDecRefArr(*tv);
413 return persistentString(vec_string.get());
415 case KindOfDict:
416 case KindOfPersistentDict:
417 raise_notice("Dict to string conversion");
418 if (type(tv) == KindOfDict) tvDecRefArr(*tv);
419 return persistentString(dict_string.get());
421 case KindOfKeyset:
422 case KindOfPersistentKeyset:
423 raise_notice("Keyset to string conversion");
424 if (type(tv) == KindOfKeyset) tvDecRefArr(*tv);
425 return persistentString(keyset_string.get());
427 case KindOfPersistentDArray:
428 case KindOfDArray:
429 case KindOfPersistentVArray:
430 case KindOfVArray:
431 case KindOfArray:
432 case KindOfPersistentArray:
433 raise_notice("Array to string conversion");
434 if (isRefcountedType(type(tv))) {
435 tvDecRefArr(*tv);
437 return persistentString(array_string.get());
439 case KindOfObject:
440 tvMove(
441 make_tv<KindOfString>(val(tv).pobj->invokeToString().detach()),
444 return;
446 case KindOfResource:
447 tvMove(
448 make_tv<KindOfString>(val(tv).pres->data()->o_toString().detach()),
451 return;
453 case KindOfFunc: {
454 auto const s = funcToStringHelper(val(tv).pfunc);
455 return persistentString(const_cast<StringData*>(s));
458 case KindOfClass: {
459 auto const s = classToStringHelper(val(tv).pclass);
460 return persistentString(const_cast<StringData*>(s));
463 case KindOfClsMeth:
464 if (RuntimeOption::EvalRaiseClsMethConversionWarning) {
465 raise_notice("Implicit clsmeth to string conversion");
467 tvDecRefClsMeth(tv);
468 if (RuntimeOption::EvalHackArrDVArrs) {
469 return persistentString(vec_string.get());
470 } else {
471 return persistentString(array_string.get());
474 case KindOfRecord:
475 raise_convert_record_to_type("string");
477 not_reached();
480 StringData* tvCastToStringData(TypedValue tv) {
481 assertx(tvIsPlausible(tv));
483 switch (tv.m_type) {
484 case KindOfUninit:
485 case KindOfNull:
486 return staticEmptyString();
488 case KindOfBoolean:
489 return tv.m_data.num ? s_1.get() : staticEmptyString();
491 case KindOfInt64:
492 return buildStringData(tv.m_data.num);
494 case KindOfDouble:
495 return buildStringData(tv.m_data.dbl);
497 case KindOfPersistentString:
498 return tv.m_data.pstr;
500 case KindOfString: {
501 auto s = tv.m_data.pstr;
502 s->incRefCount();
503 return s;
506 case KindOfPersistentVec:
507 case KindOfVec:
508 raise_notice("Vec to string conversion");
509 return vec_string.get();
511 case KindOfPersistentDict:
512 case KindOfDict:
513 raise_notice("Dict to string conversion");
514 return dict_string.get();
516 case KindOfPersistentKeyset:
517 case KindOfKeyset:
518 raise_notice("Keyset to string conversion");
519 return keyset_string.get();
521 case KindOfPersistentDArray:
522 case KindOfDArray:
523 case KindOfPersistentVArray:
524 case KindOfVArray:
525 case KindOfPersistentArray:
526 case KindOfArray:
527 raise_notice("Array to string conversion");
528 return array_string.get();
530 case KindOfObject:
531 return tv.m_data.pobj->invokeToString().detach();
533 case KindOfResource:
534 return tv.m_data.pres->data()->o_toString().detach();
536 case KindOfFunc: {
537 auto const s = funcToStringHelper(tv.m_data.pfunc);
538 return const_cast<StringData*>(s);
541 case KindOfClass: {
542 auto const s = classToStringHelper(tv.m_data.pclass);
543 return const_cast<StringData*>(s);
546 case KindOfClsMeth:
547 if (RuntimeOption::EvalRaiseClsMethConversionWarning) {
548 raise_notice("Implicit clsmeth to string conversion");
550 if (RuntimeOption::EvalHackArrDVArrs) {
551 return vec_string.get();
552 } else {
553 return array_string.get();
556 case KindOfRecord:
557 raise_convert_record_to_type("string");
559 not_reached();
562 String tvCastToString(TypedValue tv) {
563 return String::attach(tvCastToStringData(tv));
566 template <IntishCast IC>
567 ArrayData* tvCastToArrayLikeData(TypedValue tv) {
568 assertx(tvIsPlausible(tv));
569 switch (tv.m_type) {
570 case KindOfUninit:
571 case KindOfNull:
572 return ArrayData::Create();
574 case KindOfBoolean:
575 case KindOfInt64:
576 case KindOfDouble:
577 case KindOfPersistentString:
578 case KindOfString:
579 case KindOfResource:
580 case KindOfFunc:
581 case KindOfClass:
582 return ArrayData::Create(tv);
584 case KindOfPersistentDArray:
585 case KindOfDArray:
586 case KindOfPersistentVArray:
587 case KindOfVArray:
588 case KindOfPersistentVec:
589 case KindOfVec:
590 case KindOfPersistentDict:
591 case KindOfDict:
592 case KindOfPersistentKeyset:
593 case KindOfKeyset:
594 case KindOfPersistentArray:
595 case KindOfArray: {
596 auto const ad = tv.m_data.parr;
597 ad->incRefCount();
598 return ad;
601 case KindOfClsMeth:
602 raiseClsMethToVecWarningHelper();
603 return clsMethToVecHelper(tv.m_data.pclsmeth).detach();
605 case KindOfObject: {
606 auto ad = tv.m_data.pobj->toArray<IC>();
607 assertx(ad->isPHPArrayType());
608 return ad.detach();
611 case KindOfRecord:
612 raise_convert_record_to_type("array");
614 not_reached();
617 template
618 ArrayData* tvCastToArrayLikeData<IntishCast::None>(TypedValue);
619 template
620 ArrayData* tvCastToArrayLikeData<IntishCast::Cast>(TypedValue);
622 template <IntishCast IC /* = IntishCast::None */>
623 Array tvCastToArrayLike(TypedValue tv) {
624 return Array::attach(tvCastToArrayLikeData<IC>(tv));
627 template Array tvCastToArrayLike<IntishCast::Cast>(TypedValue);
628 template Array tvCastToArrayLike<IntishCast::None>(TypedValue);
630 template <typename LHS, typename T>
631 static enable_if_lval_t<
632 LHS,
633 typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type>
634 assign(LHS lhs, T&& rhs) {
635 variant_ref{lhs} = std::forward<T>(rhs);
638 template<typename T, IntishCast IC /* = IntishCast::None */>
639 enable_if_lval_t<T, void> tvCastToArrayInPlace(T tv) {
640 assertx(tvIsPlausible(*tv));
641 ArrayData* a;
643 do {
644 switch (type(tv)) {
645 case KindOfUninit:
646 case KindOfNull:
647 a = ArrayData::Create();
648 continue;
650 case KindOfBoolean:
651 case KindOfInt64:
652 case KindOfDouble:
653 case KindOfPersistentString:
654 a = ArrayData::Create(*tv);
655 continue;
657 case KindOfString:
658 a = ArrayData::Create(*tv);
659 tvDecRefStr(tv);
660 continue;
662 case KindOfPersistentVec: {
663 auto* adIn = val(tv).parr;
664 assertx(adIn->isVecArrayKind());
665 a = PackedArray::ToPHPArrayVec(adIn, true);
666 assertx(a != adIn);
667 continue;
670 case KindOfVec: {
671 auto* adIn = val(tv).parr;
672 assertx(adIn->isVecArrayKind());
673 a = PackedArray::ToPHPArrayVec(adIn, adIn->cowCheck());
674 if (a != adIn) tvDecRefArr(tv);
675 continue;
678 case KindOfPersistentDict: {
679 auto* adIn = val(tv).parr;
680 assertx(adIn->isDictKind());
682 if (IC == IntishCast::Cast) {
683 a = MixedArray::ToPHPArrayIntishCastDict(adIn, true);
684 } else {
685 assertx(IC == IntishCast::None);
686 a = MixedArray::ToPHPArrayDict(adIn, true);
689 assertx(a != adIn);
690 continue;
693 case KindOfDict: {
694 auto* adIn = val(tv).parr;
695 assertx(adIn->isDictKind());
697 if (IC == IntishCast::Cast) {
698 a = MixedArray::ToPHPArrayIntishCastDict(adIn, adIn->cowCheck());
699 } else {
700 assertx(IC == IntishCast::None);
701 a = MixedArray::ToPHPArrayDict(adIn, adIn->cowCheck());
704 if (a != adIn) tvDecRefArr(tv);
705 continue;
708 case KindOfPersistentKeyset: {
709 auto* adIn = val(tv).parr;
710 assertx(adIn->isKeysetKind());
712 if (IC == IntishCast::Cast) {
713 a = SetArray::ToPHPArrayIntishCast(adIn, true);
714 } else {
715 assertx(IC == IntishCast::None);
716 a = SetArray::ToPHPArray(adIn, true);
719 assertx(a != adIn);
720 continue;
723 case KindOfKeyset: {
724 auto* adIn = val(tv).parr;
725 assertx(adIn->isKeysetKind());
727 if (IC == IntishCast::Cast) {
728 a = SetArray::ToPHPArrayIntishCast(adIn, adIn->cowCheck());
729 } else {
730 assertx(IC == IntishCast::None);
731 a = SetArray::ToPHPArray(adIn, adIn->cowCheck());
734 if (a != adIn) tvDecRefArr(tv);
735 continue;
738 case KindOfPersistentDArray:
739 case KindOfPersistentVArray:
740 case KindOfPersistentArray: {
741 auto* adIn = val(tv).parr;
742 assertx(adIn->isPHPArrayType());
743 if (IC == IntishCast::Cast) {
744 a = adIn->toPHPArrayIntishCast(true);
745 } else {
746 assertx(IC == IntishCast::None);
747 a = adIn->toPHPArray(true);
749 continue;
752 case KindOfDArray:
753 case KindOfVArray:
754 case KindOfArray: {
755 auto* adIn = val(tv).parr;
756 assertx(adIn->isPHPArrayType());
757 if (IC == IntishCast::Cast) {
758 a = adIn->toPHPArrayIntishCast(adIn->cowCheck());
759 } else {
760 assertx(IC == IntishCast::None);
761 a = adIn->toPHPArray(adIn->cowCheck());
763 if (a != adIn) tvDecRefArr(tv);
764 continue;
767 case KindOfObject: {
768 assign(tv, ((ObjectData*)val(tv).pobj)->toArray<IC>());
769 return;
772 case KindOfResource:
773 a = ArrayData::Create(*tv);
774 tvDecRefRes(tv);
775 continue;
777 case KindOfFunc:
778 case KindOfClass:
779 a = ArrayData::Create(*tv);
780 continue;
782 case KindOfClsMeth: {
783 raiseClsMethConvertWarningHelper("array");
784 a = make_packed_array(
785 val(tv).pclsmeth->getClsStr(), val(tv).pclsmeth->getFuncStr()
786 ).detach();
787 tvDecRefClsMeth(tv);
788 continue;
791 case KindOfRecord:
792 raise_convert_record_to_type("array");
794 not_reached();
795 } while (0);
797 assertx(a->isPHPArrayType());
798 assertx(a->isNotDVArray());
800 val(tv).parr = a;
801 type(tv) = KindOfArray;
802 assertx(tvIsPlausible(*tv));
805 template<typename T>
806 enable_if_lval_t<T, void> tvCastToVecInPlace(T tv) {
807 assertx(tvIsPlausible(*tv));
808 ArrayData* a;
810 do {
811 switch (type(tv)) {
812 case KindOfUninit:
813 case KindOfNull:
814 SystemLib::throwInvalidOperationExceptionObject(
815 "Null to vec conversion"
818 case KindOfBoolean:
819 SystemLib::throwInvalidOperationExceptionObject(
820 "Bool to vec conversion"
823 case KindOfInt64:
824 SystemLib::throwInvalidOperationExceptionObject(
825 "Int to vec conversion"
828 case KindOfDouble:
829 SystemLib::throwInvalidOperationExceptionObject(
830 "Double to vec conversion"
833 case KindOfPersistentString:
834 case KindOfString:
835 SystemLib::throwInvalidOperationExceptionObject(
836 "String to vec conversion"
839 case KindOfResource:
840 SystemLib::throwInvalidOperationExceptionObject(
841 "Resource to vec conversion"
844 case KindOfPersistentDict:
845 case KindOfDict: {
846 auto* adIn = val(tv).parr;
847 assertx(adIn->isDictKind());
848 a = MixedArray::ToVecDict(adIn, adIn->cowCheck());
849 assertx(a != adIn);
850 decRefArr(adIn);
851 continue;
854 case KindOfPersistentKeyset:
855 case KindOfKeyset: {
856 auto* adIn = val(tv).parr;
857 assertx(adIn->isKeysetKind());
858 a = SetArray::ToVec(adIn, adIn->cowCheck());
859 assertx(a != adIn);
860 decRefArr(adIn);
861 continue;
864 case KindOfPersistentDArray:
865 case KindOfDArray:
866 case KindOfPersistentVArray:
867 case KindOfVArray:
868 case KindOfPersistentArray:
869 case KindOfArray: {
870 auto* adIn = val(tv).parr;
871 assertx(adIn->isPHPArrayType());
872 a = adIn->toVec(adIn->cowCheck());
873 if (a != adIn) decRefArr(adIn);
874 continue;
877 case KindOfPersistentVec:
878 case KindOfVec:
879 assertx(val(tv).parr->isVecArrayType());
880 return;
882 case KindOfObject:
883 a = castObjToVec(val(tv).pobj);
884 // We might have re-entered, so tv may not contain the object anymore.
885 tvDecRefGen(tv);
886 continue;
888 case KindOfFunc:
889 SystemLib::throwInvalidOperationExceptionObject(
890 "Func to vec conversion"
893 case KindOfClass:
894 SystemLib::throwInvalidOperationExceptionObject(
895 "Class to vec conversion"
898 case KindOfClsMeth: {
899 raiseClsMethConvertWarningHelper("vec");
900 a = make_vec_array(
901 val(tv).pclsmeth->getClsStr(), val(tv).pclsmeth->getFuncStr()
902 ).detach();
903 tvDecRefClsMeth(tv);
904 continue;
907 case KindOfRecord:
908 raise_convert_record_to_type("vec");
910 not_reached();
911 } while (0);
913 val(tv).parr = a;
914 type(tv) = KindOfVec;
915 assertx(tvIsPlausible(*tv));
918 template<typename T>
919 enable_if_lval_t<T, void> tvCastToDictInPlace(T tv) {
920 assertx(tvIsPlausible(*tv));
921 ArrayData* a;
923 do {
924 switch (type(tv)) {
925 case KindOfUninit:
926 case KindOfNull:
927 SystemLib::throwInvalidOperationExceptionObject(
928 "Null to dict conversion"
931 case KindOfBoolean:
932 SystemLib::throwInvalidOperationExceptionObject(
933 "Bool to dict conversion"
936 case KindOfInt64:
937 SystemLib::throwInvalidOperationExceptionObject(
938 "Int to dict conversion"
941 case KindOfDouble:
942 SystemLib::throwInvalidOperationExceptionObject(
943 "Double to dict conversion"
946 case KindOfPersistentString:
947 case KindOfString:
948 SystemLib::throwInvalidOperationExceptionObject(
949 "String to dict conversion"
952 case KindOfResource:
953 SystemLib::throwInvalidOperationExceptionObject(
954 "Resource to dict conversion"
957 case KindOfPersistentVec:
958 case KindOfVec: {
959 auto* adIn = val(tv).parr;
960 assertx(adIn->isVecArrayKind());
961 a = PackedArray::ToDictVec(adIn, adIn->cowCheck());
962 assertx(a != adIn);
963 decRefArr(adIn);
964 continue;
967 case KindOfPersistentKeyset:
968 case KindOfKeyset: {
969 auto* adIn = val(tv).parr;
970 assertx(adIn->isKeysetKind());
971 a = SetArray::ToDict(adIn, adIn->cowCheck());
972 if (a != adIn) decRefArr(adIn);
973 continue;
976 case KindOfPersistentDArray:
977 case KindOfDArray:
978 case KindOfPersistentVArray:
979 case KindOfVArray:
980 case KindOfPersistentArray:
981 case KindOfArray: {
982 auto* adIn = val(tv).parr;
983 assertx(adIn->isPHPArrayType());
984 a = adIn->toDict(adIn->cowCheck());
985 if (a != adIn) decRefArr(adIn);
986 continue;
989 case KindOfPersistentDict:
990 case KindOfDict:
991 assertx(val(tv).parr->isDictType());
992 return;
994 case KindOfObject:
995 a = castObjToDict(val(tv).pobj);
996 // We might have re-entered, so tv may not contain the object anymore.
997 tvDecRefGen(tv);
998 continue;
1000 case KindOfFunc:
1001 SystemLib::throwInvalidOperationExceptionObject(
1002 "Func to dict conversion"
1005 case KindOfClass:
1006 SystemLib::throwInvalidArgumentExceptionObject(
1007 "Class to dict conversion"
1010 case KindOfClsMeth: {
1011 raiseClsMethConvertWarningHelper("dict");
1012 a = make_dict_array(
1013 0, val(tv).pclsmeth->getClsStr(),
1014 1, val(tv).pclsmeth->getFuncStr()).detach();
1015 tvDecRefClsMeth(tv);
1016 continue;
1019 case KindOfRecord:
1020 raise_convert_record_to_type("dict");
1022 not_reached();
1023 } while (0);
1025 val(tv).parr = a;
1026 type(tv) = KindOfDict;
1027 assertx(tvIsPlausible(*tv));
1030 template<typename T>
1031 enable_if_lval_t<T, void> tvCastToKeysetInPlace(T tv) {
1032 assertx(tvIsPlausible(*tv));
1033 ArrayData* a;
1035 do {
1036 switch (type(tv)) {
1037 case KindOfUninit:
1038 case KindOfNull:
1039 SystemLib::throwInvalidOperationExceptionObject(
1040 "Null to keyset conversion"
1043 case KindOfBoolean:
1044 SystemLib::throwInvalidOperationExceptionObject(
1045 "Bool to keyset conversion"
1048 case KindOfInt64:
1049 SystemLib::throwInvalidOperationExceptionObject(
1050 "Int to keyset conversion"
1053 case KindOfDouble:
1054 SystemLib::throwInvalidOperationExceptionObject(
1055 "Double to keyset conversion"
1058 case KindOfPersistentString:
1059 case KindOfString:
1060 SystemLib::throwInvalidOperationExceptionObject(
1061 "String to keyset conversion"
1064 case KindOfResource:
1065 SystemLib::throwInvalidOperationExceptionObject(
1066 "Resource to keyset conversion"
1069 case KindOfPersistentVec:
1070 case KindOfVec: {
1071 auto* adIn = val(tv).parr;
1072 assertx(adIn->isVecArrayKind());
1073 a = PackedArray::ToKeysetVec(adIn, adIn->cowCheck());
1074 assertx(a != adIn);
1075 decRefArr(adIn);
1076 continue;
1079 case KindOfPersistentDict:
1080 case KindOfDict: {
1081 auto* adIn = val(tv).parr;
1082 assertx(adIn->isDictKind());
1083 a = MixedArray::ToKeysetDict(adIn, adIn->cowCheck());
1084 if (a != adIn) decRefArr(adIn);
1085 continue;
1088 case KindOfPersistentDArray:
1089 case KindOfDArray:
1090 case KindOfPersistentVArray:
1091 case KindOfVArray:
1092 case KindOfPersistentArray:
1093 case KindOfArray: {
1094 auto* adIn = val(tv).parr;
1095 assertx(adIn->isPHPArrayType());
1096 a = adIn->toKeyset(adIn->cowCheck());
1097 if (a != adIn) decRefArr(adIn);
1098 continue;
1101 case KindOfPersistentKeyset:
1102 case KindOfKeyset:
1103 assertx(val(tv).parr->isKeysetType());
1104 return;
1106 case KindOfObject:
1107 a = castObjToKeyset(val(tv).pobj);
1108 // We might have re-entered, so tv may not contain the object anymore.
1109 tvDecRefGen(tv);
1110 continue;
1112 case KindOfFunc:
1113 SystemLib::throwInvalidOperationExceptionObject(
1114 "Func to keyset conversion"
1117 case KindOfClass:
1118 SystemLib::throwInvalidOperationExceptionObject(
1119 "Class to keyset conversion"
1122 case KindOfClsMeth: {
1123 raiseClsMethConvertWarningHelper("keyset");
1124 a = make_keyset_array(
1125 const_cast<StringData*>(val(tv).pclsmeth->getCls()->name()),
1126 const_cast<StringData*>(val(tv).pclsmeth->getFunc()->name())
1127 ).detach();
1128 tvDecRefClsMeth(tv);
1129 continue;
1132 case KindOfRecord:
1133 raise_convert_record_to_type("keyset");
1135 not_reached();
1136 } while (0);
1138 val(tv).parr = a;
1139 type(tv) = KindOfKeyset;
1140 assertx(tvIsPlausible(*tv));
1143 template<typename T>
1144 enable_if_lval_t<T, void> tvCastToVArrayInPlace(T tv) {
1145 assertx(!RuntimeOption::EvalHackArrDVArrs);
1146 assertx(tvIsPlausible(*tv));
1147 ArrayData* a;
1149 do {
1150 switch (type(tv)) {
1151 case KindOfUninit:
1152 case KindOfNull:
1153 SystemLib::throwInvalidOperationExceptionObject(
1154 "Null to varray conversion"
1157 case KindOfBoolean:
1158 SystemLib::throwInvalidOperationExceptionObject(
1159 "Bool to varray conversion"
1162 case KindOfInt64:
1163 SystemLib::throwInvalidOperationExceptionObject(
1164 "Int to varray conversion"
1167 case KindOfDouble:
1168 SystemLib::throwInvalidOperationExceptionObject(
1169 "Double to varray conversion"
1172 case KindOfPersistentString:
1173 case KindOfString:
1174 SystemLib::throwInvalidOperationExceptionObject(
1175 "String to varray conversion"
1178 case KindOfResource:
1179 SystemLib::throwInvalidOperationExceptionObject(
1180 "Resource to varray conversion"
1183 case KindOfPersistentVec:
1184 case KindOfVec: {
1185 auto* adIn = val(tv).parr;
1186 assertx(adIn->isVecArrayKind());
1187 a = PackedArray::ToVArrayVec(adIn, adIn->cowCheck());
1188 if (a != adIn) decRefArr(adIn);
1189 continue;
1192 case KindOfPersistentDict:
1193 case KindOfDict: {
1194 auto* adIn = val(tv).parr;
1195 assertx(adIn->isDictKind());
1196 a = MixedArray::ToVArrayDict(adIn, adIn->cowCheck());
1197 assertx(a != adIn);
1198 decRefArr(adIn);
1199 continue;
1202 case KindOfPersistentKeyset:
1203 case KindOfKeyset: {
1204 auto* adIn = val(tv).parr;
1205 assertx(adIn->isKeysetKind());
1206 a = SetArray::ToVArray(adIn, adIn->cowCheck());
1207 assertx(a != adIn);
1208 decRefArr(adIn);
1209 continue;
1212 case KindOfPersistentDArray:
1213 case KindOfDArray:
1214 case KindOfPersistentVArray:
1215 case KindOfVArray:
1216 case KindOfPersistentArray:
1217 case KindOfArray: {
1218 auto* adIn = val(tv).parr;
1219 assertx(adIn->isPHPArrayType());
1220 if (adIn->isVArray()) return;
1221 a = adIn->toVArray(adIn->cowCheck());
1222 assertx(a->isPackedKind());
1223 assertx(a->isVArray());
1224 if (a == adIn) return;
1225 decRefArr(adIn);
1226 continue;
1229 case KindOfObject:
1230 a = castObjToVArray(val(tv).pobj);
1231 // We might have re-entered, so tv may not contain the object anymore.
1232 tvDecRefGen(tv);
1233 continue;
1235 case KindOfFunc:
1236 SystemLib::throwInvalidOperationExceptionObject(
1237 "Func to varray conversion"
1240 case KindOfClass:
1241 SystemLib::throwInvalidOperationExceptionObject(
1242 "Class to varray conversion"
1245 case KindOfClsMeth: {
1246 raiseClsMethConvertWarningHelper("varray");
1247 a = make_varray(
1248 val(tv).pclsmeth->getClsStr(), val(tv).pclsmeth->getFuncStr()
1249 ).detach();
1250 tvDecRefClsMeth(tv);
1251 continue;
1254 case KindOfRecord:
1255 raise_convert_record_to_type("varray");
1257 not_reached();
1258 } while (0);
1260 assertx(a->isPackedKind());
1261 assertx(a->isVArray());
1262 assertx(a->dvArraySanityCheck());
1264 val(tv).parr = a;
1265 type(tv) = KindOfArray;
1266 assertx(tvIsPlausible(*tv));
1269 template<typename T>
1270 enable_if_lval_t<T, void> tvCastToDArrayInPlace(T tv) {
1271 assertx(!RuntimeOption::EvalHackArrDVArrs);
1272 assertx(tvIsPlausible(*tv));
1273 ArrayData* a;
1275 do {
1276 switch (type(tv)) {
1277 case KindOfUninit:
1278 case KindOfNull:
1279 SystemLib::throwInvalidOperationExceptionObject(
1280 "Null to darray conversion"
1283 case KindOfBoolean:
1284 SystemLib::throwInvalidOperationExceptionObject(
1285 "Bool to darray conversion"
1288 case KindOfInt64:
1289 SystemLib::throwInvalidOperationExceptionObject(
1290 "Int to darray conversion"
1293 case KindOfDouble:
1294 SystemLib::throwInvalidOperationExceptionObject(
1295 "Double to darray conversion"
1298 case KindOfPersistentString:
1299 case KindOfString:
1300 SystemLib::throwInvalidOperationExceptionObject(
1301 "String to darray conversion"
1304 case KindOfResource:
1305 SystemLib::throwInvalidOperationExceptionObject(
1306 "Resource to darray conversion"
1309 case KindOfPersistentVec:
1310 case KindOfVec: {
1311 auto* adIn = val(tv).parr;
1312 assertx(adIn->isVecArrayKind());
1313 a = PackedArray::ToDArrayVec(adIn, adIn->cowCheck());
1314 assertx(a != adIn);
1315 decRefArr(adIn);
1316 continue;
1319 case KindOfPersistentDict:
1320 case KindOfDict: {
1321 auto* adIn = val(tv).parr;
1322 assertx(adIn->isDictKind());
1323 a = MixedArray::ToDArrayDict(adIn, adIn->cowCheck());
1324 if (a != adIn) decRefArr(adIn);
1325 continue;
1328 case KindOfPersistentKeyset:
1329 case KindOfKeyset: {
1330 auto* adIn = val(tv).parr;
1331 assertx(adIn->isKeysetKind());
1332 a = SetArray::ToDArray(adIn, adIn->cowCheck());
1333 assertx(a != adIn);
1334 decRefArr(adIn);
1335 continue;
1338 case KindOfPersistentDArray:
1339 case KindOfDArray:
1340 case KindOfPersistentVArray:
1341 case KindOfVArray:
1342 case KindOfPersistentArray:
1343 case KindOfArray: {
1344 auto* adIn = val(tv).parr;
1345 assertx(adIn->isPHPArrayType());
1346 if (adIn->isDArray()) return;
1347 a = adIn->toDArray(adIn->cowCheck());
1348 assertx(a->isMixedKind());
1349 assertx(a->isDArray());
1350 if (a == adIn) return;
1351 decRefArr(adIn);
1352 continue;
1355 case KindOfObject:
1356 a = castObjToDArray(val(tv).pobj);
1357 // We might have re-entered, so tv may not contain the object anymore.
1358 tvDecRefGen(tv);
1359 continue;
1361 case KindOfFunc:
1362 SystemLib::throwInvalidOperationExceptionObject(
1363 "Func to darray conversion"
1366 case KindOfClass:
1367 SystemLib::throwInvalidOperationExceptionObject(
1368 "Class to darray conversion"
1371 case KindOfClsMeth: {
1372 raiseClsMethConvertWarningHelper("darray");
1373 a = make_darray(
1374 0, val(tv).pclsmeth->getClsStr(),
1375 1, val(tv).pclsmeth->getFuncStr()
1376 ).detach();
1377 tvDecRefClsMeth(tv);
1378 continue;
1381 case KindOfRecord:
1382 raise_convert_record_to_type("darray");
1384 not_reached();
1385 } while (0);
1387 assertx(a->isMixedKind());
1388 assertx(a->isDArray());
1389 assertx(a->dvArraySanityCheck());
1391 val(tv).parr = a;
1392 type(tv) = KindOfArray;
1393 assertx(tvIsPlausible(*tv));
1396 ObjectData* tvCastToObjectData(TypedValue tv) {
1397 assertx(tvIsPlausible(tv));
1398 switch (tv.m_type) {
1399 case KindOfUninit:
1400 case KindOfNull:
1401 return SystemLib::AllocStdClassObject().detach();
1403 case KindOfBoolean:
1404 case KindOfInt64:
1405 case KindOfDouble:
1406 case KindOfPersistentString:
1407 case KindOfString:
1408 case KindOfFunc:
1409 case KindOfClass:
1410 case KindOfResource: {
1411 ArrayInit props(1, ArrayInit::Map{});
1412 props.set(s_scalar, tv);
1413 return ObjectData::FromArray(props.create()).detach();
1416 case KindOfPersistentVec:
1417 case KindOfVec:
1418 case KindOfPersistentDict:
1419 case KindOfDict:
1420 case KindOfPersistentKeyset:
1421 case KindOfKeyset: {
1422 auto const arr = Array::attach(tv.m_data.parr->toPHPArray(true));
1423 return ObjectData::FromArray(arr.get()).detach();
1426 case KindOfPersistentDArray:
1427 case KindOfDArray:
1428 case KindOfPersistentVArray:
1429 case KindOfVArray:
1430 case KindOfPersistentArray:
1431 case KindOfArray:
1432 return ObjectData::FromArray(tv.m_data.parr).detach();
1434 case KindOfObject:
1435 tv.m_data.pobj->incRefCount();
1436 return tv.m_data.pobj;
1438 case KindOfClsMeth: {
1439 raiseClsMethConvertWarningHelper("array");
1440 auto arr = make_varray(
1441 val(tv).pclsmeth->getClsStr(), val(tv).pclsmeth->getFuncStr());
1442 return ObjectData::FromArray(arr.get()).detach();
1445 case KindOfRecord:
1446 raise_convert_record_to_type("object");
1448 not_reached();
1451 template<typename T>
1452 enable_if_lval_t<T, void> tvCastToResourceInPlace(T tv) {
1453 assertx(tvIsPlausible(*tv));
1455 do {
1456 switch (type(tv)) {
1457 DT_UNCOUNTED_CASE:
1458 continue;
1459 case KindOfString:
1460 case KindOfVec:
1461 case KindOfDict:
1462 case KindOfKeyset:
1463 case KindOfDArray:
1464 case KindOfVArray:
1465 case KindOfArray:
1466 case KindOfObject:
1467 case KindOfRecord:
1468 tvDecRefCountable(tv);
1469 continue;
1470 case KindOfClsMeth:
1471 tvDecRefClsMeth(tv);
1472 continue;
1473 case KindOfResource:
1474 // no op, return
1475 return;
1477 not_reached();
1478 } while (0);
1480 type(tv) = KindOfResource;
1481 val(tv).pres = req::make<DummyResource>().detach()->hdr();
1482 assertx(tvIsPlausible(*tv));
1485 ///////////////////////////////////////////////////////////////////////////////
1486 #define X(kind) \
1487 template void tvCastTo##kind##InPlace<TypedValue*>(TypedValue*); \
1488 template void tvCastTo##kind##InPlace<tv_lval>(tv_lval); \
1489 template void tvCastTo##kind##InPlace<arr_lval>(arr_lval);
1490 X(Boolean)
1491 X(Int64)
1492 X(Double)
1493 X(String)
1494 X(Vec)
1495 X(Dict)
1496 X(Keyset)
1497 X(Resource)
1498 X(VArray)
1499 X(DArray)
1500 #undef X
1502 #define X(kind, IC) \
1503 template void tvCastTo##kind##InPlace<TypedValue*, IC>(TypedValue*); \
1504 template void tvCastTo##kind##InPlace<tv_lval, IC>(tv_lval); \
1505 template void tvCastTo##kind##InPlace<arr_lval, IC>(arr_lval);
1506 X(Array, IntishCast::Cast)
1507 X(Array, IntishCast::None)
1508 #undef X