add bitset operations and tests
[hiphop-php.git] / hphp / runtime / vm / type-constraint.h
blobf5738b6d217b8a4f7bc766173b366076b7c43e8a
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_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"
26 #include <functional>
27 #include <string>
29 namespace HPHP {
30 struct Func;
31 struct StringData;
34 namespace HPHP {
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 {
44 NoFlags = 0x0,
47 * Nullable type hints check they are either the specified type,
48 * or null.
50 Nullable = 0x1,
53 * This flag indicates either EnableHipHopSyntax was true, or the
54 * type came from a <?hh file and EnableHipHopSyntax was false.
56 HHType = 0x2,
59 * Extended hints are hints that do not apply to normal, vanilla
60 * php. For example "?Foo".
62 ExtendedHint = 0x4,
65 * Indicates that a type constraint is a type variable. For example,
66 * the constraint on $x is a TypeVar.
67 * class Foo<T> {
68 * public function bar(T $x) { ... }
69 * }
71 TypeVar = 0x8,
74 * Soft type hints: triggers warning, but never fatals
75 * E.g. "@int"
77 Soft = 0x10,
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
82 * is a TypeConstant:
84 * class Foo {
85 * const type T = int;
86 * public function bar(Foo::T $x) { ... }
87 * }
89 TypeConstant = 0x20,
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.
96 Resolved = 0x40
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;
110 TypeConstraint()
111 : m_flags(NoFlags)
112 , m_typeName(nullptr)
113 , m_namedEntity(nullptr)
115 init();
118 TypeConstraint(const StringData* typeName, Flags flags)
119 : m_flags(flags)
120 , m_typeName(typeName)
121 , m_namedEntity(nullptr)
123 assert(!(flags & Flags::Resolved));
124 init();
127 template<class SerDe>
128 void serde(SerDe& sd) {
129 sd(m_typeName)
130 (m_flags)
132 if (m_flags & Flags::Resolved) {
133 sd(m_type);
135 if (SerDe::deserializing) {
136 init();
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);
149 m_type = t;
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())
177 ? MaybeDataType(dt)
178 : folly::none;
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 {
220 std::string name;
221 if (isSoft()) {
222 name += '@';
224 if (isNullable() && isExtended()) {
225 name += '?';
227 name += m_typeName->data();
228 if (isNullable() && !isExtended()) {
229 name += " (defaulted to null)";
231 return name;
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);
275 private:
276 void init();
277 void selfToTypeName(const Func* func, const StringData **typeName) const;
278 void parentToTypeName(const Func* func, const StringData **typeName) const;
280 private:
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()
285 // for details).
286 Type m_type;
287 Flags m_flags;
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 {
316 Null,
317 Int,
318 IntOrNull,
319 Bool,
320 BoolOrNull,
321 Str,
322 StrOrNull,
323 IntOrStr,
324 None
326 MemoKeyConstraint memoKeyConstraintFromTC(const TypeConstraint&);
330 #endif