Codemod asserts to assertxs in the runtime
[hiphop-php.git] / hphp / runtime / base / annot-type.h
blob2cda1e00e3f08cd1b669bc3dcfa570699416e7a5
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 #ifndef incl_HPHP_ANNOT_TYPE_H_
18 #define incl_HPHP_ANNOT_TYPE_H_
20 #include "hphp/runtime/base/datatype.h"
21 #include "hphp/runtime/base/runtime-option.h"
23 namespace HPHP {
25 struct StringData;
27 ///////////////////////////////////////////////////////////////////////////////
29 /**
30 * AnnotMetaType and AnnotType depend on each other, so if you change one
31 * of them you must update the other.
33 * Setting AnnotMetaType::Precise = 0 makes machine code slightly nicer
34 * for some operations, though it's not needed for correctness.
36 enum class AnnotMetaType : uint8_t {
37 Precise = 0,
38 Mixed = 1,
39 Self = 2,
40 Parent = 3,
41 Callable = 4,
42 Number = 5,
43 ArrayKey = 6,
44 This = 7,
45 VArray = 8,
46 DArray = 9,
47 VArrOrDArr = 10,
48 VecOrDict = 11,
51 enum class AnnotType : uint16_t {
52 Uninit = (uint8_t)KindOfUninit | (uint16_t)AnnotMetaType::Precise << 8,
53 Null = (uint8_t)KindOfNull | (uint16_t)AnnotMetaType::Precise << 8,
54 Bool = (uint8_t)KindOfBoolean | (uint16_t)AnnotMetaType::Precise << 8,
55 Int = (uint8_t)KindOfInt64 | (uint16_t)AnnotMetaType::Precise << 8,
56 Float = (uint8_t)KindOfDouble | (uint16_t)AnnotMetaType::Precise << 8,
57 String = (uint8_t)KindOfString | (uint16_t)AnnotMetaType::Precise << 8,
58 Array = (uint8_t)KindOfArray | (uint16_t)AnnotMetaType::Precise << 8,
59 Object = (uint8_t)KindOfObject | (uint16_t)AnnotMetaType::Precise << 8,
60 Resource = (uint8_t)KindOfResource | (uint16_t)AnnotMetaType::Precise << 8,
61 Dict = (uint8_t)KindOfDict | (uint16_t)AnnotMetaType::Precise << 8,
62 Vec = (uint8_t)KindOfVec | (uint16_t)AnnotMetaType::Precise << 8,
63 Keyset = (uint8_t)KindOfKeyset | (uint16_t)AnnotMetaType::Precise << 8,
64 // Precise is intentionally excluded
65 Mixed = (uint16_t)AnnotMetaType::Mixed << 8 | (uint8_t)KindOfUninit,
66 Self = (uint16_t)AnnotMetaType::Self << 8 | (uint8_t)KindOfUninit,
67 Parent = (uint16_t)AnnotMetaType::Parent << 8 | (uint8_t)KindOfUninit,
68 Callable = (uint16_t)AnnotMetaType::Callable << 8 | (uint8_t)KindOfUninit,
69 Number = (uint16_t)AnnotMetaType::Number << 8 | (uint8_t)KindOfUninit,
70 ArrayKey = (uint16_t)AnnotMetaType::ArrayKey << 8 | (uint8_t)KindOfUninit,
71 This = (uint16_t)AnnotMetaType::This << 8 | (uint8_t)KindOfUninit,
72 VArray = (uint16_t)AnnotMetaType::VArray << 8 | (uint8_t)KindOfUninit,
73 DArray = (uint16_t)AnnotMetaType::DArray << 8 | (uint8_t)KindOfUninit,
74 VArrOrDArr = (uint16_t)AnnotMetaType::VArrOrDArr << 8 | (uint8_t)KindOfUninit,
75 VecOrDict = (uint16_t)AnnotMetaType::VecOrDict << 8 | (uint8_t)KindOfUninit,
78 inline AnnotMetaType getAnnotMetaType(AnnotType at) {
79 return (AnnotMetaType)((uint16_t)at >> 8);
82 inline DataType getAnnotDataType(AnnotType at) {
83 auto const dt = (DataType)(uint8_t)at;
84 return dt;
87 inline AnnotType dataTypeToAnnotType(DataType dt) {
88 assertx(dt == KindOfUninit || dt == KindOfBoolean || dt == KindOfInt64 ||
89 dt == KindOfDouble || dt == KindOfString || dt == KindOfArray ||
90 dt == KindOfVec || dt == KindOfDict || dt == KindOfKeyset ||
91 dt == KindOfObject || dt == KindOfResource);
92 return (AnnotType)((uint8_t)dt | (uint16_t)AnnotMetaType::Precise << 8);
95 const AnnotType* nameToAnnotType(const StringData* typeName);
96 const AnnotType* nameToAnnotType(const std::string& typeName);
97 MaybeDataType nameToMaybeDataType(const StringData* typeName);
98 MaybeDataType nameToMaybeDataType(const std::string& typeName);
101 * Returns true if the interface with the specified name
102 * supports any non-object types, false otherwise.
104 bool interface_supports_non_objects(const StringData* s);
106 bool interface_supports_int(const StringData* s);
107 bool interface_supports_double(const StringData* s);
108 bool interface_supports_string(const StringData* s);
109 bool interface_supports_array(const StringData* s);
110 bool interface_supports_vec(const StringData* s);
111 bool interface_supports_dict(const StringData* s);
112 bool interface_supports_keyset(const StringData* s);
114 bool interface_supports_int(std::string const&);
115 bool interface_supports_double(std::string const&);
116 bool interface_supports_string(std::string const&);
117 bool interface_supports_array(std::string const&);
118 bool interface_supports_vec(std::string const&);
119 bool interface_supports_dict(std::string const&);
120 bool interface_supports_keyset(std::string const&);
122 enum class AnnotAction {
123 Pass,
124 Fail,
125 ObjectCheck,
126 CallableCheck,
127 VArrayCheck,
128 DArrayCheck,
129 VArrayOrDArrayCheck,
130 NonVArrayOrDArrayCheck
134 * annotCompat() takes a DataType (`dt') and tries to determine if a value
135 * with DataType `dt' could be compatiable with a given AnnotType (`at')
136 * and class name (`annotClsName'). Note that this function does not have
137 * access to the actual value, nor does it do any run time resolution on
138 * the annotation's class name. Here are the possible values that can be
139 * returned:
141 * Pass: A value with DataType `dt' will always be compatible with the
142 * annotation at run time.
144 * Fail: A value with DataType `dt' will never be compatible with the
145 * annotation at run time. NOTE that if the annotation is "array" and the
146 * value is a collection object, this function will return Fail but the
147 * runtime might possibly cast the collection to an array and allow normal
148 * execution to continue (see TypeConstraint::verifyFail() for details). In
149 * addition in Weak mode verifyFail may coerce certain types allowing
150 * execution to continue.
152 * CallableCheck: `at' is "callable" and a value with DataType `dt' might
153 * be compatible with the annotation, but the caller needs to consult
154 * is_callable() to verify the value is actually a valid callable.
156 * ObjectCheck: `at' is either (1) a reference to a real non-enum class or
157 * interface, (2) an enum, (3) a type alias, or (4) "self" or "parent".
158 * The caller needs to perform more checks to determine whether or not a
159 * value with DataType `dt' is compatible with the annotation. NOTE that
160 * if dt is not KindOfObject, then we've already checked if the annotation
161 * was a direct reference to a "magic" interface that supports non-object
162 * types and we've already checked if the annotation was "self" / "parent",
163 * but the caller still needs to check if the annotation is a type alias or
164 * an enum.
166 * VArrayCheck: `dt' is an array on which the caller needs to do a varray check.
168 * DArrayCheck: `dt' is an array on which the caller needs to do a darray check.
170 * VArrayOrDArrayCheck: `dt' is an array on which the caller needs to do a
171 * varray or darray check.
173 * NonVArrayOrDArrayCheck: `dt' is an array on which the caller needs to check
174 * for non-dvarray-ness.
177 inline AnnotAction
178 annotCompat(DataType dt, AnnotType at, const StringData* annotClsName) {
179 assertx(dt != KindOfRef);
180 assertx(IMPLIES(at == AnnotType::Object, annotClsName != nullptr));
182 auto const metatype = getAnnotMetaType(at);
183 switch (metatype) {
184 case AnnotMetaType::Mixed:
185 return AnnotAction::Pass;
186 case AnnotMetaType::Number:
187 return (isIntType(dt) || isDoubleType(dt))
188 ? AnnotAction::Pass : AnnotAction::Fail;
189 case AnnotMetaType::ArrayKey:
190 return (isIntType(dt) || isStringType(dt))
191 ? AnnotAction::Pass : AnnotAction::Fail;
192 case AnnotMetaType::Self:
193 case AnnotMetaType::Parent:
194 // For "self" and "parent", if `dt' is not an object we know
195 // it's not compatible, otherwise more checks are required
196 return (dt == KindOfObject)
197 ? AnnotAction::ObjectCheck : AnnotAction::Fail;
198 case AnnotMetaType::This:
199 return (dt == KindOfObject)
200 ? AnnotAction::ObjectCheck
201 : (RuntimeOption::EvalThisTypeHintLevel == 0)
202 ? AnnotAction::Pass : AnnotAction::Fail;
203 case AnnotMetaType::Callable:
204 // For "callable", if `dt' is not string/array/object we know
205 // it's not compatible, otherwise more checks are required
206 return (isStringType(dt) || isArrayType(dt) || isVecType(dt) ||
207 dt == KindOfObject)
208 ? AnnotAction::CallableCheck : AnnotAction::Fail;
209 case AnnotMetaType::VArray:
210 if (!isArrayType(dt)) return AnnotAction::Fail;
211 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices)
212 ? AnnotAction::VArrayCheck
213 : AnnotAction::Pass;
214 case AnnotMetaType::DArray:
215 if (!isArrayType(dt)) return AnnotAction::Fail;
216 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices)
217 ? AnnotAction::DArrayCheck
218 : AnnotAction::Pass;
219 case AnnotMetaType::VArrOrDArr:
220 if (!isArrayType(dt)) return AnnotAction::Fail;
221 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices)
222 ? AnnotAction::VArrayOrDArrayCheck
223 : AnnotAction::Pass;
224 case AnnotMetaType::VecOrDict:
225 return (isVecType(dt) || isDictType(dt))
226 ? AnnotAction::Pass : AnnotAction::Fail;
227 case AnnotMetaType::Precise:
228 if (UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices) &&
229 at == AnnotType::Array && isArrayType(dt)) {
230 return AnnotAction::NonVArrayOrDArrayCheck;
232 break;
235 assertx(metatype == AnnotMetaType::Precise);
236 if (at != AnnotType::Object) {
237 // If `at' is "bool", "int", "float", "string", "array", or "resource",
238 // then equivDataTypes() can definitively tell us whether or not `dt'
239 // is compatible. Uninit, to which 'HH\noreturn' maps, is special-cased
240 // because uninit and null are equivalent due to isNullType.
241 return equivDataTypes(getAnnotDataType(at), dt) && (at != AnnotType::Uninit)
242 ? AnnotAction::Pass : AnnotAction::Fail;
245 // If `dt' is not an object, check for "magic" interfaces that
246 // support non-object datatypes
247 if (dt != KindOfObject && interface_supports_non_objects(annotClsName)) {
248 switch (dt) {
249 case KindOfInt64:
250 return interface_supports_int(annotClsName)
251 ? AnnotAction::Pass : AnnotAction::Fail;
252 case KindOfDouble:
253 return interface_supports_double(annotClsName)
254 ? AnnotAction::Pass : AnnotAction::Fail;
255 case KindOfPersistentString:
256 case KindOfString:
257 return interface_supports_string(annotClsName)
258 ? AnnotAction::Pass : AnnotAction::Fail;
259 case KindOfPersistentArray:
260 case KindOfArray:
261 return interface_supports_array(annotClsName)
262 ? AnnotAction::Pass : AnnotAction::Fail;
263 case KindOfPersistentVec:
264 case KindOfVec:
265 return interface_supports_vec(annotClsName)
266 ? AnnotAction::Pass : AnnotAction::Fail;
267 case KindOfPersistentDict:
268 case KindOfDict:
269 return interface_supports_dict(annotClsName)
270 ? AnnotAction::Pass : AnnotAction::Fail;
271 case KindOfPersistentKeyset:
272 case KindOfKeyset:
273 return interface_supports_keyset(annotClsName)
274 ? AnnotAction::Pass : AnnotAction::Fail;
275 case KindOfUninit:
276 case KindOfNull:
277 case KindOfBoolean:
278 case KindOfResource:
279 return AnnotAction::Fail;
280 case KindOfObject:
281 case KindOfRef:
282 not_reached();
283 break;
287 return AnnotAction::ObjectCheck;
290 ///////////////////////////////////////////////////////////////////////////////
294 #endif