laser 0.7.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 #