laser 0.7.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (319) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +661 -0
  5. data/README.md +158 -0
  6. data/Rakefile +104 -0
  7. data/VERSION +1 -0
  8. data/bin/laser +7 -0
  9. data/design_docs/goals.md +57 -0
  10. data/design_docs/object_regex.md +426 -0
  11. data/design_docs/type_annotations.md +80 -0
  12. data/ext/laser/BasicBlock.cpp +572 -0
  13. data/ext/laser/BasicBlock.h +118 -0
  14. data/ext/laser/extconf.rb +3 -0
  15. data/features/laser.feature +25 -0
  16. data/features/step_definitions/laser_steps.rb +39 -0
  17. data/features/support/env.rb +14 -0
  18. data/features/support/testdata/1_input +1 -0
  19. data/features/support/testdata/1_output +1 -0
  20. data/features/support/testdata/2_input +4 -0
  21. data/features/support/testdata/2_output +4 -0
  22. data/features/support/testdata/3_input +8 -0
  23. data/features/support/testdata/3_output +11 -0
  24. data/features/support/testdata/4_input +5 -0
  25. data/features/support/testdata/4_output +5 -0
  26. data/features/support/testdata/5_input +13 -0
  27. data/laser.gemspec +382 -0
  28. data/lib/laser.rb +98 -0
  29. data/lib/laser/analysis/annotations.rb +95 -0
  30. data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
  31. data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
  32. data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
  33. data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
  34. data/lib/laser/analysis/argument_expansion.rb +132 -0
  35. data/lib/laser/analysis/arity.rb +34 -0
  36. data/lib/laser/analysis/bindings.rb +144 -0
  37. data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
  38. data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
  39. data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
  40. data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
  41. data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
  42. data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
  43. data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
  44. data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
  45. data/lib/laser/analysis/comments.rb +35 -0
  46. data/lib/laser/analysis/control_flow.rb +28 -0
  47. data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
  48. data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
  49. data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
  50. data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
  51. data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
  52. data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
  53. data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
  54. data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
  55. data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
  56. data/lib/laser/analysis/control_flow/simulation.rb +385 -0
  57. data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
  58. data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
  59. data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
  60. data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
  61. data/lib/laser/analysis/errors.rb +131 -0
  62. data/lib/laser/analysis/laser_utils.rb +18 -0
  63. data/lib/laser/analysis/lexical_analysis.rb +172 -0
  64. data/lib/laser/analysis/method_call.rb +68 -0
  65. data/lib/laser/analysis/protocol_registry.rb +30 -0
  66. data/lib/laser/analysis/scope.rb +118 -0
  67. data/lib/laser/analysis/sexp.rb +159 -0
  68. data/lib/laser/analysis/sexp_analysis.rb +40 -0
  69. data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
  70. data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
  71. data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
  72. data/lib/laser/analysis/signature.rb +76 -0
  73. data/lib/laser/analysis/special_methods/send.rb +67 -0
  74. data/lib/laser/analysis/unused_methods.rb +21 -0
  75. data/lib/laser/analysis/visitor.rb +141 -0
  76. data/lib/laser/annotation_parser/annotations.treetop +126 -0
  77. data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
  78. data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
  79. data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
  80. data/lib/laser/annotation_parser/overload.treetop +24 -0
  81. data/lib/laser/annotation_parser/overload_parser.rb +167 -0
  82. data/lib/laser/annotation_parser/parsers.rb +6 -0
  83. data/lib/laser/annotation_parser/structural.treetop +37 -0
  84. data/lib/laser/annotation_parser/structural_parser.rb +406 -0
  85. data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
  86. data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
  87. data/lib/laser/rake/task.rb +46 -0
  88. data/lib/laser/runner.rb +189 -0
  89. data/lib/laser/scanner.rb +169 -0
  90. data/lib/laser/standard_library/_thread.rb +110 -0
  91. data/lib/laser/standard_library/abbrev.rb +103 -0
  92. data/lib/laser/standard_library/array.rb +418 -0
  93. data/lib/laser/standard_library/base64.rb +91 -0
  94. data/lib/laser/standard_library/basic_object.rb +55 -0
  95. data/lib/laser/standard_library/benchmark.rb +556 -0
  96. data/lib/laser/standard_library/bignum.rb +185 -0
  97. data/lib/laser/standard_library/cgi.rb +275 -0
  98. data/lib/laser/standard_library/cgi/cookie.rb +147 -0
  99. data/lib/laser/standard_library/cgi/core.rb +791 -0
  100. data/lib/laser/standard_library/cgi/html.rb +1021 -0
  101. data/lib/laser/standard_library/cgi/session.rb +537 -0
  102. data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
  103. data/lib/laser/standard_library/cgi/util.rb +188 -0
  104. data/lib/laser/standard_library/class_definitions.rb +333 -0
  105. data/lib/laser/standard_library/comparable.rb +125 -0
  106. data/lib/laser/standard_library/complex.rb +162 -0
  107. data/lib/laser/standard_library/enumerable.rb +178 -0
  108. data/lib/laser/standard_library/exceptions.rb +135 -0
  109. data/lib/laser/standard_library/fixnum.rb +188 -0
  110. data/lib/laser/standard_library/float.rb +180 -0
  111. data/lib/laser/standard_library/hash.rb +237 -0
  112. data/lib/laser/standard_library/integer.rb +123 -0
  113. data/lib/laser/standard_library/laser_magic.rb +7 -0
  114. data/lib/laser/standard_library/nil_false_true.rb +113 -0
  115. data/lib/laser/standard_library/numbers.rb +192 -0
  116. data/lib/laser/standard_library/proc.rb +31 -0
  117. data/lib/laser/standard_library/set.rb +1348 -0
  118. data/lib/laser/standard_library/string.rb +666 -0
  119. data/lib/laser/standard_library/stringio.rb +2 -0
  120. data/lib/laser/standard_library/symbol.rb +125 -0
  121. data/lib/laser/standard_library/tsort.rb +242 -0
  122. data/lib/laser/support/acts_as_struct.rb +66 -0
  123. data/lib/laser/support/frequency.rb +55 -0
  124. data/lib/laser/support/inheritable_attributes.rb +145 -0
  125. data/lib/laser/support/module_extensions.rb +94 -0
  126. data/lib/laser/support/placeholder_object.rb +13 -0
  127. data/lib/laser/third_party/rgl/adjacency.rb +221 -0
  128. data/lib/laser/third_party/rgl/base.rb +228 -0
  129. data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
  130. data/lib/laser/third_party/rgl/condensation.rb +47 -0
  131. data/lib/laser/third_party/rgl/connected_components.rb +138 -0
  132. data/lib/laser/third_party/rgl/control_flow.rb +170 -0
  133. data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
  134. data/lib/laser/third_party/rgl/dominators.rb +124 -0
  135. data/lib/laser/third_party/rgl/dot.rb +93 -0
  136. data/lib/laser/third_party/rgl/graphxml.rb +51 -0
  137. data/lib/laser/third_party/rgl/implicit.rb +174 -0
  138. data/lib/laser/third_party/rgl/mutable.rb +117 -0
  139. data/lib/laser/third_party/rgl/rdot.rb +445 -0
  140. data/lib/laser/third_party/rgl/topsort.rb +72 -0
  141. data/lib/laser/third_party/rgl/transitivity.rb +180 -0
  142. data/lib/laser/third_party/rgl/traversal.rb +348 -0
  143. data/lib/laser/types/types.rb +433 -0
  144. data/lib/laser/version.rb +14 -0
  145. data/lib/laser/warning.rb +149 -0
  146. data/lib/laser/warning_sets/default.yml +13 -0
  147. data/lib/laser/warnings/assignment_in_condition.rb +20 -0
  148. data/lib/laser/warnings/comment_spacing.rb +31 -0
  149. data/lib/laser/warnings/extra_blank_lines.rb +30 -0
  150. data/lib/laser/warnings/extra_whitespace.rb +16 -0
  151. data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
  152. data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
  153. data/lib/laser/warnings/line_length.rb +115 -0
  154. data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
  155. data/lib/laser/warnings/operator_spacing.rb +68 -0
  156. data/lib/laser/warnings/parens_on_declaration.rb +30 -0
  157. data/lib/laser/warnings/rescue_exception.rb +42 -0
  158. data/lib/laser/warnings/semicolon.rb +25 -0
  159. data/lib/laser/warnings/sexp_errors.rb +24 -0
  160. data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
  161. data/lib/laser/warnings/useless_double_quotes.rb +38 -0
  162. data/spec/analysis_specs/annotations_spec.rb +47 -0
  163. data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
  164. data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
  165. data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
  166. data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
  167. data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
  168. data/spec/analysis_specs/bindings_spec.rb +36 -0
  169. data/spec/analysis_specs/comment_spec.rb +93 -0
  170. data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
  171. data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
  172. data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
  173. data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
  174. data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
  175. data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
  176. data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
  177. data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
  178. data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
  179. data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
  180. data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
  181. data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
  182. data/spec/analysis_specs/error_spec.rb +30 -0
  183. data/spec/analysis_specs/laser_class_spec.rb +322 -0
  184. data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
  185. data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
  186. data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
  187. data/spec/analysis_specs/scope_spec.rb +126 -0
  188. data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
  189. data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
  190. data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
  191. data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
  192. data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
  193. data/spec/analysis_specs/sexp_spec.rb +167 -0
  194. data/spec/analysis_specs/spec_helper.rb +27 -0
  195. data/spec/analysis_specs/unused_methods_spec.rb +65 -0
  196. data/spec/analysis_specs/visitor_spec.rb +64 -0
  197. data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
  198. data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
  199. data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
  200. data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
  201. data/spec/annotation_parser_specs/spec_helper.rb +1 -0
  202. data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
  203. data/spec/laser_spec.rb +14 -0
  204. data/spec/rake_specs/spec_helper.rb +1 -0
  205. data/spec/rake_specs/task_spec.rb +67 -0
  206. data/spec/runner_spec.rb +207 -0
  207. data/spec/scanner_spec.rb +75 -0
  208. data/spec/spec_helper.rb +121 -0
  209. data/spec/standard_library/exceptions_spec.rb +19 -0
  210. data/spec/standard_library/globals_spec.rb +14 -0
  211. data/spec/standard_library/set_spec.rb +31 -0
  212. data/spec/standard_library/spec_helper.rb +1 -0
  213. data/spec/standard_library/standard_library_spec.rb +302 -0
  214. data/spec/support_specs/acts_as_struct_spec.rb +94 -0
  215. data/spec/support_specs/frequency_spec.rb +23 -0
  216. data/spec/support_specs/module_extensions_spec.rb +117 -0
  217. data/spec/support_specs/spec_helper.rb +1 -0
  218. data/spec/type_specs/spec_helper.rb +1 -0
  219. data/spec/type_specs/types_spec.rb +133 -0
  220. data/spec/warning_spec.rb +95 -0
  221. data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
  222. data/spec/warning_specs/comment_spacing_spec.rb +65 -0
  223. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  224. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  225. data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
  226. data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
  227. data/spec/warning_specs/line_length_spec.rb +173 -0
  228. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  229. data/spec/warning_specs/operator_spacing_spec.rb +104 -0
  230. data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
  231. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  232. data/spec/warning_specs/semicolon_spec.rb +58 -0
  233. data/spec/warning_specs/spec_helper.rb +1 -0
  234. data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
  235. data/status_reports/2010/12/2010-12-14.md +163 -0
  236. data/status_reports/2010/12/2010-12-23.md +298 -0
  237. data/status_reports/2010/12/2010-12-24.md +6 -0
  238. data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
  239. data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
  240. data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
  241. data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
  242. data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
  243. data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
  244. data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
  245. data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
  246. data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
  247. data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
  248. data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
  249. data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
  250. data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
  251. data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
  252. data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
  253. data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
  254. data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
  255. data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
  256. data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
  257. data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
  258. data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
  259. data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
  260. data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
  261. data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
  262. data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
  263. data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
  264. data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
  265. data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
  266. data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
  267. data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
  268. data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
  269. data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
  270. data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
  271. data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
  272. data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
  273. data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
  274. data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
  275. data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
  276. data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
  277. data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
  278. data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
  279. data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
  280. data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
  281. data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
  282. data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
  283. data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
  284. data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
  285. data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
  286. data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
  287. data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
  288. data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
  289. data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
  290. data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
  291. data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
  292. data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
  293. data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
  294. data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
  295. data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
  296. data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
  297. data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
  298. data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
  299. data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
  300. data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
  301. data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
  302. data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
  303. data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
  304. data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
  305. data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
  306. data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
  307. data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
  308. data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
  309. data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
  310. data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
  311. data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
  312. data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
  313. data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
  314. data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
  315. data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
  316. data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
  317. data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
  318. data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
  319. metadata +470 -0
