2 +----------------------------------------------------------------------+
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"
27 ///////////////////////////////////////////////////////////////////////////////
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 {
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
;
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
{
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
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
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.
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
);
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
) ||
208 ? AnnotAction::CallableCheck
: AnnotAction::Fail
;
209 case AnnotMetaType::VArray
:
210 if (!isArrayType(dt
)) return AnnotAction::Fail
;
211 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices
)
212 ? AnnotAction::VArrayCheck
214 case AnnotMetaType::DArray
:
215 if (!isArrayType(dt
)) return AnnotAction::Fail
;
216 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices
)
217 ? AnnotAction::DArrayCheck
219 case AnnotMetaType::VArrOrDArr
:
220 if (!isArrayType(dt
)) return AnnotAction::Fail
;
221 return UNLIKELY(RuntimeOption::EvalHackArrCompatTypeHintNotices
)
222 ? AnnotAction::VArrayOrDArrayCheck
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
;
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
)) {
250 return interface_supports_int(annotClsName
)
251 ? AnnotAction::Pass
: AnnotAction::Fail
;
253 return interface_supports_double(annotClsName
)
254 ? AnnotAction::Pass
: AnnotAction::Fail
;
255 case KindOfPersistentString
:
257 return interface_supports_string(annotClsName
)
258 ? AnnotAction::Pass
: AnnotAction::Fail
;
259 case KindOfPersistentArray
:
261 return interface_supports_array(annotClsName
)
262 ? AnnotAction::Pass
: AnnotAction::Fail
;
263 case KindOfPersistentVec
:
265 return interface_supports_vec(annotClsName
)
266 ? AnnotAction::Pass
: AnnotAction::Fail
;
267 case KindOfPersistentDict
:
269 return interface_supports_dict(annotClsName
)
270 ? AnnotAction::Pass
: AnnotAction::Fail
;
271 case KindOfPersistentKeyset
:
273 return interface_supports_keyset(annotClsName
)
274 ? AnnotAction::Pass
: AnnotAction::Fail
;
279 return AnnotAction::Fail
;
287 return AnnotAction::ObjectCheck
;
290 ///////////////////////////////////////////////////////////////////////////////