2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_TYPE_CONSTRAINT_H_
17 #define incl_HPHP_TYPE_CONSTRAINT_H_
20 #include <tr1/functional>
22 #include "hphp/runtime/base/types.h"
23 #include "hphp/util/case_insensitive.h"
24 #include "hphp/runtime/vm/unit.h"
25 #include "hphp/runtime/vm/type_profile.h"
31 class TypeConstraint
{
37 * Nullable type hints check they are either the specified type,
43 * This flag indicates either EnableHipHopSyntax was true, or the
44 * type came from a <?hh file and EnableHipHopSyntax was false.
49 * Extended hints are hints that do not apply to normal, vanilla
50 * php. For example "?Foo".
66 constexpr bool isParent() const {
67 return m_metatype
== MetaType::Parent
;
69 constexpr bool isSelf() const {
70 return m_metatype
== MetaType::Self
;
72 constexpr bool isCallable() const {
73 return m_metatype
== MetaType::Callable
;
75 constexpr bool isPrecise() const {
76 return m_metatype
== MetaType::Precise
;
80 // m_type represents the DataType to check on. We don't know
81 // whether a bare name is a class/interface name or a typedef, so
82 // when this is set to KindOfObject we may have to look up a typedef
83 // name and test for a different DataType.
86 const StringData
* m_typeName
;
87 const NamedEntity
* m_namedEntity
;
88 typedef hphp_hash_map
<const StringData
*, Type
,
89 string_data_hash
, string_data_isame
> TypeMap
;
90 static TypeMap s_typeNamesToTypes
;
95 void verifyFail(const Func
* func
, int paramNum
, const TypedValue
* tv
) const;
100 , m_namedEntity(nullptr)
105 TypeConstraint(const StringData
* typeName
, Flags flags
)
107 , m_typeName(typeName
)
108 , m_namedEntity(nullptr)
113 TypeConstraint(const TypeConstraint
&) = default;
114 TypeConstraint
& operator=(const TypeConstraint
&) = default;
116 bool hasConstraint() const { return m_typeName
; }
118 const StringData
* typeName() const { return m_typeName
; }
119 const NamedEntity
* namedEntity() const { return m_namedEntity
; }
121 bool nullable() const { return m_flags
& Nullable
; }
122 bool hhType() const { return m_flags
& HHType
; }
123 Flags
flags() const { return m_flags
; }
125 bool isSelf() const {
126 return m_type
.isSelf();
129 bool isParent() const {
130 return m_type
.isParent();
133 bool isCallable() const {
134 return m_type
.isCallable();
137 bool isPrecise() const {
138 return m_type
.isPrecise();
141 bool isObjectOrTypedef() const {
142 assert(IMPLIES(isParent(), m_type
.m_dt
== KindOfObject
));
143 assert(IMPLIES(isSelf(), m_type
.m_dt
== KindOfObject
));
144 assert(IMPLIES(isCallable(), m_type
.m_dt
== KindOfObject
));
145 return m_type
.m_dt
== KindOfObject
;
148 bool compat(const TypeConstraint
& other
) const {
149 if (other
.isExtended() || isExtended()) {
151 * Rely on the ahead of time typechecker---checking here can
152 * make it harder to convert a base class or interface to <?hh,
153 * because derived classes that are still <?php would all need
158 return (m_typeName
== other
.m_typeName
159 || (m_typeName
!= nullptr && other
.m_typeName
!= nullptr
160 && m_typeName
->isame(other
.m_typeName
)));
163 static bool equivDataTypes(DataType t1
, DataType t2
) {
166 (IS_STRING_TYPE(t1
) && IS_STRING_TYPE(t2
)) ||
167 (IS_NULL_TYPE(t1
) && IS_NULL_TYPE(t2
));
170 // General check for any constraint.
171 bool check(const TypedValue
* tv
, const Func
* func
) const;
173 // Check a constraint when !isObjectOrTypedef().
174 bool checkPrimitive(DataType dt
) const;
176 // Typedef checks when we know tv is or is not an object.
177 bool checkTypedefObj(const TypedValue
* tv
) const;
178 bool checkTypedefNonObj(const TypedValue
* tv
) const;
180 // NB: will throw if the check fails.
181 void verify(const TypedValue
* tv
,
182 const Func
* func
, int paramNum
) const {
183 if (UNLIKELY(!check(tv
, func
))) {
184 verifyFail(func
, paramNum
, tv
);
188 // Can not be private as it needs to be used by the translator
189 void selfToClass(const Func
* func
, const Class
**cls
) const;
190 void parentToClass(const Func
* func
, const Class
**cls
) const;
192 bool isExtended() const { return m_flags
& ExtendedHint
; }
194 void selfToTypeName(const Func
* func
, const StringData
**typeName
) const;
195 void parentToTypeName(const Func
* func
, const StringData
**typeName
) const;
198 inline TypeConstraint::Flags
199 operator|(TypeConstraint::Flags a
, TypeConstraint::Flags b
) {
200 return TypeConstraint::Flags(static_cast<int>(a
) | static_cast<int>(b
));