@@ -0,0 +1,190 @@
1
+ require 'set'
2
+ module Laser
3
+ module Analysis
4
+ module ControlFlow
5
+ class Instruction < BasicObject
6
+ attr_reader :node, :block, :body, :ignore_privacy
7
+ attr_accessor :raise_frequency, :raise_type
8
+ def initialize(body, opts={})
9
+ @body = body
10
+ @node = opts[:node]
11
+ @block = opts[:block]
12
+ @raise_frequency = :unknown
13
+ @raise_type = Types::EMPTY
14
+ @ignore_privacy = opts[:ignore_privacy]
15
+ @true_successor = @false_successor = nil
16
+ end
17
+
18
+ def type
19
+ @body[0]
20
+ end
21
+
22
+ def class
23
+ Instruction
24
+ end
25
+
26
+ def ==(other)
27
+ @body == other.body
28
+ end
29
+
30
+ def deep_dup(temp_lookup, opts={})
31
+ new_body = @body[1..-1].map do |arg|
32
+ case arg
33
+ when Bindings::ConstantBinding then arg
34
+ when Bindings::Base then temp_lookup[arg]
35
+ when ::Hash
36
+ if arg[:block]
37
+ then arg.merge(block: temp_lookup[arg[:block]])
38
+ else arg
39
+ end
40
+ else arg.dup rescue arg
41
+ end
42
+ end
43
+
44
+ new_body.unshift(self[0]) # self[0] always symbol
45
+ new_opts = {node: @node, block: temp_lookup[@block], ignore_privacy: @ignore_privacy}.merge(opts)
46
+ self.class.new(new_body, new_opts)
47
+ end
48
+
49
+ def method_missing(meth, *args, &blk)
50
+ @body.send(meth, *args, &blk)
51
+ end
52
+
53
+ def method_call?
54
+ [:call, :call_vararg, :super, :super_vararg].include?(type)
55
+ end
56
+
57
+ def require_method_call
58
+ unless method_call?
59
+ raise TypeError.new("#possible_methods is not defined on #{type} instructions.")
60
+ end
61
+ end
62
+
63
+ def require_branch(method_needed='the requested operation')
64
+ unless type == :branch
65
+ raise TypeError.new("#{method_needed} is not defined on #{type} instructions.")
66
+ end
67
+ end
68
+
69
+ def true_successor
70
+ require_branch('#true_successor')
71
+ calculate_branch_successors
72
+ return @true_successor
73
+ end
74
+
75
+ def false_successor
76
+ require_branch('#false_successor')
77
+ calculate_branch_successors
78
+ return @false_successor
79
+ end
80
+
81
+ def calculate_branch_successors
82
+ return if @true_successor
83
+ successors = block.successors.to_a
84
+ if successors[0].name == self[2]
85
+ then @true_successor, @false_successor = successors[0..1]
86
+ else @false_successor, @true_successor = successors[0..1]
87
+ end
88
+ end
89
+
90
+ def possible_public_methods
91
+ require_method_call
92
+ if type == :call || type == :call_vararg
93
+ if Bindings::ConstantBinding === self[2]
94
+ [self[2].value.singleton_class.public_instance_method(self[3])].compact
95
+ elsif LaserObject === self[2].value
96
+ [self[2].value.klass.public_instance_method(self[3])].compact
97
+ else
98
+ self[2].expr_type.public_matching_methods(self[3])
99
+ end
100
+ else
101
+ #TODO(adgar): SUPER
102
+ end
103
+ end
104
+
105
+ def possible_methods(opts)
106
+ require_method_call
107
+ if type == :call || type == :call_vararg
108
+ if Bindings::ConstantBinding === self[2]
109
+ [self[2].value.singleton_class.instance_method(self[3])].compact
110
+ elsif LaserObject === self[2].value
111
+ [self[2].value.klass.instance_method(self[3])].compact
112
+ else
113
+ self[2].expr_type.matching_methods(self[3])
114
+ end
115
+ else
116
+ [opts[:method].owner.parent.instance_method(opts[:method].name)]
117
+ end
118
+ end
119
+
120
+ # Gets all bindings that are explicitly set in this instruction (no aliasing
121
+ # concerns)
122
+ def explicit_targets
123
+ case self[0]
124
+ when :assign, :call, :call_vararg, :super, :super_vararg, :lambda, :phi
125
+ self[1] ? ::Set[self[1]] : ::Set[]
126
+ else
127
+ ::Set[]
128
+ end
129
+ end
130
+
131
+ def block_operand
132
+ ::Hash === last ? last[:block] : nil
133
+ end
134
+
135
+ def replace_block_operand(new_block)
136
+ last[:block] = new_block
137
+ end
138
+
139
+ # Gets all bindings that are operands in this instruction
140
+ def operands
141
+ self[operand_range].select { |x| Bindings::Base === x && x != Bootstrap::VISIBILITY_STACK }
142
+ end
143
+
144
+ # Replaces the operands with a new list. Used by SSA renaming.
145
+ def replace_operands(new_operands)
146
+ # splice in new operands: replace bindings with bindings.
147
+ index = operand_range.begin
148
+ while new_operands.any? && index < @body.size
149
+ if Bindings::Base === self[index] && self[index] != Bootstrap::VISIBILITY_STACK
150
+ self[index] = new_operands.shift
151
+ end
152
+ index += 1
153
+ end
154
+ end
155
+
156
+ # Replaces a target of the instruction. Used by SSA renaming.
157
+ # Currently, all instructions only have at most 1 target.
158
+ def replace_target(original_target, new_target)
159
+ if self[1] == original_target
160
+ self[1] = new_target
161
+ else
162
+ raise ArgumentError.new("#{original_target.inspect} is not a "+
163
+ "target of #{self.inspect}")
164
+ end
165
+ end
166
+
167
+ private
168
+
169
+ def operand_range
170
+ case self[0]
171
+ when :assign, :call_vararg, :super, :super_vararg, :lambda, :phi
172
+ 2..-1
173
+ when :declare
174
+ case self[1]
175
+ when :alias then 2..-1
176
+ when :expect_tuple_size then 4..-1
177
+ end
178
+ when :call
179
+ # check for hardcoded call on a constant class. Used by literals.
180
+ if Bindings::ConstantBinding === self[2]
181
+ then 3..-1
182
+ else 2..-1
183
+ end
184
+ else 1..-1
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,742 @@
1
+ module Laser
2
+ module Analysis
3
+ module ControlFlow
4
+ INAPPLICABLE = PlaceholderObject.new('INAPPLICABLE')
5
+
6
+ # Sparse Conditional Constant Propagation: Wegman and Zadeck
7
+ # Love those IBMers
8
+ # Using Morgan's implementation though.
9
+ module ConstantPropagation
10
+ attr_reader :constants
11
+
12
+ # Only public method: mutably turns the CFG into a constant-propagated
13
+ # one. Each binding will have a value assigned to it afterward: either
14
+ # the constant, as a Ruby object (or a proxy to one), UNDEFINED, or VARYING.
15
+ def perform_constant_propagation(opts={})
16
+ opts = {fixed_methods: {}, initial_block: self.enter}.merge(opts)
17
+
18
+ initialize_constant_propagation(opts)
19
+ visited = Set.new
20
+ worklist = Set.new
21
+ blocklist = Set[opts[:initial_block]]
22
+ while worklist.any? || blocklist.any?
23
+ while worklist.any?
24
+ constant_propagation_for_instruction(
25
+ worklist.pop, blocklist, worklist, opts)
26
+ end
27
+ while blocklist.any?
28
+ constant_propagation_for_block(
29
+ blocklist.pop, visited, blocklist, worklist, opts)
30
+ end
31
+ end
32
+ teardown_constant_propagation
33
+ @constants = find_remaining_constants
34
+ end
35
+
36
+ private
37
+
38
+ def find_remaining_constants
39
+ result = {}
40
+ all_variables.select do |variable|
41
+ variable.value != VARYING && variable.value != UNDEFINED
42
+ end.each do |constant|
43
+ result[constant] = constant.value
44
+ end
45
+ result
46
+ end
47
+
48
+ # Initializes the variables, formals, and edges for constant propagation.
49
+ # Morgan, p. 201
50
+ def initialize_constant_propagation(opts)
51
+ @constants.clear
52
+ # value cells for :call nodes that discard their argument.
53
+ @cp_private_cells = Hash.new do |h, k|
54
+ h[k] = Bindings::TemporaryBinding.new(k.hash.to_s, UNDEFINED)
55
+ h[k].inferred_type = nil
56
+ h[k]
57
+ end
58
+ @cp_self_cells = Hash.new do |h, k|
59
+ h[k] = Bindings::TemporaryBinding.new(k.hash.to_s, VARYING)
60
+ h[k].inferred_type = real_self_type
61
+ h[k]
62
+ end
63
+ clear_analyses unless opts[:no_wipe]
64
+ @_cp_fixed_methods = opts[:fixed_methods]
65
+ end
66
+
67
+ def teardown_constant_propagation
68
+ @cp_private_cells.clear
69
+ @cp_self_cells.clear
70
+ end
71
+
72
+ def cp_cell_for(instruction)
73
+ @cp_private_cells[instruction]
74
+ end
75
+
76
+ def cp_self_cell(instruction)
77
+ @cp_self_cells[instruction]
78
+ end
79
+
80
+ # Simulates a block. As we know, phi nodes execute simultaneously
81
+ # and immediately upon block entry, so first we check phi nodes to
82
+ # see if they form a constant. This happens unconditionally, as
83
+ # phi nodes must be checked repeatedly.
84
+ #
85
+ # Then, if the block hasn't been visited before, simulate the normal
86
+ # instructions, and mark it so it is not visited again.
87
+ #
88
+ # Morgan, p.200
89
+ def constant_propagation_for_block(block, visited, blocklist, worklist, opts)
90
+ block.phi_nodes.each do |phi_node|
91
+ constant_propagation_for_instruction(
92
+ phi_node, blocklist, worklist, opts)
93
+ end
94
+ if visited.add?(block)
95
+ block.natural_instructions.each do |instruction|
96
+ constant_propagation_for_instruction(
97
+ instruction, blocklist, worklist, opts)
98
+ end
99
+ if block.fall_through_block?
100
+ block.successors.each do |succ|
101
+ constant_propagation_consider_edge block, succ, blocklist
102
+ end
103
+ end
104
+ end
105
+ end
106
+ private :constant_propagation_for_block
107
+
108
+ def constant_propagation_for_instruction(instruction, blocklist, worklist, opts)
109
+ return if instruction.type != :phi && instruction.block.executed_predecessors.empty?
110
+ Laser.debug_p(instruction)
111
+ block = instruction.block
112
+ case instruction.type
113
+ when :assign, :phi
114
+ if constant_propagation_evaluate(instruction)
115
+ add_target_uses_to_worklist instruction, worklist
116
+ end
117
+ when :call, :call_vararg, :super, :super_vararg
118
+ changed, raised, raise_changed = constant_propagation_for_call(instruction, opts)
119
+ if changed
120
+ if instruction[1] && instruction[1].value != UNDEFINED
121
+ add_target_uses_to_worklist instruction, worklist
122
+ end
123
+ end
124
+ if raise_changed && instruction == block.instructions.last
125
+ raise_capture_insn = instruction.block.exception_successors.first.instructions.first
126
+ raise_capture_insn[1].bind!(VARYING)
127
+ raise_capture_insn[1].inferred_type = instruction.raise_type
128
+ add_target_uses_to_worklist raise_capture_insn, worklist
129
+ end
130
+ if raised != instruction.raise_frequency && instruction == block.instructions.last
131
+ instruction.raise_frequency = raised
132
+ successors = case raised
133
+ when :unknown then []
134
+ when Frequency::MAYBE then block.successors
135
+ when Frequency::NEVER then block.normal_successors
136
+ when Frequency::ALWAYS then block.abnormal_successors
137
+ end
138
+ successors.each do |succ|
139
+ constant_propagation_consider_edge block, succ, blocklist
140
+ end
141
+ end
142
+ when :branch
143
+ constant_propagation_for_branch(instruction, blocklist)
144
+ when :jump, :raise, :return
145
+ succ = block.real_successors.first
146
+ constant_propagation_consider_edge block, succ, blocklist
147
+ when :declare
148
+ case instruction[1]
149
+ when :expect_tuple_size
150
+ # check array/tuple size against expectation - issue warning if fail
151
+ validate_tuple_expectation(instruction)
152
+ end
153
+ # don't do shit
154
+ else
155
+ raise ArgumentError("Unknown instruction evaluation type: #{instruction.type}")
156
+ end
157
+ end
158
+
159
+ def add_target_uses_to_worklist(instruction, worklist)
160
+ uses = if instruction[0] == :call && instruction[2] == ClassRegistry['Laser#Magic'].binding &&
161
+ instruction[3] == :set_global
162
+ Scope::GlobalScope.lookup(instruction[4].value).uses
163
+ elsif instruction[0] == :call && instruction[3] == :instance_variable_set &&
164
+ instruction[4] != UNDEFINED && instruction[4] != VARYING
165
+ receiver = instruction[2]
166
+ klass = LaserObject === receiver.value ? receiver.value.normal_class : receiver.expr_type.possible_classes.first
167
+ klass.instance_variable(instruction[4].value).uses
168
+ else
169
+ instruction.explicit_targets.map(&:uses).inject(:|) || []
170
+ end
171
+ uses.each { |use| worklist.add(use) if use }
172
+ end
173
+
174
+ # Examines the branch for newly executable edges, and adds them to
175
+ # the blocklist.
176
+ def constant_propagation_for_branch(instruction, blocklist)
177
+ block = instruction.block
178
+ executable_successors = constant_propagation_branch_successors(instruction)
179
+ executable_successors.each do |succ|
180
+ constant_propagation_consider_edge block, succ, blocklist
181
+ end
182
+ end
183
+
184
+ def constant_propagation_branch_successors(instruction)
185
+ condition = instruction[1]
186
+ case condition.value
187
+ when VARYING
188
+ if Types.overlap?(condition.expr_type, Types::FALSY)
189
+ instruction.block.real_successors
190
+ else
191
+ [instruction.true_successor]
192
+ end
193
+ when UNDEFINED then []
194
+ when nil, false then [instruction.false_successor]
195
+ else [instruction.true_successor]
196
+ end
197
+ end
198
+
199
+ def constant_propagation_consider_edge(block, succ, blocklist)
200
+ if !is_executable?(block, succ) && !is_fake?(block, succ)
201
+ add_flag(block, succ, ControlFlowGraph::EDGE_EXECUTABLE)
202
+ blocklist << succ
203
+ end
204
+ end
205
+
206
+ def constant_propagation_for_call(instruction, cp_opts)
207
+ target = instruction[1] || cp_cell_for(instruction)
208
+ original = target.value
209
+ old_type = target.inferred_type
210
+ old_raise_type = instruction.raise_type
211
+
212
+ if instruction.type == :call
213
+ receiver, method_name, *args, opts = instruction[2..-1]
214
+ components = [receiver, *args]
215
+ fixed_arity = true
216
+ elsif instruction.type == :call_vararg
217
+ receiver, method_name, args, opts = instruction[2..-1]
218
+ components = [receiver, args]
219
+ elsif instruction.type == :super
220
+ *args, opts = instruction[2..-1]
221
+ fixed_arity = issuper = true
222
+ components = args.dup
223
+ receiver = cp_self_cell(instruction)
224
+ elsif instruction.type == :super_vararg
225
+ args, opts = instruction[2..3]
226
+ issuper = true
227
+ components = [args]
228
+ receiver = cp_self_cell(instruction)
229
+ end
230
+ components << opts[:block] if opts[:block]
231
+
232
+ if components.any? { |arg| arg.value == UNDEFINED }
233
+ # cannot evaluate unless all args and receiver are defined
234
+ return [false, :unknown]
235
+ end
236
+ # check purity
237
+ methods = instruction.possible_methods(cp_opts)
238
+ # Require precise resolution
239
+ method = methods.size == 1 ? methods.first : nil
240
+ if methods.empty?
241
+ new_value = UNDEFINED
242
+ new_type = Types::TOP
243
+ raised = Frequency::ALWAYS # NoMethodError
244
+ raise_type = Types::UnionType.new([Types::ClassObjectType.new('NoMethodError')])
245
+ elsif method && (@_cp_fixed_methods.has_key?(method))
246
+ result = @_cp_fixed_methods[method]
247
+ new_value = result
248
+ new_type = Utilities.type_for(result)
249
+ raised = Frequency::NEVER
250
+ raise_type = Types::EMPTY
251
+ elsif fixed_arity && !issuper &&
252
+ (special_result, special_type =
253
+ apply_special_case(instruction, receiver, method_name, *args);
254
+ special_result != INAPPLICABLE)
255
+ new_value = special_result
256
+ new_type = special_type
257
+ raised = Frequency::NEVER
258
+ raise_type = Types::EMPTY
259
+ elsif components.any? { |arg| arg.value == VARYING }
260
+ new_value = VARYING
261
+ new_type, raised, raise_type = infer_type_and_raising(instruction, receiver, method_name, args, cp_opts)
262
+ # All components constant, and never evaluated before.
263
+ elsif original == UNDEFINED
264
+ if !issuper && method && (method.pure || allow_impure_method?(method))
265
+ arg_array = fixed_arity ? args.map(&:value) : args.value
266
+ block = opts[:block] && opts[:block].value
267
+ new_value, new_type, raised, raise_type = adapt_simulation_of_method(
268
+ instruction, receiver.value, method, arg_array, block, cp_opts)
269
+ else
270
+ new_value = VARYING
271
+ new_type, raised, raise_type = infer_type_and_raising(instruction, receiver, method_name, args, cp_opts)
272
+ end
273
+ else
274
+ # all components constant, nothing changed, shouldn't happen, but okay
275
+ new_value = original
276
+ new_type = old_type
277
+ raised = instruction.raise_frequency
278
+ raise_type = instruction.raise_type
279
+ end
280
+ # At this point, we should prune raise edges!
281
+ if original != new_value
282
+ target.bind! new_value
283
+ changed = true
284
+ end
285
+ if old_type != new_type
286
+ Laser.debug_puts "-> Return type: #{new_type.inspect}"
287
+ target.inferred_type = new_type
288
+ changed = true
289
+ end
290
+ Laser.debug_puts "-> Raise freq: #{raised.inspect}"
291
+ if raise_type != old_raise_type
292
+ Laser.debug_puts "-> Raise Type: #{raise_type.inspect}"
293
+ instruction.raise_type = raise_type
294
+ raise_changed = true
295
+ end
296
+ [changed, raised, raise_changed]
297
+ end
298
+
299
+ # Runs method call simulation from the Simulation modules, and adapts
300
+ # the output for consumption by constant propagation.
301
+ def adapt_simulation_of_method(insn, receiver, method, args, block, opts)
302
+ opts = Simulation::DEFAULT_SIMULATION_OPTS.merge(opts)
303
+ opts.merge!(current_block: insn.block)
304
+ begin
305
+ new_value = simulate_call_dispatch(receiver, method, args, block, opts)
306
+ new_type = Utilities.type_for(new_value)
307
+ raised = Frequency::NEVER
308
+ raise_type = Types::EMPTY
309
+ rescue Simulation::ExitedAbnormally => err
310
+ new_value = UNDEFINED
311
+ new_type = Types::TOP
312
+ raised = Frequency::ALWAYS
313
+ raise_type = Types::UnionType.new([Types::ClassObjectType.new(err.error.class.name)])
314
+ end
315
+ [new_value, new_type, raised, raise_type]
316
+ end
317
+
318
+ def infer_type_and_raising(instruction, receiver, method_name, args, opts)
319
+ begin
320
+ type, raise_freq, raise_type = cpa_call_properties(
321
+ receiver, method_name, args, instruction, opts)
322
+ rescue TypeError => err
323
+ type = Types::TOP
324
+ raise_freq = Frequency::ALWAYS
325
+ raise_type = Types::UnionType.new([Types::ClassObjectType.new('TypeError')])
326
+ Laser.debug_puts("No method named #{method_name} with matching types was found")
327
+ instruction.node.add_error(NoMatchingTypeSignature.new(
328
+ "No method named #{method_name} with matching types was found", instruction.node))
329
+ end
330
+ [type, raise_freq, raise_type]
331
+ end
332
+
333
+ # Calculates all possible return types, raise types, and the raise
334
+ # frequency for a method call using CPA.
335
+ def cpa_call_properties(receiver, method, args, instruction, opts)
336
+ ignore_privacy, block = instruction.ignore_privacy, instruction.block_operand
337
+ dispatches = cpa_dispatches(receiver, instruction, method, opts)
338
+ cartesian = calculate_possible_templates(dispatches, args, block)
339
+ result = cpa_for_templates(dispatches, cartesian)
340
+ raise_result, raise_type = raisability_for_templates(dispatches, cartesian, ignore_privacy)
341
+ if result.empty?
342
+ raise TypeError.new("No methods named #{method} with matching types were found.")
343
+ end
344
+ [Types::UnionType.new(result), raise_result, raise_type]
345
+ end
346
+
347
+ # Calculates all possible (self_type, dispatches) pairs for a call.
348
+ def cpa_dispatches(receiver, instruction, method, opts)
349
+ if instruction.type == :call || instruction.type == :call_vararg
350
+ receiver.expr_type.member_types.map do |type|
351
+ [type, type.matching_methods(method)]
352
+ end
353
+ else
354
+ dispatches = instruction.possible_methods(opts)
355
+ receiver.expr_type.member_types.map do |type|
356
+ [type, dispatches]
357
+ end
358
+ end
359
+ end
360
+
361
+ # Calculates the set of methods potentially invoked in dynamic dispatch,
362
+ # and the set of all possible argument type combinations.
363
+ def calculate_possible_templates(possible_dispatches, args, block)
364
+ if Bindings::Base === args && Types::TupleType === args.expr_type
365
+ cartesian_parts = args.element_types
366
+ empty = cartesian_parts.empty?
367
+ elsif Bindings::Base === args && Types::UnionType === args.expr_type &&
368
+ Types::TupleType === args.expr_type.member_types.first
369
+ cartesian_parts = args.expr_type.member_types.first.element_types.map { |x| [x] }
370
+ empty = cartesian_parts.empty?
371
+ else
372
+ cartesian_parts = args.map(&:expr_type).map(&:member_types).map(&:to_a)
373
+ empty = args.empty?
374
+ end
375
+ if empty && !block
376
+ cartesian = [ [Types::NILCLASS] ]
377
+ else
378
+ if block
379
+ then cartesian_parts << block.expr_type.member_types.to_a
380
+ else cartesian_parts << [Types::NILCLASS]
381
+ end
382
+ cartesian = cartesian_parts[0].product(*cartesian_parts[1..-1])
383
+ end
384
+ cartesian
385
+ end
386
+
387
+ # Calculates the CPA-based return type of a dynamic call.
388
+ def cpa_for_templates(possible_dispatches, cartesian)
389
+ result = Set.new
390
+ possible_dispatches.each do |self_type, methods|
391
+ result |= methods.map do |method|
392
+ cartesian.map do |*type_list, block_type|
393
+ begin
394
+ method.return_type_for_types(self_type, type_list, block_type)
395
+ rescue TypeError => err
396
+ Laser.debug_puts("Invalid argument types found.")
397
+ nil
398
+ end
399
+ end.compact
400
+ end.flatten
401
+ end
402
+ result
403
+ end
404
+
405
+ # TODO(adgar): Optimize this. Use lattice-style expression of raisability
406
+ # until types need to be added too.
407
+ def raisability_for_templates(possible_dispatches, cartesian, ignore_privacy)
408
+ raise_type = Types::EMPTY
409
+ seen_public = seen_private = seen_raise = seen_succeed = seen_any = seen_missing = false
410
+ seen_valid_arity = seen_invalid_arity = false
411
+ arity = cartesian.first.size - 1 # -1 for block arg
412
+ possible_dispatches.each do |self_type, methods|
413
+ seen_any = true if methods.size > 0 && !seen_any
414
+ seen_missing = true if methods.empty? && !seen_missing
415
+ methods.each do |method|
416
+ if !seen_valid_arity && method.valid_arity?(arity)
417
+ seen_valid_arity = true
418
+ end
419
+ if !seen_invalid_arity && !method.valid_arity?(arity)
420
+ seen_invalid_arity = true
421
+ end
422
+ if !ignore_privacy
423
+ self_type.possible_classes.each do |self_class|
424
+ if self_class.visibility_for(method.name) == :public
425
+ seen_public = true
426
+ method.been_used! if method.valid_arity?(arity)
427
+ end
428
+ if !seen_private
429
+ seen_private = (self_class.visibility_for(method.name) != :public)
430
+ end
431
+ end
432
+ else
433
+ method.been_used! if method.valid_arity?(arity)
434
+ end
435
+ cartesian.each do |*type_list, block_type|
436
+ raise_frequency = method.raise_frequency_for_types(self_type, type_list, block_type)
437
+ if raise_frequency > Frequency::NEVER
438
+ seen_raise = true
439
+ raise_type = raise_type | method.raise_type_for_types(self_type, type_list, block_type)
440
+ end
441
+ seen_succeed = raise_frequency < Frequency::ALWAYS if !seen_succeed
442
+ end
443
+ end
444
+ end
445
+
446
+ if seen_any
447
+ fails_lookup = seen_missing ? Frequency::MAYBE : Frequency::NEVER
448
+ fails_privacy = if ignore_privacy
449
+ then Frequency::NEVER
450
+ else Frequency.for_samples(seen_private, seen_public)
451
+ end
452
+ failed_arity = Frequency.for_samples(seen_invalid_arity, seen_valid_arity)
453
+ if fails_privacy == Frequency::ALWAYS
454
+ raise_type = ClassRegistry['NoMethodError'].as_type
455
+ elsif failed_arity == Frequency::ALWAYS
456
+ raise_type = ClassRegistry['ArgumentError'].as_type
457
+ else
458
+ if fails_lookup > Frequency::NEVER || fails_privacy > Frequency::NEVER
459
+ raise_type |= ClassRegistry['NoMethodError'].as_type
460
+ end
461
+ if failed_arity > Frequency::NEVER
462
+ raise_type |= ClassRegistry['ArgumentError'].as_type
463
+ end
464
+ end
465
+ raised = Frequency.for_samples(seen_raise, seen_succeed)
466
+ raise_freq = [fails_privacy, raised, fails_lookup, failed_arity].max
467
+ else
468
+ raise_freq = Frequency::ALWAYS # no method!
469
+ raise_type = ClassRegistry['NoMethodError'].as_type
470
+ end
471
+ [raise_freq, raise_type]
472
+ end
473
+
474
+ # Evaluates the instruction, and if the constant value is lowered,
475
+ # then return true. Otherwise, return false.
476
+ def constant_propagation_evaluate(instruction)
477
+ target = instruction[1] || cp_cell_for(instruction)
478
+ original = target.value
479
+ old_type = target.inferred_type
480
+ changed = false
481
+ case instruction.type
482
+ when :assign
483
+ rhs = instruction[2]
484
+ if Bindings::Base === rhs
485
+ # temporary <- temporary
486
+ new_value = rhs.value
487
+ new_type = rhs.inferred_type
488
+ else
489
+ # temporary <- constant
490
+ new_value = rhs
491
+ new_type = Utilities.type_for(rhs)
492
+ end
493
+ when :phi
494
+ components = instruction[2..-1]
495
+ if components.any? { |var| var.value == VARYING }
496
+ new_value = VARYING
497
+ new_type = Types::UnionType.new(components.select { |c| c.value != UNDEFINED }.map(&:inferred_type).compact.uniq)
498
+ else
499
+ possible_values = components.map(&:value).uniq - [UNDEFINED]
500
+ Laser.debug_puts("CP_Phi(#{instruction.inspect}, #{possible_values.inspect})")
501
+ if possible_values == []
502
+ new_value = UNDEFINED
503
+ new_type = nil
504
+ elsif possible_values.size == 1
505
+ new_value = possible_values.first
506
+ new_type = Utilities.type_for(new_value)
507
+ else
508
+ new_value = VARYING
509
+ new_type = Types::UnionType.new(components.select { |c| c.value != UNDEFINED }.map(&:inferred_type).compact.uniq)
510
+ end
511
+ end
512
+ when :super, :super_vararg
513
+ new_value = VARYING
514
+ new_type = Types::TOP
515
+ else
516
+ raise ArgumentError("Invalid evaluate instruction evaluation type: #{instruction.type}")
517
+ end
518
+ if original != new_value
519
+ target.bind! new_value
520
+ changed = true
521
+ end
522
+ if old_type != new_type
523
+ target.inferred_type = new_type
524
+ changed = true
525
+ end
526
+ changed
527
+ end
528
+
529
+ def is_numeric?(temp)
530
+ temp.value != UNDEFINED && Types.subtype?(temp.inferred_type,
531
+ Types::ClassType.new('Numeric', :covariant))
532
+ end
533
+
534
+ def uses_method?(temp, method)
535
+ temp.value != UNDEFINED && temp.expr_type.matching_methods(method.name) == [method]
536
+ end
537
+
538
+ # TODO(adgar): Add typechecking. Forealz.
539
+ def apply_special_case(instruction, receiver, method_name, *args)
540
+ if method_name == :*
541
+ # 0 * n == 0
542
+ # n * 0 == 0
543
+ if (receiver.value == 0 && is_numeric?(args.first)) ||
544
+ (args.first.value == 0 && is_numeric?(receiver))
545
+ return [0, Types::FIXNUM]
546
+ elsif (args.first.value == 0 &&
547
+ uses_method?(receiver, ClassRegistry['String'].instance_method(:*)))
548
+ return ['', Types::STRING]
549
+ elsif (args.first.value == 0 &&
550
+ receiver.expr_type.member_types.all? { |t|
551
+ Types::TupleType === t || t.matching_methods(:*) == [ClassRegistry['Array'].instance_method(:*)]
552
+ })
553
+ return [[], Types::ARRAY]
554
+ end
555
+ elsif method_name == :**
556
+ # n ** 0 == 1
557
+ if args.first.value == 0 && is_numeric?(receiver)
558
+ return [1, Types::FIXNUM]
559
+ # 1 ** n == 1
560
+ elsif receiver.value == 1 && is_numeric?(args.first)
561
+ return [1, Types::FIXNUM]
562
+ end
563
+ elsif method_name == :===
564
+ if LaserModule === receiver.value && args.first != UNDEFINED
565
+ instance_type = args.first.expr_type
566
+ module_type = Types::ClassType.new(receiver.value.path, :covariant)
567
+ result = Types.subtype?(instance_type, module_type)
568
+ if result
569
+ return [true, Types::TRUECLASS]
570
+ elsif !(Types.overlap?(instance_type, module_type))
571
+ return [false, Types::FALSECLASS]
572
+ end
573
+ end
574
+ elsif method_name == :instance_variable_get
575
+ if args.first.value != UNDEFINED && args.first.value != VARYING
576
+ klass = LaserObject === receiver.value ? receiver.value.normal_class : receiver.expr_type.possible_classes.first
577
+ ivar = klass.instance_variable(args.first.value)
578
+ ivar.uses.add(instruction)
579
+ return [VARYING, ivar.expr_type]
580
+ end
581
+ elsif method_name == :instance_variable_set
582
+ if args.first.value != UNDEFINED && args.first.value != VARYING
583
+ klass = LaserObject === receiver.value ? receiver.value.normal_class : receiver.expr_type.possible_classes.first
584
+ ivar = klass.instance_variable(args.first.value)
585
+ unless Types.subtype?(args[1].expr_type, ivar.expr_type)
586
+ ivar.inferred_type = Types::UnionType.new([args[1].expr_type, ivar.expr_type])
587
+ end
588
+ return [args[1].value, ivar.expr_type]
589
+ end
590
+ elsif receiver == ClassRegistry['Laser#Magic'].binding
591
+ magic_result, magic_type = cp_magic(instruction, method_name, *args)
592
+ if magic_result != INAPPLICABLE
593
+ return [magic_result, magic_type]
594
+ end
595
+ elsif (receiver.value == ClassRegistry['Proc'] && method_name == :new) ||
596
+ ((method_name == :block_given? || method_name == :iterable?) &&
597
+ (uses_method?(receiver, ClassRegistry['Kernel'].instance_method(:block_given?)))) # and check no block
598
+ return cp_magic(instruction, :current_block)
599
+ elsif receiver.value == ClassRegistry['Array'] && method_name == :[]
600
+ if args.all? { |arg| arg.value != UNDEFINED }
601
+ tuple_type = Types::TupleType.new(args.map(&:expr_type))
602
+ if args.all? { |arg| arg.value != VARYING }
603
+ return [args.map(&:value), tuple_type]
604
+ else
605
+ return [VARYING, tuple_type]
606
+ end
607
+ end
608
+ elsif receiver.value == ClassRegistry['Array'] && method_name == :new
609
+ if args.all? { |arg| arg.value != UNDEFINED }
610
+ if args.size == 0
611
+ return [[], Types::TupleType.new([])]
612
+ elsif args.size == 1 && Types::equal(Types::ARRAY, args.first.expr_type)
613
+ return [args.first.value, args.first.expr_type]
614
+ else
615
+ # TODO(adgar): add integer, val, and integer, block case
616
+ end
617
+ end
618
+ elsif receiver.expr_type.member_types.size == 1 &&
619
+ Types::TupleType === receiver.expr_type.member_types.first
620
+ tuple_type = receiver.expr_type.member_types.first
621
+ # switch on method object
622
+ case tuple_type.matching_methods(method_name)[0]
623
+ when ClassRegistry['Array'].instance_method(:size)
624
+ size = tuple_type.size
625
+ return [size, Utilities.type_for(size)]
626
+ end
627
+ elsif method_name == :+
628
+ if receiver.value != VARYING && receiver.value != UNDEFINED &&
629
+ Utilities.normal_class_for(receiver.value) == ClassRegistry['Array'] &&
630
+ args[0].value == VARYING && args[0].expr_type.member_types.all? { |t| Types::TupleType === t }
631
+ constant, tuple = receiver, args[0]
632
+ elsif args[0].value != VARYING && args[0].value != UNDEFINED &&
633
+ Utilities.normal_class_for(args[0].value) == ClassRegistry['Array'] &&
634
+ receiver.value == VARYING &&
635
+ receiver.expr_type.member_types.all? { |t| Types::TupleType === t }
636
+ constant, tuple = args[0], receiver
637
+ end
638
+ if constant
639
+ constant_types = constant.value.map { |v| Utilities.type_for(v) }
640
+ new_types = tuple.expr_type.member_types.map do |tuple_type|
641
+ Types::TupleType.new(constant_types + tuple_type.element_types)
642
+ end
643
+ return [VARYING, Types::UnionType.new(new_types)]
644
+ end
645
+ end
646
+ [INAPPLICABLE, Types::EMPTY]
647
+ end
648
+
649
+ def allow_impure_method?(method)
650
+ method == ClassRegistry['Module'].instance_method(:const_get)
651
+ end
652
+
653
+ def cp_magic(instruction, method_name, *args)
654
+ case method_name
655
+ when :current_self
656
+ return [VARYING, real_self_type]
657
+ when :current_argument
658
+ return [VARYING, real_formal_type(args[0].value)]
659
+ when :current_argument_range
660
+ if bound_argument_types?
661
+ tuple_args = ((args[0].value)...(args[0].value + args[1].value)).map do |num|
662
+ real_formal_type(num)
663
+ end
664
+ return [VARYING, Types::TupleType.new(tuple_args)]
665
+ else
666
+ return [VARYING, Types::ARRAY]
667
+ end
668
+ when :current_arity
669
+ if bound_argument_types?
670
+ return [bound_arity, Types::FIXNUM]
671
+ else
672
+ return [VARYING, Types::FIXNUM]
673
+ end
674
+ when :current_block
675
+ if real_block_type == Types::NILCLASS
676
+ return [nil, Types::NILCLASS]
677
+ else
678
+ return [VARYING, real_block_type]
679
+ end
680
+ when :current_exception
681
+ return [VARYING, Types::EMPTY]
682
+ when :get_just_raised_exception
683
+ # Actually assigned to by the call's raisability-inference.
684
+ # return current state.
685
+ result_holder = instruction[1]
686
+ return [result_holder.value, result_holder.expr_type]
687
+ when :get_global
688
+ global = Scope::GlobalScope.lookup(args[0].value)
689
+ global.uses.add(instruction)
690
+ return [VARYING, global.expr_type]
691
+ when :set_global
692
+ if args[1].value != UNDEFINED
693
+ global = Scope::GlobalScope.lookup(args[0].value)
694
+ unless Types.subtype?(args[1].expr_type, global.expr_type)
695
+ global.inferred_type = Types::UnionType.new([args[1].expr_type, global.expr_type])
696
+ end
697
+ return [VARYING, global.expr_type]
698
+ end
699
+ when :responds?
700
+ name = args[1].value
701
+ seen_yes = seen_no = false
702
+ args[0].expr_type.possible_classes.each do |klass|
703
+ if klass.instance_method(name)
704
+ then seen_yes = true; break if seen_no
705
+ else seen_no = true; break if seen_yes
706
+ end
707
+ end
708
+ if seen_yes && !seen_no
709
+ return [true, Types::TRUECLASS]
710
+ elsif !seen_yes && seen_no
711
+ return [false, Types::FALSECLASS]
712
+ elsif seen_yes && seen_no
713
+ return [VARYING, Types::BOOLEAN]
714
+ else # receiver's type is empty. YAGNI?
715
+ return [false, Types::FALSECLASS]
716
+ end
717
+ end
718
+ [INAPPLICABLE, nil]
719
+ end
720
+
721
+ def validate_tuple_expectation(instruction)
722
+ expect_type, val, array = instruction[2..-1]
723
+ return if array.value == UNDEFINED
724
+ node = instruction.node
725
+ array.expr_type.member_types.each do |type|
726
+ if Types::TupleType === type
727
+ if type.size < val && expect_type == :==
728
+ node.add_error(UnassignedLHSError.new('LHS never assigned - defaults to nil', node))
729
+ elsif type.size <= val && expect_type == :>
730
+ node.add_error(UnassignedLHSError.new('LHS splat is always empty ([]) - not useful', node))
731
+ elsif type.size > val && expect_type == :==
732
+ node.add_error(DiscardedRHSError.new('RHS value being discarded', node))
733
+ elsif type.size >= val && expect_type == :<
734
+ node.add_error(DiscardedRHSError.new('RHS splat expanded and then discarded', node))
735
+ end
736
+ end
737
+ end
738
+ end
739
+ end # ConstantPropagation
740
+ end # ControlFlow
741
+ end # Analysis
742
+ end #