Fix bug in way function types are serialized to the Code Model.
[hiphop-php.git] / hphp / compiler / type_annotation.cpp
blob19bdd7532fe87e74faeb90329e7d7fb1953ae62e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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"
18 #include "hphp/util/util.h"
20 namespace HPHP {
22 ///////////////////////////////////////////////////////////////////////////////
23 // constructors/destructors
25 TypeAnnotation::TypeAnnotation(const std::string &name,
26 TypeAnnotationPtr typeArgs) : m_name(name),
27 m_typeArgs(typeArgs),
28 m_typeList(TypeAnnotationPtr()),
29 m_nullable(false),
30 m_soft(false),
31 m_tuple(false),
32 m_function(false),
33 m_xhp(false),
34 m_typevar(false) { }
36 std::string TypeAnnotation::vanillaName() const {
37 // filter out types that should not be exposed to the runtime
38 if (m_nullable || m_soft || m_typevar || m_function) {
39 return "";
41 if (!m_name.compare("mixed") || !m_name.compare("this")) {
42 return "";
44 return m_name;
47 std::string TypeAnnotation::fullName() const {
48 std::string name;
49 if (m_soft) {
50 name += '@';
52 if (m_nullable) {
53 name += '?';
56 if (m_function) {
57 functionTypeName(name);
58 } else if (m_xhp) {
59 xhpTypeName(name);
60 } else if (m_tuple) {
61 tupleTypeName(name);
62 } else if (m_typeArgs) {
63 genericTypeName(name);
64 } else {
65 name += m_name;
67 return name;
70 DataType TypeAnnotation::dataType(bool expectedType /*= false */) const {
71 if (m_function || m_xhp || m_tuple) {
72 return KindOfObject;
74 if (m_typeArgs) {
75 return !m_name.compare("array") ? KindOfArray : KindOfObject;
77 if (!expectedType && (m_nullable || m_soft)) {
78 return KindOfUnknown;
80 if (!m_name.compare("null") || !m_name.compare("void")) {
81 return KindOfNull;
83 if (!m_name.compare("bool")) return KindOfBoolean;
84 if (!m_name.compare("int")) return KindOfInt64;
85 if (!m_name.compare("float")) return KindOfDouble;
86 if (!m_name.compare("num")) return KindOfUnknown;
87 if (!m_name.compare("string")) return KindOfString;
88 if (!m_name.compare("array")) return KindOfArray;
89 if (!m_name.compare("resource")) return KindOfResource;
90 if (!m_name.compare("mixed")) return KindOfUnknown;
92 return KindOfObject;
95 void TypeAnnotation::getAllSimpleNames(std::vector<std::string>& names) const {
96 names.push_back(m_name);
97 if (m_typeList) {
98 m_typeList->getAllSimpleNames(names);
99 } else if (m_typeArgs) {
100 m_typeArgs->getAllSimpleNames(names);
104 void TypeAnnotation::functionTypeName(std::string &name) const {
105 name += "(function (";
106 // return value of function types is the first element of type list
107 TypeAnnotationPtr retType = m_typeArgs;
108 TypeAnnotationPtr typeEl = m_typeArgs->m_typeList;
109 bool hasArgs = (typeEl != nullptr);
110 while (typeEl) {
111 name += typeEl->fullName();
112 typeEl = typeEl->m_typeList;
113 name += ", ";
115 // replace the trailing ", " (if any) with "): "
116 if (hasArgs) {
117 name.replace(name.size() - 2, 2, "): ");
118 } else {
119 name += "): ";
121 // add function return value
122 name += retType->fullName();
123 name += ")";
126 // xhp names are mangled so we get them back to their original definition
127 // @see the mangling in ScannerToken::xhpLabel
128 void TypeAnnotation::xhpTypeName(std::string &name) const {
129 // remove prefix if any
130 if (m_name.compare(0, sizeof("xhp_") - 1, "xhp_") == 0) {
131 name += std::string(m_name).replace(0, sizeof("xhp_") - 1, ":");
132 } else {
133 name += m_name;
135 // un-mangle back
136 Util::replaceAll(name, "__", ":");
137 Util::replaceAll(name, "_", "-");
140 void TypeAnnotation::tupleTypeName(std::string &name) const {
141 name += "(";
142 TypeAnnotationPtr typeEl = m_typeArgs;
143 while (typeEl) {
144 name += typeEl->fullName();
145 typeEl = typeEl->m_typeList;
146 name += ", ";
148 // replace the trailing ", " with ")"
149 name.replace(name.size() - 2, 2, ")");
152 void TypeAnnotation::genericTypeName(std::string &name) const {
153 name += m_name;
154 name += "<";
155 TypeAnnotationPtr typeEl = m_typeArgs;
156 while (typeEl) {
157 name += typeEl->fullName();
158 typeEl = typeEl->m_typeList;
159 name += ", ";
161 // replace the trailing ", " with ">"
162 name.replace(name.size() - 2, 2, ">");
165 void TypeAnnotation::appendToTypeList(TypeAnnotationPtr typeList) {
166 if (m_typeList) {
167 TypeAnnotationPtr current = m_typeList;
168 while (current->m_typeList) {
169 current = current->m_typeList;
171 current->m_typeList = typeList;
172 } else {
173 m_typeList = typeList;
177 void TypeAnnotation::outputCodeModel(CodeGenerator& cg) {
178 TypeAnnotationPtr typeArgsElem = m_typeArgs;
179 auto numTypeArgs = 0;
180 while (typeArgsElem != nullptr) {
181 numTypeArgs++;
182 typeArgsElem = typeArgsElem->m_typeList;
184 typeArgsElem = m_typeArgs;
186 auto numProps = 1;
187 if (m_nullable) numProps++;
188 if (m_soft) numProps++;
189 if (m_function) {
190 numProps++;
191 // Since this is a function type, the first type argument is the return type
192 // and no typeArguments property will be serialized unless there are at
193 // least two type arguments.
194 if (numTypeArgs > 1) numProps++;
195 } else {
196 if (numTypeArgs > 0) numProps++;
198 cg.printObjectHeader("TypeExpression", numProps);
199 cg.printPropertyHeader("name");
200 cg.printValue(m_tuple ? "tuple" : m_name);
201 if (m_nullable) {
202 cg.printPropertyHeader("isNullable");
203 cg.printBool(true);
205 if (m_soft) {
206 cg.printPropertyHeader("isSoft");
207 cg.printBool(true);
209 if (m_function) {
210 cg.printPropertyHeader("returnType");
211 typeArgsElem->outputCodeModel(cg);
212 typeArgsElem = typeArgsElem->m_typeList;
213 // Since we've grabbed the first element of the list as the return
214 // type, make sure that the logic for serializing type arguments gets
215 // disabled unless there is at least one more type argument.
216 numTypeArgs--;
218 if (numTypeArgs > 0) {
219 cg.printPropertyHeader("typeArguments");
220 cg.printf("V:9:\"HH\\Vector\":%d:{", numTypeArgs);
221 while (typeArgsElem != nullptr) {
222 typeArgsElem->outputCodeModel(cg);
223 typeArgsElem = typeArgsElem->m_typeList;
225 cg.printf("}");
227 cg.printObjectFooter();