PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test/test_type_inference.cpp

https://github.com/tmjnaid/hiphop-php
C++ | 451 lines | 367 code | 41 blank | 43 comment | 0 complexity | 8a55f0283a56f7f61bbf1f40b680db1c MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010 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. +----------------------------------------------------------------------+
  15. */
  16. #include <test/test_type_inference.h>
  17. using namespace std;
  18. ///////////////////////////////////////////////////////////////////////////////
  19. TestTypeInference::TestTypeInference() {
  20. m_verbose = false;
  21. }
  22. bool TestTypeInference::RunTests(const std::string &which) {
  23. bool ret = true;
  24. RUN_TEST(TestLocalVariable);
  25. RUN_TEST(TestDynamicLocalVariable);
  26. RUN_TEST(TestClassConstant);
  27. RUN_TEST(TestClassVariable);
  28. RUN_TEST(TestDynamicClassVariable);
  29. RUN_TEST(TestGlobalConstant);
  30. RUN_TEST(TestGlobalVariable);
  31. RUN_TEST(TestDynamicGlobalVariable);
  32. RUN_TEST(TestFunctionReturn);
  33. RUN_TEST(TestFunctionParameter);
  34. RUN_TEST(TestMethodParameter);
  35. return ret;
  36. }
  37. ///////////////////////////////////////////////////////////////////////////////
  38. /**
  39. * Local variables are well-scoped. If either l-dynamic variable or r-dynamic
  40. * variable is present, a local variable table needs to set up and all
  41. * local variables become Variants.
  42. */
  43. bool TestTypeInference::TestLocalVariable() {
  44. // l-value infers types
  45. VT("<?php function t() { $a = 1;}",
  46. "void f_t();\n"
  47. "void f_t() {\n"
  48. " int64 v_a = 0;\n"
  49. " \n"
  50. " v_a = 1;\n"
  51. "}\n");
  52. // two different types should coerce
  53. VT("<?php function t() { $a = 1; $a = 'test';}",
  54. "void f_t();\n"
  55. "void f_t() {\n"
  56. " Variant v_a;\n"
  57. " \n"
  58. " v_a = 1;\n"
  59. " v_a = \"test\";\n"
  60. "}\n");
  61. // r-value should not modify inferred type...
  62. VT("<?php function t() { $a = 1; print $a;}",
  63. "void f_t();\n"
  64. "void f_t() {\n"
  65. " int64 v_a = 0;\n"
  66. " \n"
  67. " v_a = 1;\n"
  68. " print(toString(v_a));\n"
  69. "}\n");
  70. // ...although it could, when some expressions require certain types.
  71. VT("<?php function t() { $a = 1; foreach($a as $b) {}}",
  72. "void f_t();\n"
  73. "void f_t() {\n"
  74. " Variant v_a;\n"
  75. " Variant v_b;\n"
  76. " \n"
  77. " v_a = 1;\n"
  78. " {\n"
  79. " Variant map2 = (toArray(v_a));\n"
  80. " for (ArrayIter iter3 = map2.begin(); !iter3.end(); iter3.next()) {\n"
  81. " v_b = iter3.second();\n"
  82. " {\n"
  83. " }\n"
  84. " goto continue1; continue1:;\n"
  85. " }\n"
  86. " goto break1; break1:;\n"
  87. " }\n"
  88. "}\n");
  89. // this would be problematic if type inference only has one pass
  90. VT("<?php function t() { $a = 1; while(true){ $b=$a; print $b; $a='t';}}",
  91. "void f_t();\n"
  92. "void f_t() {\n"
  93. " Variant v_a;\n"
  94. " Variant v_b;\n"
  95. " \n"
  96. " v_a = 1;\n"
  97. " {\n"
  98. " while (true) {\n"
  99. " {\n"
  100. " v_b = v_a;\n"
  101. " print(toString(v_b));\n"
  102. " v_a = \"t\";\n"
  103. " }\n"
  104. " goto continue1; continue1:;\n"
  105. " }\n"
  106. " goto break1; break1:;\n"
  107. " }\n"
  108. "}\n");
  109. return true;
  110. }
  111. bool TestTypeInference::TestDynamicLocalVariable() {
  112. // l-dynamic variable
  113. VT("<?php function t() { $a = 1; $$b = 'test'; print $a;}",
  114. "void f_t();\n"
  115. "void f_t() {\n"
  116. " Variant v_a;\n"
  117. " Variant v_b;\n"
  118. " \n"
  119. " v_a = 1;\n"
  120. " variables->get(toString(v_b)) = \"test\";\n"
  121. " print(toString(v_a));\n"
  122. "}\n");
  123. // r-dynamic variable doesn't change inferrence results
  124. VT("<?php function t() { $a = 1; print $$a;}",
  125. "void f_t();\n"
  126. "void f_t() {\n"
  127. " int64 v_a = 0;\n"
  128. " \n"
  129. " v_a = 1;\n"
  130. " print(toString(variables->get(toString(v_a))));\n"
  131. "}\n");
  132. // extract() is the same as assigning values to l-dynamic variables
  133. VT("<?php function t($a) { extract($a);}",
  134. "void f_t(Variant v_a);\n"
  135. "void f_t(Variant v_a) {\n"
  136. " extract(variables, toArray(v_a));\n"
  137. "}\n");
  138. return true;
  139. }
  140. bool TestTypeInference::TestClassConstant() {
  141. // a class constant always infers its type from its initial value
  142. VT("<?php class T { const a = 1; } print T::a;",
  143. "extern const int64 q_t_a;\n"
  144. "class c_t : public ObjectData {\n"
  145. " void c_t::init();\n"
  146. "};\n"
  147. "const int64 q_t_a = 1;\n"
  148. "c_t::c_t() {\n"
  149. "}\n"
  150. "void c_t::init() {\n"
  151. "}\n"
  152. "print(toString(q_t_a));\n");
  153. // r-value won't modify its type
  154. VT("<?php class T { const a = 'test'; } T::a + 1;",
  155. "extern const String q_t_a;\n"
  156. "class c_t : public ObjectData {\n"
  157. " void c_t::init();\n"
  158. "};\n"
  159. "const String q_t_a = \"test\";\n"
  160. "c_t::c_t() {\n"
  161. "}\n"
  162. "void c_t::init() {\n"
  163. "}\n"
  164. "(Variant)(q_t_a) + 1;\n");
  165. return true;
  166. }
  167. bool TestTypeInference::TestClassVariable() {
  168. // l-value infers types
  169. VT("<?php class T { var $a; function t() { $this->a = 1;}}",
  170. "class c_t : public ObjectData {\n"
  171. " void c_t::init();\n"
  172. " public: int64 m_a;\n"
  173. " public: void t___construct();\n"
  174. " public: ObjectData *create();\n"
  175. " public: ObjectData *dynCreate(const Array &params, bool init = true);\n"
  176. "};\n"
  177. "ObjectData *c_t::create() {\n"
  178. " init();\n"
  179. " t___construct();\n"
  180. " return this;\n"
  181. "}\n"
  182. "ObjectData *c_t::dynCreate(const Array &params, bool init /* = true */) {\n"
  183. " if (init) {\n"
  184. " return (create());\n"
  185. " } else return this;\n"
  186. "}\n"
  187. "c_t::c_t() {\n"
  188. "}\n"
  189. "void c_t::init() {\n"
  190. " m_a = 0;\n"
  191. "}\n"
  192. "void c_t::t___construct() {\n"
  193. " m_a = 1;\n"
  194. "}\n"
  195. );
  196. // 1st one got a narrower type of "int64" because of 2nd pass
  197. VT("<?php class T { var $a;} function t() { $b = new T(); $c = $b->a;} function t2() { $b = new T(); $b->a = 1;}",
  198. "void f_t();\n"
  199. "void f_t2();\n"
  200. "class c_t : public ObjectData {\n"
  201. " void c_t::init();\n"
  202. " public: int64 m_a;\n"
  203. "};\n"
  204. "c_t::c_t() {\n"
  205. "}\n"
  206. "void c_t::init() {\n"
  207. " m_a = 0;\n"
  208. "}\n"
  209. "void f_t() {\n"
  210. " sp_t v_b;\n"
  211. " int64 v_c = 0;\n"
  212. " \n"
  213. " v_b = sp_t(sp_t(NEW(c_t)())->create());\n"
  214. " v_c = v_b->m_a;\n"
  215. "}\n"
  216. "void f_t2() {\n"
  217. " sp_t v_b;\n"
  218. " \n"
  219. " v_b = sp_t(sp_t(NEW(c_t)())->create());\n"
  220. " v_b->m_a = 1;\n"
  221. "}\n"
  222. );
  223. return true;
  224. }
  225. bool TestTypeInference::TestDynamicClassVariable() {
  226. // property table would handle this
  227. VT("<?php class T { var $a; function t() { $this->$a = 1;}}",
  228. "class c_t : public ObjectData {\n"
  229. " void c_t::init();\n"
  230. " public: Variant m_a;\n"
  231. " public: void t___construct();\n"
  232. " public: ObjectData *create();\n"
  233. " public: ObjectData *dynCreate(const Array &params, bool init = true);\n"
  234. "};\n"
  235. "ObjectData *c_t::create() {\n"
  236. " init();\n"
  237. " t___construct();\n"
  238. " return this;\n"
  239. "}\n"
  240. "ObjectData *c_t::dynCreate(const Array &params, bool init /* = true */) {\n"
  241. " if (init) {\n"
  242. " return (create());\n"
  243. " } else return this;\n"
  244. "}\n"
  245. "c_t::c_t() {\n"
  246. "}\n"
  247. "void c_t::init() {\n"
  248. "}\n"
  249. "void c_t::t___construct() {\n"
  250. " Variant v_a;\n"
  251. " \n"
  252. " o_lval(toString(v_a), -1LL) = 1;\n"
  253. "}\n"
  254. );
  255. return true;
  256. }
  257. /**
  258. * Global variables might be easier than class variables, because they are
  259. * always initilized with inferrable values.
  260. */
  261. bool TestTypeInference::TestGlobalConstant() {
  262. VT("<?php define('T', 'test'); $a = T;",
  263. "Variant gv_a;\n"
  264. "\n"
  265. "const String k_T = \"test\";\n"
  266. "\n"
  267. ";\n"
  268. "gv_a = k_T;\n");
  269. VT("<?php apc_fetch(0, 0, A);",
  270. "const String k_A = \"A\";\n\n"
  271. "f_apc_fetch(toString(0), ref(lval(0)), toInt64(k_A));\n");
  272. return true;
  273. }
  274. bool TestTypeInference::TestGlobalVariable() {
  275. VT("<?php $a = 1; function t() { $b = $GLOBALS['a'];}",
  276. "Variant gv_a;\n"
  277. "\n"
  278. "void f_t();\n"
  279. "void f_t() {\n"
  280. " Variant v_b;\n"
  281. " \n"
  282. " v_b = gv_a;\n"
  283. "}\n"
  284. "gv_a = 1;\n");
  285. VT("<?php function t() { $b = $GLOBALS['a'];}",
  286. "Variant gv_a;\n"
  287. "\n"
  288. "void f_t();\n"
  289. "void f_t() {\n"
  290. " Variant v_b;\n"
  291. " \n"
  292. " v_b = gv_a;\n"
  293. "}\n");
  294. return true;
  295. }
  296. bool TestTypeInference::TestDynamicGlobalVariable() {
  297. VT("<?php $a = 1; print $$a;",
  298. "Variant gv_a;\n"
  299. "\n"
  300. "gv_a = 1;\n"
  301. "print(toString(variables->get(toString(gv_a))));\n");
  302. return true;
  303. }
  304. /**
  305. * The hardest type inference is actually function's, whose depend on each
  306. * other and multiple passes are needed.
  307. */
  308. bool TestTypeInference::TestFunctionReturn() {
  309. VT("<?php function t() { return 1;} $a = t();",
  310. "Variant gv_a;\n"
  311. "\n"
  312. "int64 f_t();\n"
  313. "int64 f_t() {\n"
  314. " return 1;\n"
  315. "}\n"
  316. "gv_a = f_t();\n");
  317. VT("<?php $a = t(); function t() { return r();} function r() { return 1;}",
  318. "Variant gv_a;\n"
  319. "\n"
  320. "int64 f_r();\n"
  321. "int64 f_t();\n"
  322. "int64 f_r() {\n"
  323. " return 1;\n"
  324. "}\n"
  325. "int64 f_t() {\n"
  326. " return f_r();\n"
  327. "}\n"
  328. "gv_a = f_t();\n");
  329. return true;
  330. }
  331. bool TestTypeInference::TestFunctionParameter() {
  332. VT("<?php function t($a) { print $a;} $a = 1; t($a); ",
  333. "Variant gv_a;\n"
  334. "\n"
  335. "void f_t(CVarRef v_a);\n"
  336. "void f_t(CVarRef v_a) {\n"
  337. " print(toString(v_a));\n"
  338. "}\n"
  339. "gv_a = 1;\n"
  340. "f_t(gv_a);\n");
  341. VT("<?php function t($a) { print $a;} t(1); t('test'); ",
  342. "void f_t(CVarRef v_a);\n"
  343. "void f_t(CVarRef v_a) {\n"
  344. " print(toString(v_a));\n"
  345. "}\n"
  346. "f_t(1);\n"
  347. "f_t(\"test\");\n");
  348. VT("<?php $a = 1; t($a); function t($a) { print $a;}",
  349. "Variant gv_a;\n"
  350. "\n"
  351. "void f_t(CVarRef v_a);\n"
  352. "void f_t(CVarRef v_a) {\n"
  353. " print(toString(v_a));\n"
  354. "}\n"
  355. "gv_a = 1;\n"
  356. "f_t(gv_a);\n");
  357. VT("<?php $a = 1; t($a); function t($a) { r($a);} function r($a) {}",
  358. "Variant gv_a;\n"
  359. "\n"
  360. "void f_r(CVarRef v_a);\n"
  361. "void f_t(CVarRef v_a);\n"
  362. "void f_r(CVarRef v_a) {\n"
  363. "}\n"
  364. "void f_t(CVarRef v_a) {\n"
  365. " f_r(v_a);\n"
  366. "}\n"
  367. "gv_a = 1;\n"
  368. "f_t(gv_a);\n");
  369. return true;
  370. }
  371. bool TestTypeInference::TestMethodParameter() {
  372. VT("<?php class a { function test($x) { return $x; }} $z = new a(); $z->test(1); ",
  373. "Variant gv_z;\n"
  374. "\n"
  375. "class c_a : public ObjectData {\n"
  376. " void c_a::init();\n"
  377. " public: int64 t_test(int64 v_x);\n"
  378. "};\n"
  379. "c_a::c_a() {\n"
  380. "}\n"
  381. "void c_a::init() {\n"
  382. "}\n"
  383. "int64 c_a::t_test(int64 v_x) {\n"
  384. " return v_x;\n"
  385. "}\n"
  386. "gv_z = sp_a(sp_a(NEW(c_a)())->create());\n"
  387. "sp_a(gv_z)->t_test(1);\n"
  388. );
  389. VT("<?php class a { function test($x) { return $x; }} $z = new a(); $z->test(1); $y='test'; $z->$y(\'m\');",
  390. "Variant gv_z;\n"
  391. "Variant gv_y;\n"
  392. "\n"
  393. "class c_a : public ObjectData {\n"
  394. " void c_a::init();\n"
  395. " public: Variant t_test(CVarRef v_x);\n"
  396. "};\n"
  397. "c_a::c_a() {\n"
  398. "}\n"
  399. "void c_a::init() {\n"
  400. "}\n"
  401. "Variant c_a::t_test(CVarRef v_x) {\n"
  402. " return v_x;\n"
  403. "}\n"
  404. "gv_z = sp_a(sp_a(NEW(c_a)())->create());\n"
  405. "sp_a(gv_z)->t_test(1);\n"
  406. "gv_y = \"test\";\n"
  407. "toObject(gv_z)->o_invoke((toString(gv_y)), Array(NEW(ArrayElement)(ref(\"m\")), NULL), -1LL);\n"
  408. );
  409. return true;
  410. }