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 #include "hphp/compiler/type_annotation.h"
21 #include "hphp/compiler/code_generator.h"
22 #include "hphp/util/text-util.h"
23 #include "hphp/runtime/base/type-array.h"
24 #include "hphp/runtime/base/type-structure.h"
25 #include "hphp/runtime/base/type-variant.h"
29 ///////////////////////////////////////////////////////////////////////////////
30 // constructors/destructors
32 TypeAnnotation::TypeAnnotation(const std::string
&name
,
33 TypeAnnotationPtr typeArgs
) : m_name(name
),
35 m_typeList(TypeAnnotationPtr()),
44 m_clsCnsShapeField(false),
45 m_optionalShapeField(false) { }
47 std::string
TypeAnnotation::vanillaName() const {
48 // filter out types that should not be exposed to the runtime
49 if (m_nullable
|| m_soft
|| m_typevar
|| m_function
|| m_typeaccess
) {
52 if (!strcasecmp(m_name
.c_str(), "HH\\mixed") ||
53 !strcasecmp(m_name
.c_str(), "HH\\this")) {
59 std::string
TypeAnnotation::fullName() const {
69 functionTypeName(name
);
70 } else if (m_typeaccess
) {
78 } else if (m_typeArgs
) {
79 genericTypeName(name
);
86 MaybeDataType
TypeAnnotation::dataType() const {
87 if (m_function
|| m_xhp
|| m_tuple
) {
91 return !strcasecmp(m_name
.c_str(), "array") ? KindOfArray
: KindOfObject
;
93 if (m_nullable
|| m_soft
) {
96 if (!strcasecmp(m_name
.c_str(), "null") ||
97 !strcasecmp(m_name
.c_str(), "HH\\void")) {
100 if (!strcasecmp(m_name
.c_str(), "HH\\bool")) return KindOfBoolean
;
101 if (!strcasecmp(m_name
.c_str(), "HH\\int")) return KindOfInt64
;
102 if (!strcasecmp(m_name
.c_str(), "HH\\float")) return KindOfDouble
;
103 if (!strcasecmp(m_name
.c_str(), "HH\\num")) return folly::none
;
104 if (!strcasecmp(m_name
.c_str(), "HH\\arraykey")) return folly::none
;
105 if (!strcasecmp(m_name
.c_str(), "HH\\string")) return KindOfString
;
106 if (!strcasecmp(m_name
.c_str(), "array")) return KindOfArray
;
107 if (!strcasecmp(m_name
.c_str(), "HH\\dict")) return KindOfDict
;
108 if (!strcasecmp(m_name
.c_str(), "HH\\vec")) return KindOfVec
;
109 if (!strcasecmp(m_name
.c_str(), "HH\\keyset")) return KindOfKeyset
;
110 if (!strcasecmp(m_name
.c_str(), "HH\\resource")) return KindOfResource
;
111 if (!strcasecmp(m_name
.c_str(), "HH\\mixed")) return folly::none
;
116 void TypeAnnotation::getAllSimpleNames(std::vector
<std::string
>& names
) const {
117 names
.push_back(m_name
);
119 m_typeList
->getAllSimpleNames(names
);
120 } else if (m_typeArgs
) {
121 // do not return the shape fields and keys
123 m_typeArgs
->getAllSimpleNames(names
);
128 void TypeAnnotation::shapeTypeName(std::string
& name
) const {
129 name
+= "HH\\shape(";
130 TypeAnnotationPtr shapeField
= m_typeArgs
;
135 if (shapeField
->isClsCnsShapeField()) {
136 folly::toAppend(shapeField
->m_name
, &name
);
138 folly::toAppend("'", shapeField
->m_name
, "'", &name
);
140 auto fieldValue
= shapeField
->m_typeArgs
;
142 folly::toAppend("=>", fieldValue
->fullName(), &name
);
145 shapeField
= shapeField
->m_typeList
;
151 void TypeAnnotation::functionTypeName(std::string
&name
) const {
152 name
+= "(function (";
153 // return value of function types is the first element of type list
154 TypeAnnotationPtr retType
= m_typeArgs
;
155 TypeAnnotationPtr typeEl
= m_typeArgs
->m_typeList
;
158 folly::toAppend(sep
, typeEl
->fullName(), &name
);
159 typeEl
= typeEl
->m_typeList
;
162 // add function return value
163 folly::toAppend("): ", retType
->fullName(), ")", &name
);
166 // xhp names are mangled so we get them back to their original definition
167 // @see the mangling in ScannerToken::xhpLabel
168 void TypeAnnotation::xhpTypeName(std::string
&name
) const {
169 // remove prefix if any
170 if (m_name
.compare(0, sizeof("xhp_") - 1, "xhp_") == 0) {
171 name
+= std::string(m_name
).replace(0, sizeof("xhp_") - 1, ":");
176 replaceAll(name
, "__", ":");
177 replaceAll(name
, "_", "-");
180 void TypeAnnotation::tupleTypeName(std::string
&name
) const {
182 TypeAnnotationPtr typeEl
= m_typeArgs
;
185 folly::toAppend(sep
, typeEl
->fullName(), &name
);
186 typeEl
= typeEl
->m_typeList
;
192 void TypeAnnotation::genericTypeName(std::string
&name
) const {
193 folly::toAppend(m_name
, "<", &name
);
194 TypeAnnotationPtr typeEl
= m_typeArgs
;
197 folly::toAppend(sep
, typeEl
->fullName(), &name
);
198 typeEl
= typeEl
->m_typeList
;
204 void TypeAnnotation::accessTypeName(std::string
&name
) const {
206 TypeAnnotationPtr typeEl
= m_typeArgs
;
208 folly::toAppend("::", typeEl
->fullName(), &name
);
209 typeEl
= typeEl
->m_typeList
;
213 void TypeAnnotation::appendToTypeList(TypeAnnotationPtr typeList
) {
215 TypeAnnotationPtr current
= m_typeList
;
216 while (current
->m_typeList
) {
217 current
= current
->m_typeList
;
219 current
->m_typeList
= typeList
;
221 m_typeList
= typeList
;
225 int TypeAnnotation::numTypeArgs() const {
227 TypeAnnotationPtr typeEl
= m_typeArgs
;
230 typeEl
= typeEl
->m_typeList
;
235 TypeAnnotationPtr
TypeAnnotation::getTypeArg(int n
) const {
237 TypeAnnotationPtr typeEl
= m_typeArgs
;
243 typeEl
= typeEl
->m_typeList
;
245 return TypeAnnotationPtr();
248 bool TypeAnnotation::isPrimType(const char* str
) const{
249 return !strcasecmp(m_name
.c_str(), str
);
252 TypeStructure::Kind
TypeAnnotation::getKind() const {
254 return TypeStructure::Kind::T_void
;
258 if (isPrimType("HH\\int")) {
259 return TypeStructure::Kind::T_int
;
261 if (isPrimType("HH\\bool")) {
262 return TypeStructure::Kind::T_bool
;
264 if (isPrimType("HH\\float")) {
265 return TypeStructure::Kind::T_float
;
267 if (isPrimType("HH\\string")) {
268 return TypeStructure::Kind::T_string
;
270 if (isPrimType("HH\\resource")) {
271 return TypeStructure::Kind::T_resource
;
273 if (isPrimType("HH\\num")) {
274 return TypeStructure::Kind::T_num
;
276 if (isPrimType("HH\\arraykey")) {
277 return TypeStructure::Kind::T_arraykey
;
279 if (isPrimType("HH\\noreturn")) {
280 return TypeStructure::Kind::T_noreturn
;
284 return TypeStructure::Kind::T_mixed
;
287 return TypeStructure::Kind::T_tuple
;
290 return TypeStructure::Kind::T_fun
;
292 if (!strcasecmp(m_name
.c_str(), "array")) {
294 ? TypeStructure::Kind::T_shape
295 : TypeStructure::Kind::T_array
;
297 if (!strcasecmp(m_name
.c_str(), "HH\\dict")) {
298 return TypeStructure::Kind::T_dict
;
300 if (!strcasecmp(m_name
.c_str(), "HH\\vec")) {
301 return TypeStructure::Kind::T_vec
;
303 if (!strcasecmp(m_name
.c_str(), "HH\\keyset")) {
304 return TypeStructure::Kind::T_keyset
;
307 return TypeStructure::Kind::T_typevar
;
310 return TypeStructure::Kind::T_typeaccess
;
313 // TODO(7657500): in the runtime, resolve this type to a class.
314 return TypeStructure::Kind::T_xhp
;
317 return TypeStructure::Kind::T_unresolved
;
321 s_nullable("nullable"),
324 s_classname("classname"),
325 s_elem_types("elem_types"),
326 s_return_type("return_type"),
327 s_param_types("param_types"),
328 s_generic_types("generic_types"),
329 s_root_name("root_name"),
330 s_access_list("access_list"),
332 s_is_cls_cns("is_cls_cns"),
334 s_typevars("typevars")
337 /* Turns the argsList linked list of TypeAnnotation into a positioned
339 Array
TypeAnnotation::argsListToScalarArray(TypeAnnotationPtr ta
) const {
341 auto typeargs
= Array::Create();
345 typeargs
.add(i
, Variant(typeEl
->getScalarArrayRep()));
347 typeEl
= typeEl
->m_typeList
;
352 void TypeAnnotation::shapeFieldsToScalarArray(Array
& rep
,
353 TypeAnnotationPtr ta
) const {
354 auto fields
= Array::Create();
355 auto shapeField
= ta
;
357 assert(shapeField
->m_typeArgs
);
358 auto field
= Array::Create();
359 if (shapeField
->isClsCnsShapeField()) field
.add(s_is_cls_cns
, true_varNR
);
360 field
.add(s_value
, Variant(shapeField
->m_typeArgs
->getScalarArrayRep()));
361 fields
.add(String(shapeField
->m_name
), Variant(field
.get()));
362 shapeField
= shapeField
->m_typeList
;
364 rep
.add(s_fields
, Variant(fields
));
367 Array
TypeAnnotation::getScalarArrayRep() const {
368 auto rep
= Array::Create();
370 bool nullable
= (bool) m_nullable
;
372 rep
.add(s_nullable
, true_varNR
);
375 TypeStructure::Kind kind
= getKind();
376 rep
.add(s_kind
, Variant(static_cast<uint8_t>(kind
)));
379 case TypeStructure::Kind::T_tuple
:
381 rep
.add(s_elem_types
, Variant(argsListToScalarArray(m_typeArgs
)));
383 case TypeStructure::Kind::T_fun
:
385 // return type is the first of the typeArgs
386 rep
.add(s_return_type
, Variant(m_typeArgs
->getScalarArrayRep()));
387 rep
.add(s_param_types
,
388 Variant(argsListToScalarArray(m_typeArgs
->m_typeList
)));
390 case TypeStructure::Kind::T_array
:
391 case TypeStructure::Kind::T_dict
:
392 case TypeStructure::Kind::T_vec
:
393 case TypeStructure::Kind::T_keyset
:
395 rep
.add(s_generic_types
, Variant(argsListToScalarArray(m_typeArgs
)));
398 case TypeStructure::Kind::T_shape
:
399 shapeFieldsToScalarArray(rep
, m_typeArgs
);
401 case TypeStructure::Kind::T_typevar
:
402 rep
.add(s_name
, Variant(m_name
));
404 case TypeStructure::Kind::T_typeaccess
: {
405 // for now, only store the vanilla names (strings) as part of the
407 rep
.add(s_root_name
, Variant(m_name
));
408 auto accList
= Array::Create();
409 auto typeEl
= m_typeArgs
;
412 accList
.add(i
, Variant(typeEl
->vanillaName()));
414 typeEl
= typeEl
->m_typeList
;
416 rep
.add(s_access_list
, Variant(accList
));
419 case TypeStructure::Kind::T_xhp
:
420 rep
.add(s_classname
, Variant(m_name
));
422 case TypeStructure::Kind::T_unresolved
:
423 rep
.add(s_classname
, Variant(m_name
));
425 rep
.add(s_generic_types
, Variant(argsListToScalarArray(m_typeArgs
)));
432 if (!m_generics
.empty()) {
433 rep
.add(s_typevars
, Variant(m_generics
));