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_TYPE_CONSTRAINT_H_
18 #define incl_HPHP_TYPE_CONSTRAINT_H_
20 #include "hphp/runtime/base/annot-type.h"
21 #include "hphp/runtime/vm/named-entity.h"
22 #include "hphp/runtime/vm/type-profile.h"
24 #include "hphp/util/functional.h"
36 //////////////////////////////////////////////////////////////////////
39 * TypeConstraint represents the metadata required to check a PHP
40 * function or method parameter typehint at runtime.
42 struct TypeConstraint
{
43 enum Flags
: uint8_t {
47 * Nullable type hints check they are either the specified type,
53 * This flag indicates either EnableHipHopSyntax was true, or the
54 * type came from a <?hh file and EnableHipHopSyntax was false.
59 * Extended hints are hints that do not apply to normal, vanilla
60 * php. For example "?Foo".
65 * Indicates that a type constraint is a type variable. For example,
66 * the constraint on $x is a TypeVar.
68 * public function bar(T $x) { ... }
74 * Soft type hints: triggers warning, but never fatals
80 * Indicates a type constraint is a type constant, which is similar to a
81 * type alias defined inside a class. For instance, the constraint on $x
86 * public function bar(Foo::T $x) { ... }
92 * Indicates that a Object type-constraint was resolved by hhbbc,
93 * and the actual type is in m_type. When set, Object is guaranteed
94 * to be an object, not a type-alias.
100 * Special type constraints use a "Type", instead of just
101 * underlyingDataType().
103 * See underlyingDataType().
105 using Type
= AnnotType
;
106 using MetaType
= AnnotMetaType
;
108 static const int32_t ReturnId
= -1;
112 , m_typeName(nullptr)
113 , m_namedEntity(nullptr)
118 TypeConstraint(const StringData
* typeName
, Flags flags
)
120 , m_typeName(typeName
)
121 , m_namedEntity(nullptr)
123 assert(!(flags
& Flags::Resolved
));
127 template<class SerDe
>
128 void serde(SerDe
& sd
) {
132 if (m_flags
& Flags::Resolved
) {
135 if (SerDe::deserializing
) {
140 TypeConstraint(const TypeConstraint
&) = default;
141 TypeConstraint
& operator=(const TypeConstraint
&) = default;
143 void resolveType(AnnotType t
, bool nullable
) {
144 assert(m_type
== AnnotType::Object
);
145 assert(t
!= AnnotType::Object
);
146 auto flags
= m_flags
| Flags::Resolved
;
147 if (nullable
) flags
|= Flags::Nullable
;
148 m_flags
= static_cast<Flags
>(flags
);
153 * Returns: whether this constraint implies any runtime checking at
154 * all. If this function returns false, it means the
155 * VerifyParamType would be a no-op.
157 bool hasConstraint() const { return m_typeName
; }
160 * Read access to various members.
162 const StringData
* typeName() const { return m_typeName
; }
163 const NamedEntity
* namedEntity() const { return m_namedEntity
; }
164 Flags
flags() const { return m_flags
; }
167 * Access to the "meta type" for this TypeConstraint.
169 MetaType
metaType() const { return getAnnotMetaType(m_type
); }
172 * Returns the underlying DataType for this TypeConstraint.
174 MaybeDataType
underlyingDataType() const {
175 auto const dt
= getAnnotDataType(m_type
);
176 return (dt
!= KindOfUninit
|| isPrecise())
182 * Returns the underlying DataType for this TypeConstraint,
183 * chasing down type aliases.
185 MaybeDataType
underlyingDataTypeResolved() const;
188 * Predicates for various properties of the type constraint.
190 bool isNullable() const { return m_flags
& Nullable
; }
191 bool isSoft() const { return m_flags
& Soft
; }
192 bool isHHType() const { return m_flags
& HHType
; }
193 bool isExtended() const { return m_flags
& ExtendedHint
; }
194 bool isTypeVar() const { return m_flags
& TypeVar
; }
195 bool isTypeConstant() const { return m_flags
& TypeConstant
; }
196 bool isResolved() const { return m_flags
& Resolved
; }
198 bool isPrecise() const { return metaType() == MetaType::Precise
; }
199 bool isMixed() const { return m_type
== Type::Mixed
; }
200 bool isSelf() const { return m_type
== Type::Self
; }
201 bool isThis() const { return m_type
== Type::This
; }
202 bool isParent() const { return m_type
== Type::Parent
; }
203 bool isCallable() const { return m_type
== Type::Callable
; }
204 bool isNumber() const { return m_type
== Type::Number
; }
205 bool isArrayKey() const { return m_type
== Type::ArrayKey
; }
207 bool isArray() const { return m_type
== Type::Array
; }
208 bool isDict() const { return m_type
== Type::Dict
; }
209 bool isVec() const { return m_type
== Type::Vec
; }
210 bool isKeyset() const { return m_type
== Type::Keyset
; }
212 bool isObject() const { return m_type
== Type::Object
; }
214 AnnotType
type() const { return m_type
; }
217 * A string representation of this type constraint.
219 std::string
fullName() const {
224 if (isNullable() && isExtended()) {
227 name
+= m_typeName
->data();
228 if (isNullable() && !isExtended()) {
229 name
+= " (defaulted to null)";
234 std::string
displayName(const Func
* func
= nullptr, bool extra
= false) const;
237 * Returns: whether two TypeConstraints are compatible, in the sense
238 * required for PHP inheritance where a method with parameter
239 * typehints is overridden.
241 bool compat(const TypeConstraint
& other
) const;
243 // General check for any constraint.
244 bool check(TypedValue
* tv
, const Func
* func
) const;
246 bool checkTypeAliasObj(const Class
* cls
) const;
247 bool checkTypeAliasNonObj(const TypedValue
* tv
) const;
249 // NB: will throw if the check fails.
250 void verifyParam(TypedValue
* tv
, const Func
* func
, int paramNum
,
251 bool useStrictTypes
= true) const {
252 if (UNLIKELY(!check(tv
, func
))) {
253 verifyParamFail(func
, tv
, paramNum
, useStrictTypes
);
256 void verifyReturn(TypedValue
* tv
, const Func
* func
,
257 bool useStrictTypes
= true) const {
258 if (UNLIKELY(!check(tv
, func
))) {
259 verifyReturnFail(func
, tv
, useStrictTypes
);
263 // Can not be private; used by the translator.
264 void selfToClass(const Func
* func
, const Class
**cls
) const;
265 void parentToClass(const Func
* func
, const Class
**cls
) const;
266 void verifyFail(const Func
* func
, TypedValue
* tv
, int id
,
267 bool useStrictTypes
) const;
268 void verifyParamFail(const Func
* func
, TypedValue
* tv
,
269 int paramNum
, bool useStrictTypes
= true) const;
270 void verifyReturnFail(const Func
* func
, TypedValue
* tv
,
271 bool useStrictTypes
= true) const {
272 verifyFail(func
, tv
, ReturnId
, useStrictTypes
);
277 void selfToTypeName(const Func
* func
, const StringData
**typeName
) const;
278 void parentToTypeName(const Func
* func
, const StringData
**typeName
) const;
281 // m_type represents the type to check on. We don't know whether a
282 // bare name is a class/interface name or a type alias or an enum,
283 // so when this is set to Type::Object we may have to resolve a type
284 // alias or enum and test for a different DataType (see annotCompat()
288 LowStringPtr m_typeName
;
289 LowPtr
<const NamedEntity
> m_namedEntity
;
292 //////////////////////////////////////////////////////////////////////
294 inline TypeConstraint::Flags
295 operator|(TypeConstraint::Flags a
, TypeConstraint::Flags b
) {
296 return TypeConstraint::Flags(static_cast<int>(a
) | static_cast<int>(b
));
299 //////////////////////////////////////////////////////////////////////
302 * Its possible to use type constraints on function parameters to devise better
303 * memoization key generation schemes. For example, if we know the
304 * type-constraint limits the parameter to only ever being an integer or string,
305 * then the memoization key scheme can just be the identity. This is because
306 * integers and strings won't collide with each other, and we know it won't ever
307 * be anything else. Without such a constraint, the string would need escaping.
309 * This function takes a type-constraint and returns the suitable "memo-key
310 * constraint" if it corresponds to one. Note: HHBBC, the interpreter, and the
311 * JIT all need to agree exactly on the scheme for each constraint. It is the
312 * caller's responsibility to actually verify that type-hints are being
313 * enforced. If they are not, then none of this information can be used.
315 enum class MemoKeyConstraint
{
326 MemoKeyConstraint
memoKeyConstraintFromTC(const TypeConstraint
&);