rdl 2.0.1 → 2.1.0

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 (252) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -0
  3. data/CHANGES.md +35 -0
  4. data/README.md +153 -116
  5. data/bin/rdl_query +1 -1
  6. data/extras/type_tests/typetests.rb +905 -0
  7. data/lib/rdl.rb +0 -1
  8. data/lib/rdl/boot.rb +108 -77
  9. data/lib/rdl/boot_rails.rb +2 -8
  10. data/lib/rdl/config.rb +44 -17
  11. data/lib/rdl/contracts/flat.rb +1 -1
  12. data/lib/rdl/info.rb +3 -3
  13. data/lib/rdl/query.rb +11 -11
  14. data/lib/rdl/typecheck.rb +399 -136
  15. data/lib/rdl/types/finite_hash.rb +3 -2
  16. data/lib/rdl/types/generic.rb +7 -6
  17. data/lib/rdl/types/intersection.rb +3 -2
  18. data/lib/rdl/types/lexer.rex +2 -3
  19. data/lib/rdl/types/lexer.rex.rb +1 -4
  20. data/lib/rdl/types/method.rb +7 -6
  21. data/lib/rdl/types/nominal.rb +10 -1
  22. data/lib/rdl/types/parser.racc +7 -8
  23. data/lib/rdl/types/parser.tab.rb +108 -109
  24. data/lib/rdl/types/structural.rb +1 -0
  25. data/lib/rdl/types/tuple.rb +2 -2
  26. data/lib/rdl/types/type.rb +8 -8
  27. data/lib/rdl/types/type_inferencer.rb +1 -1
  28. data/lib/rdl/types/union.rb +2 -1
  29. data/lib/rdl/util.rb +28 -3
  30. data/lib/rdl/wrap.rb +216 -165
  31. data/lib/rdl_disable.rb +22 -15
  32. data/lib/types/core.rb +2 -4
  33. data/lib/types/core/_aliases.rb +14 -0
  34. data/lib/types/core/abbrev.rb +3 -0
  35. data/lib/types/core/array.rb +139 -0
  36. data/lib/types/core/base64.rb +8 -0
  37. data/lib/types/core/basic_object.rb +12 -0
  38. data/lib/types/core/benchmark.rb +9 -0
  39. data/lib/types/core/bigdecimal.rb +223 -0
  40. data/lib/types/core/bigmath.rb +10 -0
  41. data/lib/types/core/bignum.rb +214 -0
  42. data/lib/types/core/class.rb +15 -0
  43. data/lib/types/core/complex.rb +123 -0
  44. data/lib/types/core/coverage.rb +4 -0
  45. data/lib/types/core/csv.rb +3 -0
  46. data/lib/types/core/date.rb +4 -0
  47. data/lib/types/core/dir.rb +37 -0
  48. data/lib/types/core/encoding.rb +21 -0
  49. data/lib/types/core/enumerable.rb +96 -0
  50. data/lib/types/core/enumerator.rb +24 -0
  51. data/lib/types/core/exception.rb +15 -0
  52. data/lib/types/core/file.rb +125 -0
  53. data/lib/types/core/fileutils.rb +4 -0
  54. data/lib/types/core/fixnum.rb +213 -0
  55. data/lib/types/core/float.rb +199 -0
  56. data/lib/types/core/gem.rb +19 -0
  57. data/lib/types/core/hash.rb +72 -0
  58. data/lib/types/core/integer.rb +194 -0
  59. data/lib/types/core/io.rb +101 -0
  60. data/lib/types/core/kernel.rb +89 -0
  61. data/lib/types/core/marshal.rb +3 -0
  62. data/lib/types/core/matchdata.rb +24 -0
  63. data/lib/types/core/math.rb +50 -0
  64. data/lib/types/core/module.rb +81 -0
  65. data/lib/types/core/nil.rb +11 -0
  66. data/lib/types/core/numeric.rb +56 -0
  67. data/lib/types/core/object.rb +73 -0
  68. data/lib/types/core/pathname.rb +104 -0
  69. data/lib/types/core/proc.rb +12 -0
  70. data/lib/types/core/process.rb +110 -0
  71. data/lib/types/core/random.rb +13 -0
  72. data/lib/types/core/range.rb +37 -0
  73. data/lib/types/core/rational.rb +207 -0
  74. data/lib/types/core/regexp.rb +28 -0
  75. data/lib/types/core/set.rb +56 -0
  76. data/lib/types/core/string.rb +140 -0
  77. data/lib/types/core/strscan.rb +6 -0
  78. data/lib/types/core/symbol.rb +27 -0
  79. data/lib/types/core/time.rb +66 -0
  80. data/lib/types/core/uri.rb +18 -0
  81. data/lib/types/core/yaml.rb +3 -0
  82. data/lib/types/devise.rb +1 -0
  83. data/lib/types/devise/controller_helpers.rb +3 -0
  84. data/lib/types/devise/parameter_sanitizer.rb +2 -0
  85. data/lib/types/pundit.rb +2 -0
  86. data/lib/types/rails/_helpers.rb +50 -0
  87. data/lib/types/rails/abstract_controller/translation.rb +2 -0
  88. data/lib/types/rails/action_controller/base.rb +3 -0
  89. data/lib/types/rails/action_controller/instrumentation.rb +6 -0
  90. data/lib/types/rails/action_controller/metal.rb +3 -0
  91. data/lib/types/rails/action_controller/mime_responds.rb +13 -0
  92. data/lib/types/rails/action_controller/parameters.rb +3 -0
  93. data/lib/types/{rails-5.x → rails}/action_controller/strong_parameters.rb +4 -8
  94. data/lib/types/rails/action_dispatch/flashhash.rb +8 -0
  95. data/lib/types/rails/action_dispatch/routing.rb +10 -0
  96. data/lib/types/rails/action_mailer/base.rb +2 -0
  97. data/lib/types/rails/action_mailer/message_delivery.rb +2 -0
  98. data/lib/types/rails/action_view/helpers_sanitizehelper.rb +2 -0
  99. data/lib/types/rails/action_view/helpers_urlhelper.rb +5 -0
  100. data/lib/types/rails/active_model/errors.rb +14 -0
  101. data/lib/types/rails/active_model/validations.rb +2 -0
  102. data/lib/types/rails/active_record/associations.rb +208 -0
  103. data/lib/types/rails/active_record/base.rb +2 -0
  104. data/lib/types/rails/active_record/core.rb +2 -0
  105. data/lib/types/rails/active_record/finder_methods.rb +2 -0
  106. data/lib/types/rails/active_record/model_schema.rb +37 -0
  107. data/lib/types/rails/active_record/relation.rb +11 -0
  108. data/lib/types/rails/active_record/schema_types.rb +51 -0
  109. data/lib/types/rails/active_record/validations.rb +2 -0
  110. data/lib/types/rails/active_support/base.rb +2 -0
  111. data/lib/types/rails/active_support/logger.rb +3 -0
  112. data/lib/types/rails/active_support/tagged_logging.rb +2 -0
  113. data/lib/types/rails/active_support/time_with_zone.rb +13 -0
  114. data/lib/types/rails/active_support/time_zone.rb +2 -0
  115. data/lib/types/rails/fixnum.rb +2 -0
  116. data/lib/types/rails/integer.rb +2 -0
  117. data/lib/types/rails/rack/request.rb +2 -0
  118. data/lib/types/rails/string.rb +3 -0
  119. data/lib/types/rails/time.rb +1 -0
  120. data/rdl.gemspec +2 -2
  121. data/test/disabled_test_rdoc.rb +8 -8
  122. data/test/test_alias.rb +1 -0
  123. data/test/test_dsl.rb +4 -4
  124. data/test/test_generic.rb +45 -38
  125. data/test/test_intersection.rb +10 -10
  126. data/test/test_le.rb +103 -102
  127. data/test/test_member.rb +33 -33
  128. data/test/test_parser.rb +101 -96
  129. data/test/test_query.rb +84 -84
  130. data/test/test_rdl.rb +87 -52
  131. data/test/test_rdl_type.rb +26 -9
  132. data/test/test_type_contract.rb +32 -31
  133. data/test/test_typecheck.rb +802 -436
  134. data/test/test_types.rb +39 -39
  135. data/test/test_wrap.rb +3 -2
  136. metadata +91 -120
  137. data/extras/type_tests/%.rb +0 -171
  138. data/extras/type_tests/&.rb +0 -159
  139. data/extras/type_tests/**.rb +0 -222
  140. data/extras/type_tests/*.rb +0 -177
  141. data/extras/type_tests/+.rb +0 -170
  142. data/extras/type_tests/-.rb +0 -171
  143. data/extras/type_tests/1scomp.rb +0 -157
  144. data/extras/type_tests/<.rb +0 -170
  145. data/extras/type_tests/<<.rb +0 -159
  146. data/extras/type_tests/>>.rb +0 -159
  147. data/extras/type_tests/[].rb +0 -163
  148. data/extras/type_tests/^.rb +0 -159
  149. data/extras/type_tests/abs.rb +0 -155
  150. data/extras/type_tests/abs2.rb +0 -164
  151. data/extras/type_tests/angle.rb +0 -157
  152. data/extras/type_tests/arg.rb +0 -157
  153. data/extras/type_tests/bit_length.rb +0 -157
  154. data/extras/type_tests/ceil.rb +0 -157
  155. data/extras/type_tests/ceilRational.rb +0 -160
  156. data/extras/type_tests/conj.rb +0 -158
  157. data/extras/type_tests/defwhere.rb +0 -86
  158. data/extras/type_tests/denominator.rb +0 -157
  159. data/extras/type_tests/div.rb +0 -172
  160. data/extras/type_tests/divslash.rb +0 -179
  161. data/extras/type_tests/even?.rb +0 -157
  162. data/extras/type_tests/fdiv.rb +0 -244
  163. data/extras/type_tests/finite?.rb +0 -157
  164. data/extras/type_tests/floor.rb +0 -157
  165. data/extras/type_tests/floorRational.rb +0 -161
  166. data/extras/type_tests/hash.rb +0 -157
  167. data/extras/type_tests/imag.rb +0 -158
  168. data/extras/type_tests/infinite?.rb +0 -157
  169. data/extras/type_tests/modulo.rb +0 -171
  170. data/extras/type_tests/nan?.rb +0 -157
  171. data/extras/type_tests/neg.rb +0 -155
  172. data/extras/type_tests/next.rb +0 -157
  173. data/extras/type_tests/next_float.rb +0 -157
  174. data/extras/type_tests/numerator.rb +0 -157
  175. data/extras/type_tests/phase.rb +0 -157
  176. data/extras/type_tests/prev_float.rb +0 -157
  177. data/extras/type_tests/quo.rb +0 -179
  178. data/extras/type_tests/rationalize.rb +0 -157
  179. data/extras/type_tests/rationalizeArg.rb +0 -198
  180. data/extras/type_tests/real.rb +0 -157
  181. data/extras/type_tests/real?.rb +0 -157
  182. data/extras/type_tests/round.rb +0 -157
  183. data/extras/type_tests/roundArg.rb +0 -169
  184. data/extras/type_tests/size.rb +0 -157
  185. data/extras/type_tests/to_c.rb +0 -157
  186. data/extras/type_tests/to_f.rb +0 -155
  187. data/extras/type_tests/to_i.rb +0 -157
  188. data/extras/type_tests/to_r.rb +0 -157
  189. data/extras/type_tests/to_s.rb +0 -157
  190. data/extras/type_tests/truncate.rb +0 -157
  191. data/extras/type_tests/truncateArg.rb +0 -166
  192. data/extras/type_tests/type tests +0 -1
  193. data/extras/type_tests/zero?.rb +0 -155
  194. data/extras/type_tests/|.rb +0 -159
  195. data/lib/types/core-ruby-2.x/_aliases.rb +0 -15
  196. data/lib/types/core-ruby-2.x/abbrev.rb +0 -5
  197. data/lib/types/core-ruby-2.x/array.rb +0 -137
  198. data/lib/types/core-ruby-2.x/base64.rb +0 -10
  199. data/lib/types/core-ruby-2.x/basic_object.rb +0 -14
  200. data/lib/types/core-ruby-2.x/benchmark.rb +0 -11
  201. data/lib/types/core-ruby-2.x/bigdecimal.rb +0 -224
  202. data/lib/types/core-ruby-2.x/bigmath.rb +0 -12
  203. data/lib/types/core-ruby-2.x/bignum.rb +0 -214
  204. data/lib/types/core-ruby-2.x/class.rb +0 -17
  205. data/lib/types/core-ruby-2.x/complex.rb +0 -124
  206. data/lib/types/core-ruby-2.x/coverage.rb +0 -6
  207. data/lib/types/core-ruby-2.x/csv.rb +0 -5
  208. data/lib/types/core-ruby-2.x/date.rb +0 -6
  209. data/lib/types/core-ruby-2.x/dir.rb +0 -38
  210. data/lib/types/core-ruby-2.x/encoding.rb +0 -23
  211. data/lib/types/core-ruby-2.x/enumerable.rb +0 -98
  212. data/lib/types/core-ruby-2.x/enumerator.rb +0 -26
  213. data/lib/types/core-ruby-2.x/exception.rb +0 -17
  214. data/lib/types/core-ruby-2.x/file.rb +0 -126
  215. data/lib/types/core-ruby-2.x/fileutils.rb +0 -6
  216. data/lib/types/core-ruby-2.x/fixnum.rb +0 -213
  217. data/lib/types/core-ruby-2.x/float.rb +0 -199
  218. data/lib/types/core-ruby-2.x/gem.rb +0 -247
  219. data/lib/types/core-ruby-2.x/hash.rb +0 -72
  220. data/lib/types/core-ruby-2.x/integer.rb +0 -197
  221. data/lib/types/core-ruby-2.x/io.rb +0 -103
  222. data/lib/types/core-ruby-2.x/kernel.rb +0 -90
  223. data/lib/types/core-ruby-2.x/marshal.rb +0 -5
  224. data/lib/types/core-ruby-2.x/matchdata.rb +0 -26
  225. data/lib/types/core-ruby-2.x/math.rb +0 -53
  226. data/lib/types/core-ruby-2.x/module.rb +0 -83
  227. data/lib/types/core-ruby-2.x/nil.rb +0 -12
  228. data/lib/types/core-ruby-2.x/numeric.rb +0 -56
  229. data/lib/types/core-ruby-2.x/object.rb +0 -75
  230. data/lib/types/core-ruby-2.x/pathname.rb +0 -106
  231. data/lib/types/core-ruby-2.x/proc.rb +0 -16
  232. data/lib/types/core-ruby-2.x/process.rb +0 -127
  233. data/lib/types/core-ruby-2.x/random.rb +0 -17
  234. data/lib/types/core-ruby-2.x/range.rb +0 -39
  235. data/lib/types/core-ruby-2.x/rational.rb +0 -209
  236. data/lib/types/core-ruby-2.x/regexp.rb +0 -30
  237. data/lib/types/core-ruby-2.x/set.rb +0 -58
  238. data/lib/types/core-ruby-2.x/string.rb +0 -143
  239. data/lib/types/core-ruby-2.x/strscan.rb +0 -7
  240. data/lib/types/core-ruby-2.x/symbol.rb +0 -29
  241. data/lib/types/core-ruby-2.x/time.rb +0 -68
  242. data/lib/types/core-ruby-2.x/uri.rb +0 -20
  243. data/lib/types/core-ruby-2.x/yaml.rb +0 -5
  244. data/lib/types/rails-5.x/_helpers.rb +0 -52
  245. data/lib/types/rails-5.x/action_controller/mime_responds.rb +0 -11
  246. data/lib/types/rails-5.x/action_dispatch/routing.rb +0 -10
  247. data/lib/types/rails-5.x/active_model/errors.rb +0 -15
  248. data/lib/types/rails-5.x/active_model/validations.rb +0 -5
  249. data/lib/types/rails-5.x/active_record/associations.rb +0 -190
  250. data/lib/types/rails-5.x/active_record/core.rb +0 -3
  251. data/lib/types/rails-5.x/active_record/model_schema.rb +0 -39
  252. data/lib/types/rails-5.x/fixnum.rb +0 -3
data/lib/rdl.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # This wrapper file allows us to completely disable RDL in certain modes.
2
-
3
2
  if defined?(Rails)
4
3
  require 'rdl/boot_rails'
5
4
  else
@@ -12,52 +12,72 @@ def RDL.config
12
12
  end
13
13
  require 'rdl/info.rb'
14
14
 
15
- # Method/variable info table with kinds:
16
- # For methods
17
- # :pre to array of precondition contracts
18
- # :post to array of postcondition contracts
19
- # :type to array of types
20
- # :source_location to [filename, linenumber] location of most recent definition
21
- # :typecheck - boolean that is true if method should be statically type checked
22
- # :otype to set of types that were observed at run time, where a type is a finite hash {:args => Array<Class>, :ret => Class, :block => %bool}
23
- # :context_types to array of [klass, meth, Type] - method types that exist only within this method. An icky hack to deal with Rails `params`.
24
- # For variables
25
- # :type to type
26
- $__rdl_info = RDL::Info.new
27
-
28
- # Map from full_method_name to number of times called when wrapped
29
- $__rdl_wrapped_calls = Hash.new 0
30
-
31
- # Hash from class name to array of symbols that are the class's type parameters
32
- $__rdl_type_params = Hash.new
33
-
34
- # Hash from class name to method name to its alias method name
35
- # class names are strings
36
- # method names are symbols
37
- $__rdl_aliases = Hash.new
38
-
39
- # Set of [class, method] pairs to wrap.
40
- # class is a string
41
- # method is a symbol
42
- $__rdl_to_wrap = Set.new
43
-
44
- # Map from symbols to set of [class, method] pairs to type check when those symbols are rdl_do_typecheck'd
45
- # (or the methods are defined, for the symbol :now)
46
- $__rdl_to_typecheck = Hash.new
47
- $__rdl_to_typecheck[:now] = Set.new
48
-
49
- # Map from symbols to Array<Proc> where the Procs are called when those symbols are rdl_do_typecheck'd
50
- $__rdl_at = Hash.new
51
-
52
- # List of contracts that should be applied to the next method definition
53
- $__rdl_deferred = []
15
+ module RDL::Globals
16
+ # Method/variable info table with kinds:
17
+ # For methods
18
+ # :pre to array of precondition contracts
19
+ # :post to array of postcondition contracts
20
+ # :type to array of types
21
+ # :source_location to [filename, linenumber] location of most recent definition
22
+ # :typecheck - boolean that is true if method should be statically type checked
23
+ # :otype to set of types that were observed at run time, where a type is a finite hash {:args => Array<Class>, :ret => Class, :block => %bool}
24
+ # :context_types to array of [klass, meth, Type] - method types that exist only within this method. An icky hack to deal with Rails `params`.
25
+ # For variables
26
+ # :type to type
27
+ @info = RDL::Info.new
28
+
29
+ # Map from full_method_name to number of times called when wrapped
30
+ @wrapped_calls = Hash.new 0
31
+
32
+ # Hash from class name to array of symbols that are the class's type parameters
33
+ @type_params = Hash.new
34
+
35
+ # Hash from class name to method name to its alias method name
36
+ # class names are strings
37
+ # method names are symbols
38
+ @aliases = Hash.new
39
+
40
+ # Set of [class, method] pairs to wrap.
41
+ # class is a string
42
+ # method is a symbol
43
+ @to_wrap = Set.new
44
+
45
+ # Map from symbols to set of [class, method] pairs to type check when those symbols are rdl_do_typecheck'd
46
+ # (or the methods are defined, for the symbol :now)
47
+ @to_typecheck = Hash.new
48
+ @to_typecheck[:now] = Set.new
49
+
50
+ # Map from symbols to Array<Proc> where the Procs are called when those symbols are rdl_do_typecheck'd
51
+ @to_do_at = Hash.new
52
+
53
+ # List of contracts that should be applied to the next method definition
54
+ @deferred = []
55
+ end
56
+
57
+ class << RDL::Globals # add accessors and readers for module variables
58
+ attr_accessor :info
59
+ attr_accessor :wrapped_calls
60
+ attr_accessor :type_params
61
+ attr_reader :aliases
62
+ attr_accessor :to_wrap
63
+ attr_accessor :to_typecheck
64
+ attr_accessor :to_do_at
65
+ attr_accessor :deferred
66
+ end
54
67
 
55
68
  # Create switches to control whether wrapping happens and whether
56
69
  # contracts are checked. These need to be created before rdl/wrap.rb
57
70
  # is loaded.
58
71
  require 'rdl/switch.rb'
59
- $__rdl_wrap_switch = RDL::Switch.new
60
- $__rdl_contract_switch = RDL::Switch.new
72
+ module RDL::Globals
73
+ @wrap_switch = RDL::Switch.new
74
+ @contract_switch = RDL::Switch.new
75
+ end
76
+
77
+ class << RDL::Globals
78
+ attr_reader :wrap_switch
79
+ attr_reader :contract_switch
80
+ end
61
81
 
62
82
  require 'rdl/types/type.rb'
63
83
  require 'rdl/types/annotated_arg.rb'
@@ -95,39 +115,50 @@ require 'rdl/query.rb'
95
115
  require 'rdl/typecheck.rb'
96
116
  #require_relative 'rdl/stats.rb'
97
117
 
98
- $__rdl_parser = RDL::Type::Parser.new
99
-
100
- # Map from file names to [digest, cache] where 2nd elt maps
101
- # :ast to the AST
102
- # :line_defs maps linenumber to AST for def at that line
103
- $__rdl_ruby_parser_cache = Hash.new
104
-
105
- # Some generally useful types; not really a big deal to do this since
106
- # NominalTypes are cached, but these names are shorter to type
107
- $__rdl_nil_type = RDL::Type::NominalType.new NilClass # actually creates singleton type
108
- $__rdl_top_type = RDL::Type::TopType.new
109
- $__rdl_bot_type = RDL::Type::BotType.new
110
- $__rdl_object_type = RDL::Type::NominalType.new Object
111
- $__rdl_true_type = RDL::Type::NominalType.new TrueClass # actually creates singleton type
112
- $__rdl_false_type = RDL::Type::NominalType.new FalseClass # also singleton type
113
- $__rdl_bool_type = RDL::Type::UnionType.new($__rdl_true_type, $__rdl_false_type)
114
- $__rdl_fixnum_type = RDL::Type::NominalType.new Fixnum
115
- $__rdl_bignum_type = RDL::Type::NominalType.new Bignum
116
- $__rdl_float_type = RDL::Type::NominalType.new Float
117
- $__rdl_complex_type = RDL::Type::NominalType.new Complex
118
- $__rdl_rational_type = RDL::Type::NominalType.new Rational
119
- $__rdl_integer_type = RDL::Type::UnionType.new($__rdl_fixnum_type, $__rdl_bignum_type)
120
- $__rdl_numeric_type = RDL::Type::NominalType.new Numeric
121
- $__rdl_string_type = RDL::Type::NominalType.new String
122
- $__rdl_array_type = RDL::Type::NominalType.new Array
123
- $__rdl_hash_type = RDL::Type::NominalType.new Hash
124
- $__rdl_symbol_type = RDL::Type::NominalType.new Symbol
125
- $__rdl_range_type = RDL::Type::NominalType.new Range
126
- $__rdl_regexp_type = RDL::Type::NominalType.new Regexp
127
- $__rdl_standard_error_type = RDL::Type::NominalType.new StandardError
128
- $__rdl_proc_type = RDL::Type::NominalType.new Proc
129
-
130
- # Hash from special type names to their values
131
- $__rdl_special_types = {'%any' => $__rdl_top_type,
132
- '%bot' => $__rdl_bot_type,
133
- '%bool' => $__rdl_bool_type}
118
+ module RDL::Globals
119
+ FIXBIG_VERSIONS = ['>= 2.0.0', '< 2.4.0']
120
+ # INTEGER_VERSIONS = '>= 2.4.0'
121
+
122
+ @parser = RDL::Type::Parser.new
123
+
124
+ # Map from file names to [digest, cache] where 2nd elt maps
125
+ # :ast to the AST
126
+ # :line_defs maps linenumber to AST for def at that line
127
+ @parser_cache = Hash.new
128
+
129
+ # Some generally useful types; not really a big deal to do this since
130
+ # NominalTypes are cached, but these names are shorter to type
131
+ @types = Hash.new
132
+ @types[:nil] = RDL::Type::NominalType.new NilClass # actually creates singleton type
133
+ @types[:top] = RDL::Type::TopType.new
134
+ @types[:bot] = RDL::Type::BotType.new
135
+ @types[:object] = RDL::Type::NominalType.new Object
136
+ @types[:true] = RDL::Type::NominalType.new TrueClass # actually creates singleton type
137
+ @types[:false] = RDL::Type::NominalType.new FalseClass # also singleton type
138
+ @types[:bool] = RDL::Type::UnionType.new(@types[:true], @types[:false])
139
+ @types[:float] = RDL::Type::NominalType.new Float
140
+ @types[:complex] = RDL::Type::NominalType.new Complex
141
+ @types[:rational] = RDL::Type::NominalType.new Rational
142
+ @types[:integer] = RDL::Type::NominalType.new Integer
143
+ @types[:numeric] = RDL::Type::NominalType.new Numeric
144
+ @types[:string] = RDL::Type::NominalType.new String
145
+ @types[:array] = RDL::Type::NominalType.new Array
146
+ @types[:hash] = RDL::Type::NominalType.new Hash
147
+ @types[:symbol] = RDL::Type::NominalType.new Symbol
148
+ @types[:range] = RDL::Type::NominalType.new Range
149
+ @types[:regexp] = RDL::Type::NominalType.new Regexp
150
+ @types[:standard_error] = RDL::Type::NominalType.new StandardError
151
+ @types[:proc] = RDL::Type::NominalType.new Proc
152
+
153
+ # Hash from special type names to their values
154
+ @special_types = {'%any' => @types[:top],
155
+ '%bot' => @types[:bot],
156
+ '%bool' => @types[:bool]}
157
+ end
158
+
159
+ class << RDL::Globals
160
+ attr_reader :parser
161
+ attr_accessor :parser_cache
162
+ attr_reader :types
163
+ attr_reader :special_types
164
+ end
@@ -2,14 +2,8 @@ if Rails.env.development? || Rails.env.test?
2
2
  require 'rdl/boot'
3
3
  require 'types/core'
4
4
 
5
- version = Rails::VERSION::STRING.split('.')[0] + ".x"
6
-
7
- begin
8
- require_relative "../types/rails-#{version}/_helpers.rb" # load type aliases first
9
- Dir[File.dirname(__FILE__) + "/../types/rails-#{version}/**/*.rb"].each { |f| require f }
10
- rescue LoadError
11
- $stderr.puts("rdl could not load type definitions for Rails v#{version}")
12
- end
5
+ require_relative "../types/rails/_helpers.rb" # load type aliases first
6
+ Dir[File.dirname(__FILE__) + "/../types/rails/**/*.rb"].each { |f| require f }
13
7
  elsif Rails.env.production?
14
8
  require 'rdl_disable'
15
9
  class ActionController::Base
@@ -5,26 +5,47 @@ class RDL::Config
5
5
 
6
6
  attr_accessor :nowrap
7
7
  attr_accessor :gather_stats
8
- attr_accessor :report
9
- attr_accessor :guess_types
8
+ attr_reader :report # writer is custom defined
10
9
  attr_accessor :type_defaults, :pre_defaults, :post_defaults
11
10
 
12
11
  def initialize
13
- @nowrap = Set.new
12
+ @nowrap = Set.new # Set of symbols
14
13
  @gather_stats = false
15
- @report = false
16
- @guess_types = []
14
+ @report = false # if this is enabled by default, modify @at_exit_installed
15
+ @guess_types = [] # same as above
16
+ @at_exit_installed = false
17
17
  @type_defaults = { wrap: true, typecheck: false }
18
18
  @pre_defaults = { wrap: true }
19
19
  @post_defaults = { wrap: true }
20
20
  end
21
21
 
22
+ def report=(val)
23
+ install_at_exit
24
+ @report = val
25
+ end
26
+
27
+ def guess_types
28
+ install_at_exit
29
+ return @guess_types
30
+ end
31
+
32
+ def guess_types=(val)
33
+ install_at_exit
34
+ @guess_types = val
35
+ end
36
+
22
37
  def add_nowrap(*klasses)
23
- klasses.each { |klass| @nowrap.add klass }
38
+ klasses.each { |klass|
39
+ @nowrap.add klass.to_s.to_sym
40
+ @nowrap.add RDL::Util.add_singleton_marker(klass.to_s).to_sym
41
+ }
24
42
  end
25
43
 
26
44
  def remove_nowrap(*klasses)
27
- klasses.each { |klass| @nowrap.delete klass }
45
+ klasses.each { |klass|
46
+ @nowrap.delete klass.to_s.to_sym
47
+ @nowrap.delete RDL::Util.add_singleton_marker(klass.to_s).to_sym
48
+ }
28
49
  end
29
50
 
30
51
  # To use, copy these 3 lines to the test file of a gem
@@ -39,7 +60,7 @@ RDL::Config.instance.profile_stats
39
60
 
40
61
  at_exit do
41
62
  Profiler__.stop_profile
42
- $__rdl_contract_switch.off {
63
+ RDL::Globals.contract_switch.off {
43
64
  puts "START."
44
65
  puts "Performing Profile Analysis"
45
66
  # Class Name => [Times Contract Called | Times Called | Time | Time | Class Profile]
@@ -75,7 +96,7 @@ RDL::Config.instance.profile_stats
75
96
  }
76
97
 
77
98
  p "Scanning RDL Contract Log"
78
- $__rdl_wrapped_calls.each{ |mname,ct|
99
+ RDL::Globals.wrapped_calls.each{ |mname,ct|
79
100
  if (totals[mname]) then
80
101
  if (totals[mname][0]) then
81
102
  totals[mname][0] = ct
@@ -132,7 +153,7 @@ RDL::Config.instance.profile_stats
132
153
  puts "------------------------------"
133
154
  typechecked = []
134
155
  missing = []
135
- $__rdl_info.info.each_pair { |klass, meths|
156
+ RDL::Globals.info.info.each_pair { |klass, meths|
136
157
  meths.each { |meth, kinds|
137
158
  if kinds[:typecheck]
138
159
  if kinds[:typechecked]
@@ -186,16 +207,16 @@ RDL::Config.instance.profile_stats
186
207
  puts " -> XXXX'"
187
208
 
188
209
  # next print based on observed types
189
- otypes = $__rdl_info.get(klass, meth, :otype) if $__rdl_info.has?(klass, meth, :otype) # observed types
210
+ otypes = RDL::Globals.info.get(klass, meth, :otype) if RDL::Globals.info.has?(klass, meth, :otype) # observed types
190
211
  return if otypes.nil?
191
212
  first = true
192
213
  print " type #{if is_sing then '\'self.' + meth + '\'' else ':' + meth end}, '("
193
214
  otargs = []
194
- otret = $__rdl_bot_type
215
+ otret = RDL::Globals.types[:bot]
195
216
  otblock = false
196
217
  otypes.each { |ot|
197
218
  ot[:args].each_with_index { |t, i|
198
- otargs[i] = $__rdl_bot_type if otargs[i].nil?
219
+ otargs[i] = RDL::Globals.types[:bot] if otargs[i].nil?
199
220
  otargs[i] = RDL::Type::UnionType.new(otargs[i], RDL::Type::NominalType.new(t)).canonical
200
221
  }
201
222
  otret = RDL::Type::UnionType.new(otret, RDL::Type::NominalType.new(ot[:ret])).canonical
@@ -233,7 +254,13 @@ RDL::Config.instance.profile_stats
233
254
  end
234
255
  end
235
256
 
236
- at_exit do
237
- RDL::Config.instance.do_report
238
- RDL::Config.instance.do_guess_types
239
- end
257
+ private
258
+
259
+ def install_at_exit
260
+ return if @at_exit_installed
261
+ at_exit do
262
+ RDL::Config.instance.do_report
263
+ RDL::Config.instance.do_guess_types
264
+ end
265
+ @at_exit_installed = true
266
+ end
@@ -8,7 +8,7 @@ module RDL::Contract
8
8
  end
9
9
 
10
10
  def check(slf, *v, &blk)
11
- $__rdl_contract_switch.off {
11
+ RDL::Globals.contract_switch.off {
12
12
  if @pred && v.length >= @pred.arity
13
13
  unless blk ? slf.instance_exec(*v, blk, &@pred) : slf.instance_exec(*v, &@pred) # TODO: Fix blk
14
14
  # unless blk ? pred.call(*v, &blk) : pred.call(*v)
@@ -23,7 +23,7 @@ class RDL::Info
23
23
  # if no prev info for kind, set to val and return true
24
24
  # if prev info for kind, return true if prev == val and false otherwise
25
25
  def set(klass, label, kind, val)
26
- klass = klass.to_s
26
+ klass = RDL::Util.to_class_str(klass)
27
27
  label = label.to_sym
28
28
  @info[klass] = {} unless @info[klass]
29
29
  @info[klass][label] = {} unless @info[klass][label]
@@ -73,8 +73,8 @@ class RDL::Info
73
73
  end
74
74
 
75
75
  def get_with_aliases(klass, label, kind)
76
- while $__rdl_aliases[klass] && $__rdl_aliases[klass][label]
77
- label = $__rdl_aliases[klass][label]
76
+ while RDL::Globals.aliases[klass] && RDL::Globals.aliases[klass][label]
77
+ label = RDL::Globals.aliases[klass][label]
78
78
  end
79
79
  get(klass, label, kind)
80
80
  end
@@ -17,25 +17,25 @@ class RDL::Query
17
17
  # klass = self.class.to_s
18
18
  # meth = q.to_sym
19
19
  end
20
- return $__rdl_info.get(klass, meth, :type)
20
+ return RDL::Globals.info.get(klass, meth, :type)
21
21
  end
22
22
 
23
23
  # Return an ordered list of all method types of a class. The query should be a class name.
24
24
  def self.class_query(q)
25
25
  klass = q.to_s
26
- return nil unless $__rdl_info.info.has_key? klass
26
+ return nil unless RDL::Globals.info.info.has_key? klass
27
27
  cls_meths = []
28
28
  cls_klass = RDL::Util.add_singleton_marker(klass)
29
- if $__rdl_info.info.has_key? cls_klass then
30
- $__rdl_info.info[cls_klass].each { |meth, kinds|
29
+ if RDL::Globals.info.info.has_key? cls_klass then
30
+ RDL::Globals.info.info[cls_klass].each { |meth, kinds|
31
31
  if kinds.has_key? :type then
32
32
  kinds[:type].each { |t| cls_meths << [meth.to_s, t] }
33
33
  end
34
34
  }
35
35
  end
36
36
  inst_meths = []
37
- if $__rdl_info.info.has_key? klass then
38
- $__rdl_info.info[klass].each { |meth, kinds|
37
+ if RDL::Globals.info.info.has_key? klass then
38
+ RDL::Globals.info.info[klass].each { |meth, kinds|
39
39
  if kinds.has_key? :type then
40
40
  kinds[:type].each { |t| inst_meths << [meth.to_s, t] }
41
41
  end
@@ -49,9 +49,9 @@ class RDL::Query
49
49
 
50
50
  # Returns sorted list of pairs [method name, type] matching query. The query should be a string containing a method type query.
51
51
  def self.method_type_query(q)
52
- q = $__rdl_parser.scan_str "#Q #{q}"
52
+ q = RDL::Globals.parser.scan_str "#Q #{q}"
53
53
  result = []
54
- $__rdl_info.info.each { |klass, meths|
54
+ RDL::Globals.info.info.each { |klass, meths|
55
55
  meths.each { |meth, kinds|
56
56
  if kinds.has_key? :type then
57
57
  kinds[:type].each { |t|
@@ -67,10 +67,10 @@ class RDL::Query
67
67
  end
68
68
  end
69
69
 
70
- class Object
70
+ module RDL
71
71
 
72
- def rdl_query(q)
73
- $__rdl_contract_switch.off {
72
+ def self.query(q)
73
+ RDL::Globals.contract_switch.off {
74
74
  if q =~ /^[A-Z]\w*(#|\.)([a-z_]\w*(!|\?|=)?|!|~|\+|\*\*|-|\*|\/|%|<<|>>|&|\||\^|<|<=|=>|>|==|===|!=|=~|!~|<=>|\[\]|\[\]=)$/
75
75
  typs = RDL::Query.method_query(q)
76
76
  if typs.nil? then
@@ -124,7 +124,7 @@ module RDL::Typecheck
124
124
  error :inconsistent_var_type_type, [var.to_s, (first_typ + neq).map { |t| t.to_s }.join(' and ')], e unless neq.empty?
125
125
  env.env[var] = {type: h[:type], fixed: true}
126
126
  else
127
- typ = RDL::Type::UnionType.new(first_typ, *rest.map { |other| ((other.has_key? var) && other[var]) || $__rdl_nil_type })
127
+ typ = RDL::Type::UnionType.new(first_typ, *rest.map { |other| ((other.has_key? var) && other[var]) || RDL::Globals.types[:nil] })
128
128
  typ = typ.canonical
129
129
  env.env[var] = {type: typ, fixed: false}
130
130
  end
@@ -155,15 +155,30 @@ module RDL::Typecheck
155
155
 
156
156
  # report msg at ast's loc
157
157
  def self.error(reason, args, ast)
158
- raise StaticTypeError, ("\n" + (Parser::Diagnostic.new :error, reason, args, ast.loc.expression).render.join("\n"))
158
+ raise StaticTypeError, ("\n" + (Diagnostic.new :error, reason, args, ast.loc.expression).render.join("\n"))
159
159
  end
160
160
 
161
161
  def self.note(reason, args, ast)
162
- puts (Parser::Diagnostic.new :note, reason, args, ast.loc.expression).render
162
+ puts (Diagnostic.new :note, reason, args, ast.loc.expression).render
163
+ end
164
+
165
+ def self.get_leaves(node, r=[])
166
+ node.children.each {|n|
167
+ if n.is_a? AST::Node
168
+ get_leaves(n, r)
169
+ elsif n
170
+ r.push n
171
+ end
172
+ }
173
+ r
174
+ end
175
+
176
+ def self.is_RDL(node)
177
+ return node != nil && node.type == :const && node.children[0] == nil && node.children[1] == :RDL
163
178
  end
164
179
 
165
180
  def self.get_ast(klass, meth)
166
- file, line = $__rdl_info.get(klass, meth, :source_location)
181
+ file, line = RDL::Globals.info.get(klass, meth, :source_location)
167
182
  raise RuntimeError, "No file for #{RDL::Util.pp_klass_method(klass, meth)}" if file.nil?
168
183
  raise RuntimeError, "static type checking in irb not supported" if file == "(irb)"
169
184
  if file == "(pry)"
@@ -179,23 +194,24 @@ module RDL::Typecheck
179
194
  end
180
195
 
181
196
  digest = Digest::MD5.file file
182
- cache_hit = (($__rdl_ruby_parser_cache.has_key? file) &&
183
- ($__rdl_ruby_parser_cache[file][0] == digest))
197
+ cache_hit = ((RDL::Globals.parser_cache.has_key? file) &&
198
+ (RDL::Globals.parser_cache[file][0] == digest))
184
199
  unless cache_hit
185
200
  file_ast = Parser::CurrentRuby.parse_file file
186
201
  mapper = ASTMapper.new(file)
187
202
  mapper.process(file_ast)
188
203
  cache = {ast: file_ast, line_defs: mapper.line_defs}
189
- $__rdl_ruby_parser_cache[file] = [digest, cache]
204
+ RDL::Globals.parser_cache[file] = [digest, cache]
190
205
  end
191
- ast = $__rdl_ruby_parser_cache[file][1][:line_defs][line]
206
+ ast = RDL::Globals.parser_cache[file][1][:line_defs][line]
192
207
  raise RuntimeError, "Can't find source for class #{RDL::Util.pp_klass_method(klass, meth)}" if ast.nil?
193
208
  return ast
194
209
  end
195
210
 
196
211
  def self.typecheck(klass, meth)
212
+ @cur_meth = [klass, meth]
197
213
  ast = get_ast(klass, meth)
198
- types = $__rdl_info.get(klass, meth, :type)
214
+ types = RDL::Globals.info.get(klass, meth, :type)
199
215
  raise RuntimeError, "Can't typecheck method with no types?!" if types.nil? or types == []
200
216
 
201
217
  if ast.type == :def
@@ -206,7 +222,7 @@ module RDL::Typecheck
206
222
  raise RuntimeError, "Unexpected ast type #{ast.type}"
207
223
  end
208
224
  raise RuntimeError, "Method #{name} defined where method #{meth} expected" if name.to_sym != meth
209
- context_types = $__rdl_info.get(klass, meth, :context_types)
225
+ context_types = RDL::Globals.info.get(klass, meth, :context_types)
210
226
  types.each { |type|
211
227
  if RDL::Util.has_singleton_marker(klass)
212
228
  # to_class gets the class object itself, so remove singleton marker to get class rather than singleton class
@@ -214,6 +230,10 @@ module RDL::Typecheck
214
230
  else
215
231
  self_type = RDL::Type::NominalType.new(klass)
216
232
  end
233
+ if meth == :initialize
234
+ # initialize method must always return "self" or GenericType where base is "self"
235
+ error :bad_initialize_type, [], ast unless ((type.ret.is_a?(RDL::Type::VarType) && type.ret.name == :self) || (type.ret.is_a?(RDL::Type::GenericType) && type.ret.base.is_a?(RDL::Type::VarType) && type.ret.base.name == :self))
236
+ end
217
237
  inst = {self: self_type}
218
238
  type = type.instantiate inst
219
239
  _, targs = args_hash({}, Env.new, type, args, ast, 'method')
@@ -222,14 +242,14 @@ module RDL::Typecheck
222
242
  begin
223
243
  old_captured = scope[:captured].dup
224
244
  if body.nil?
225
- body_type = $__rdl_nil_type
245
+ body_type = RDL::Globals.types[:nil]
226
246
  else
227
247
  _, body_type = tc(scope, Env.new(targs.merge(scope[:captured])), body)
228
248
  end
229
249
  end until old_captured == scope[:captured]
230
- error :bad_return_type, [body_type.to_s, type.ret.to_s], body unless body.nil? || body_type <= type.ret
250
+ error :bad_return_type, [body_type.to_s, type.ret.to_s], body unless body.nil? || meth == :initialize || body_type <= type.ret
231
251
  }
232
- $__rdl_info.set(klass, meth, :typechecked, true)
252
+ RDL::Globals.info.set(klass, meth, :typechecked, true)
233
253
  end
234
254
 
235
255
  # [+ scope +] is used to typecheck default values for optional arguments
@@ -262,7 +282,7 @@ module RDL::Typecheck
262
282
  elsif arg.type == :restarg
263
283
  error :type_arg_kind_mismatch, [kind, 'optional', 'vararg'], arg if targ.optional?
264
284
  error :type_arg_kind_mismatch, [kind, 'required', 'vararg'], arg if !targ.vararg?
265
- targs[arg.children[0]] = RDL::Type::GenericType.new($__rdl_array_type, targ.type)
285
+ targs[arg.children[0]] = RDL::Type::GenericType.new(RDL::Globals.types[:array], targ.type)
266
286
  tpos += 1
267
287
  elsif arg.type == :kwarg
268
288
  error :type_args_no_kws, [kind], arg unless targ.is_a?(RDL::Type::FiniteHashType)
@@ -285,7 +305,7 @@ module RDL::Typecheck
285
305
  elsif arg.type == :kwrestarg
286
306
  error :type_args_no_kws, [kind], e unless targ.is_a?(RDL::Type::FiniteHashType)
287
307
  error :type_args_no_kw_rest, [kind], arg if targ.rest.nil?
288
- targs[arg.children[0]] = RDL::Type::GenericType.new($__rdl_hash_type, $__rdl_symbol_type, targ.rest)
308
+ targs[arg.children[0]] = RDL::Type::GenericType.new(RDL::Globals.types[:hash], RDL::Globals.types[:symbol], targ.rest)
289
309
  kw_rest_matched = true
290
310
  elsif arg.type == :blockarg
291
311
  error :type_arg_block, [kind, kind], arg unless type.block
@@ -305,6 +325,27 @@ module RDL::Typecheck
305
325
  return [env, targs]
306
326
  end
307
327
 
328
+ def self.get_super_owner(slf, m)
329
+ case slf
330
+ when RDL::Type::SingletonType
331
+ if slf.nominal.name == 'Class'
332
+ trecv_owner = get_super_owner_from_class(slf.val.singleton_class, m)
333
+ RDL::Type::SingletonType.new(RDL::Util.singleton_class_to_class(trecv_owner))
334
+ else
335
+ raise Exception, 'self is singleton class but nominal is not Class'
336
+ end
337
+ when RDL::Type::NominalType
338
+ RDL::Type::NominalType.new(get_super_owner_from_class(slf.klass, m))
339
+ else
340
+ raise Exception, 'unsupported self #{slf} in get_super_owner'
341
+ end
342
+ end
343
+
344
+ def self.get_super_owner_from_class(cls, m)
345
+ raise Exception, "cls #{cls} is not a Class" if cls.class != Class
346
+ cls.superclass.instance_method(m).owner
347
+ end
348
+
308
349
  # The actual type checking logic.
309
350
  # [+ scope +] tracks flow-insensitive information about the current scope, excluding local variables
310
351
  # [+ env +] is the (local variable) Env
@@ -314,11 +355,11 @@ module RDL::Typecheck
314
355
  def self.tc(scope, env, e)
315
356
  case e.type
316
357
  when :nil
317
- [env, $__rdl_nil_type]
358
+ [env, RDL::Globals.types[:nil]]
318
359
  when :true
319
- [env, $__rdl_true_type]
360
+ [env, RDL::Globals.types[:true]]
320
361
  when :false
321
- [env, $__rdl_false_type]
362
+ [env, RDL::Globals.types[:false]]
322
363
  when :complex, :rational, :str, :string # constants
323
364
  [env, RDL::Type::NominalType.new(e.children[0].class)]
324
365
  when :int, :float, :sym # singletons
@@ -326,15 +367,15 @@ module RDL::Typecheck
326
367
  when :dstr, :xstr # string (or execute-string) with interpolation
327
368
  envi = env
328
369
  e.children.each { |ei| envi, _ = tc(scope, envi, ei) }
329
- [envi, $__rdl_string_type]
370
+ [envi, RDL::Globals.types[:string]]
330
371
  when :dsym # symbol with interpolation
331
372
  envi = env
332
373
  e.children.each { |ei| envi, _ = tc(scope, envi, ei) }
333
- [envi, $__rdl_symbol_type]
374
+ [envi, RDL::Globals.types[:symbol]]
334
375
  when :regexp
335
376
  envi = env
336
377
  e.children.each { |ei| envi, _ = tc(scope, envi, ei) unless ei.type == :regopt }
337
- [envi, $__rdl_regexp_type]
378
+ [envi, RDL::Globals.types[:regexp]]
338
379
  when :array
339
380
  envi = env
340
381
  tis = []
@@ -350,16 +391,16 @@ module RDL::Typecheck
350
391
  ti.elts.each_pair { |k, t|
351
392
  tis << RDL::Type::TupleType.new(RDL::Type::SingletonType.new(k), t)
352
393
  }
353
- elsif ti.is_a?(RDL::Type::GenericType) && ti.base == $__rdl_array_type
394
+ elsif ti.is_a?(RDL::Type::GenericType) && ti.base == RDL::Globals.types[:array]
354
395
  is_array = true
355
396
  tis << ti.params[0]
356
- elsif ti.is_a?(RDL::Type::GenericType) && ti.base == $__rdl_hash_type
397
+ elsif ti.is_a?(RDL::Type::GenericType) && ti.base == RDL::Globals.types[:hash]
357
398
  is_array = true
358
399
  tis << RDL::Type::TupleType.new(*ti.params)
359
400
  elsif ti.is_a?(RDL::Type::SingletonType) && ti.val.nil?
360
401
  # nil gets thrown out
361
- elsif ($__rdl_array_type <= ti) || (ti <= $__rdl_array_type) ||
362
- ($__rdl_hash_type <= ti) || (ti <= $__rdl_hash_type)
402
+ elsif (RDL::Globals.types[:array] <= ti) || (ti <= RDL::Globals.types[:array]) ||
403
+ (RDL::Globals.types[:hash] <= ti) || (ti <= RDL::Globals.types[:hash])
363
404
  # might or might not be array...can't splat...
364
405
  error :cant_splat, [ti], ei
365
406
  else
@@ -371,7 +412,7 @@ module RDL::Typecheck
371
412
  end
372
413
  }
373
414
  if is_array
374
- [envi, RDL::Type::GenericType.new($__rdl_array_type, RDL::Type::UnionType.new(*tis).canonical)]
415
+ [envi, RDL::Type::GenericType.new(RDL::Globals.types[:array], RDL::Type::UnionType.new(*tis).canonical)]
375
416
  else
376
417
  [envi, RDL::Type::TupleType.new(*tis)]
377
418
  end
@@ -394,7 +435,7 @@ module RDL::Typecheck
394
435
  tkwsplat.cant_promote! # must remain finite hash
395
436
  tlefts.concat(tkwsplat.elts.keys.map { |k| RDL::Type::SingletonType.new(k) })
396
437
  trights.concat(tkwsplat.elts.values)
397
- elsif tkwsplat.is_a?(RDL::Type::GenericType) && tkwsplat.base == $__rdl_hash_type
438
+ elsif tkwsplat.is_a?(RDL::Type::GenericType) && tkwsplat.base == RDL::Globals.types[:hash]
398
439
  is_fh = false
399
440
  tlefts << tkwsplat.params[0]
400
441
  trights << tkwsplat.params[1]
@@ -412,7 +453,7 @@ module RDL::Typecheck
412
453
  else
413
454
  tleft = RDL::Type::UnionType.new(*tlefts)
414
455
  tright = RDL::Type::UnionType.new(*trights)
415
- [envi, RDL::Type::GenericType.new($__rdl_hash_type, tleft, tright)]
456
+ [envi, RDL::Type::GenericType.new(RDL::Globals.types[:hash], tleft, tright)]
416
457
  end
417
458
  #TODO test!
418
459
  # when :kwsplat # TODO!
@@ -423,7 +464,7 @@ module RDL::Typecheck
423
464
  t1 = RDL::Type::NominalType.new(t1.val.class) if t1.is_a? RDL::Type::SingletonType
424
465
  t2 = RDL::Type::NominalType.new(t2.val.class) if t2.is_a? RDL::Type::SingletonType
425
466
  error :nonmatching_range_type, [t1, t2], e unless t1 <= t2 || t2 <= t1
426
- [env2, RDL::Type::GenericType.new($__rdl_range_type, t1)]
467
+ [env2, RDL::Type::GenericType.new(RDL::Globals.types[:range], t1)]
427
468
  when :self
428
469
  [env, env[:self]]
429
470
  when :lvar, :ivar, :cvar, :gvar
@@ -431,7 +472,7 @@ module RDL::Typecheck
431
472
  when :lvasgn, :ivasgn, :cvasgn, :gvasgn
432
473
  x = e.children[0]
433
474
  # if local var, lhs is bound to nil before assignment is executed! only matters in type checking for locals
434
- env = env.bind(x, $__rdl_nil_type) if ((e.type == :lvasgn) && (not (env.has_key? x)))
475
+ env = env.bind(x, RDL::Globals.types[:nil]) if ((e.type == :lvasgn) && (not (env.has_key? x)))
435
476
  envright, tright = tc(scope, env, e.children[1])
436
477
  tc_vasgn(scope, envright, e.type, x, tright, e)
437
478
  when :masgn
@@ -439,7 +480,7 @@ module RDL::Typecheck
439
480
  e.children[0].children.each { |asgn|
440
481
  next unless asgn.type == :lvasgn
441
482
  x = e.children[0]
442
- env = env.bind(x, $__rdl_nil_type) if (not (env.has_key? x)) # see lvasgn
483
+ env = env.bind(x, RDL::Globals.types[:nil]) if (not (env.has_key? x)) # see lvasgn
443
484
  # Note don't need to check outer_env here because will be checked by tc_vasgn below
444
485
  }
445
486
  envi, tright = tc(scope, env, e.children[1])
@@ -471,7 +512,7 @@ module RDL::Typecheck
471
512
  }
472
513
  [envi, tright]
473
514
  end
474
- elsif (tright.is_a? RDL::Type::GenericType) && (tright.base == $__rdl_array_type)
515
+ elsif (tright.is_a? RDL::Type::GenericType) && (tright.base == RDL::Globals.types[:array])
475
516
  tasgn = tright.params[0]
476
517
  lhs.each { |asgn|
477
518
  if asgn.type == :splat
@@ -489,16 +530,27 @@ module RDL::Typecheck
489
530
  # (op-asgn (send recv meth) :op operand)
490
531
  meth = e.children[0].children[1]
491
532
  envleft, trecv = tc(scope, env, e.children[0].children[0]) # recv
492
- tloperand = tc_send(scope, envleft, trecv, meth, [], nil, e.children[0]) # call recv.meth()
533
+ elargs = e.children[0].children[2]
534
+
535
+ if elargs
536
+ envleft, elargs = tc(scope, envleft, elargs)
537
+ largs = [elargs]
538
+ else
539
+ largs = []
540
+ end
541
+
542
+ tloperand = tc_send(scope, envleft, trecv, meth, largs, nil, e.children[0]) # call recv.meth()
493
543
  envoperand, troperand = tc(scope, envleft, e.children[2]) # operand
494
544
  tright = tc_send(scope, envoperand, tloperand, e.children[1], [troperand], nil, e) # recv.meth().op(operand)
545
+
546
+ tright = largs.push(tright) if largs
495
547
  mutation_meth = (meth.to_s + '=').to_sym
496
- tres = tc_send(scope, envoperand, trecv, mutation_meth, [tright], nil, e) # call recv.meth=(recv.meth().op(operand))
548
+ tres = tc_send(scope, envoperand, trecv, mutation_meth, tright, nil, e) # call recv.meth=(recvt.meth().op(operand))
497
549
  [envoperand, tres]
498
550
  else
499
551
  # (op-asgn (Xvasgn var-name) :op operand)
500
552
  x = e.children[0].children[0] # Note don't need to check outer_env here because will be checked by tc_vasgn below
501
- env = env.bind(x, $__rdl_nil_type) if ((e.children[0].type == :lvasgn) && (not (env.has_key? x))) # see :lvasgn
553
+ env = env.bind(x, RDL::Globals.types[:nil]) if ((e.children[0].type == :lvasgn) && (not (env.has_key? x))) # see :lvasgn
502
554
  envi, trecv = tc_var(scope, env, @@asgn_to_var[e.children[0].type], x, e.children[0]) # var being assigned to
503
555
  envright, tright = tc(scope, envi, e.children[2]) # operand
504
556
  trhs = tc_send(scope, envright, trecv, e.children[1], [tright], nil, e)
@@ -513,7 +565,7 @@ module RDL::Typecheck
513
565
  envright, tright = tc(scope, envleft, e.children[1]) # operand
514
566
  else
515
567
  x = e.children[0].children[0] # Note don't need to check outer_env here because will be checked by tc_var below
516
- env = env.bind(x, $__rdl_nil_type) if ((e.children[0].type == :lvasgn) && (not (env.has_key? x))) # see :lvasgn
568
+ env = env.bind(x, RDL::Globals.types[:nil]) if ((e.children[0].type == :lvasgn) && (not (env.has_key? x))) # see :lvasgn
517
569
  envleft, tleft = tc_var(scope, env, @@asgn_to_var[e.children[0].type], x, e.children[0]) # var being assigned to
518
570
  envright, tright = tc(scope, envleft, e.children[1])
519
571
  end
@@ -534,20 +586,51 @@ module RDL::Typecheck
534
586
  tc_vasgn(scope, envi, e.children[0].type, x, trhs, e)
535
587
  end
536
588
  when :nth_ref, :back_ref
537
- [env, $__rdl_string_type]
589
+ [env, RDL::Globals.types[:string]]
538
590
  when :const
539
591
  c = nil
540
592
  if e.children[0].nil?
541
- c = env[:self].klass.const_get(e.children[1])
593
+ case env[:self]
594
+ when RDL::Type::SingletonType
595
+ sclass = env[:self].val
596
+ when RDL::Type::NominalType
597
+ sclass = env[:self].klass
598
+ else
599
+ raise Exception, "unsupported env[self]=#{env[:self]}"
600
+ end
601
+ c1_str = RDL::Util.to_class_str(e.children[1])
602
+ self_klass_str = RDL::Util.to_class_str(sclass)
603
+ if self_klass_str.end_with?('::' + c1_str)
604
+ i = self_klass_str.rindex('::' + c1_str)
605
+ pc = RDL::Util.to_class self_klass_str[0..i-1]
606
+ c = pc.const_get(e.children[1])
607
+ else
608
+ if self_klass_str['::']
609
+ i = self_klass_str.rindex('::')
610
+ sclass = RDL::Util.to_class self_klass_str[0..i-1]
611
+ end
612
+ c = sclass.const_get(e.children[1])
613
+ end
542
614
  elsif e.children[0].type == :cbase
543
615
  raise "const cbase not implemented yet" # TODO!
544
616
  elsif e.children[0].type == :lvar
545
617
  raise "const lvar not implemented yet" # TODO!
618
+ elsif e.children[0].type == :const
619
+ if env[:self]
620
+ if env[:self].is_a?(RDL::Type::SingletonType)
621
+ ic = env[:self].val
622
+ else
623
+ ic = env[:self].class
624
+ end
625
+ else
626
+ ic = Object
627
+ end
628
+ c = get_leaves(e).inject(ic) {|m, c2| m.const_get(c2)}
546
629
  else
547
630
  raise "const other not implemented yet"
548
631
  end
549
632
  case c
550
- when TrueClass, FalseClass, Complex, Rational, Fixnum, Bignum, Float, Symbol, Class
633
+ when TrueClass, FalseClass, Complex, Rational, Integer, Float, Symbol, Class
551
634
  [env, RDL::Type::SingletonType.new(c)]
552
635
  when Module
553
636
  t = RDL::Type::SingletonType.new(const_get(e.children[1]))
@@ -557,24 +640,25 @@ module RDL::Typecheck
557
640
  end
558
641
  when :defined?
559
642
  # do not type check subexpression, since it may not be type correct, e.g., undefined variable
560
- [env, $__rdl_string_type]
643
+ [env, RDL::Globals.types[:string]]
561
644
  when :send, :csend
562
645
  # children[0] = receiver; if nil, receiver is self
563
646
  # children[1] = method name, a symbol
564
647
  # children [2..] = actual args
565
- return tc_var_type(scope, env, e) if e.children[1] == :var_type && e.children[0].nil?
566
- return tc_type_cast(scope, env, e) if e.children[1] == :type_cast && scope[:block].nil?
567
- return tc_note_type(scope, env, e) if e.children[1] == :rdl_note_type && e.children[0].nil?
648
+ return tc_var_type(scope, env, e) if (e.children[0].nil? || is_RDL(e.children[0])) && e.children[1] == :var_type
649
+ return tc_type_cast(scope, env, e) if is_RDL(e.children[0]) && e.children[1] == :type_cast && scope[:block].nil?
650
+ return tc_note_type(scope, env, e) if is_RDL(e.children[0]) && e.children[1] == :rdl_note_type
651
+ return tc_instantiate!(scope, env, e) if is_RDL(e.children[0]) && e.children[1] == :instantiate!
568
652
  envi = env
569
653
  tactuals = []
570
654
  block = scope[:block]
571
- scope_merge(scope, block: nil) { |sscope|
655
+ scope_merge(scope, block: nil, break: env, next: env) { |sscope|
572
656
  e.children[2..-1].each { |ei|
573
657
  if ei.type == :splat
574
658
  envi, ti = tc(sscope, envi, ei.children[0])
575
659
  if ti.is_a? RDL::Type::TupleType
576
660
  tactuals.concat ti.params
577
- elsif ti.is_a?(RDL::Type::GenericType) && ti.base == $__rdl_array_type
661
+ elsif ti.is_a?(RDL::Type::GenericType) && ti.base == RDL::Globals.types[:array]
578
662
  tactuals << RDL::Type::VarargType.new(ti.params[0]) # Turn Array<t> into *t
579
663
  else
580
664
  error :cant_splat, [ti], ei.children[0]
@@ -631,15 +715,15 @@ RUBY
631
715
  # when :not # in latest Ruby, not is a method call that could be redefined, so can't count on its behavior
632
716
  # a1, t1 = tc(scope, a, e.children[0])
633
717
  # if t1.is_a? RDL::Type::SingletonType
634
- # if t1.val then [a1, $__rdl_false_type] else [a1, $__rdl_true_type] end
718
+ # if t1.val then [a1, RDL::Globals.types[:false]] else [a1, RDL::Globals.types[:true]] end
635
719
  # else
636
- # [a1, $__rdl_bool_type]
720
+ # [a1, RDL::Globals.types[:bool]]
637
721
  # end
638
722
  when :if
639
723
  envi, tguard = tc(scope, env, e.children[0]) # guard; any type allowed
640
724
  # always type check both sides
641
- envleft, tleft = if e.children[1].nil? then [envi, $__rdl_nil_type] else tc(scope, envi, e.children[1]) end # then
642
- envright, tright = if e.children[2].nil? then [envi, $__rdl_nil_type] else tc(scope, envi, e.children[2]) end # else
725
+ envleft, tleft = if e.children[1].nil? then [envi, RDL::Globals.types[:nil]] else tc(scope, envi, e.children[1]) end # then
726
+ envright, tright = if e.children[2].nil? then [envi, RDL::Globals.types[:nil]] else tc(scope, envi, e.children[2]) end # else
643
727
  if tguard.is_a? RDL::Type::SingletonType
644
728
  if tguard.val then [envleft, tleft] else [envright, tright] end
645
729
  else
@@ -685,7 +769,13 @@ RUBY
685
769
  # previous, unrefined type
686
770
  end
687
771
  end
688
- envbody, tbody = tc(scope, initial_env, wclause.children[-1]) # last wclause child is body
772
+ if wclause.children[-1] == nil
773
+ envbody = initial_env
774
+ tbody = RDL::Globals.types[:nil]
775
+ else
776
+ envbody, tbody = tc(scope, initial_env, wclause.children[-1]) # last wclause child is body
777
+ end
778
+
689
779
  tbodies << tbody
690
780
  envbodies << envbody
691
781
  }
@@ -705,7 +795,7 @@ RUBY
705
795
  # retry: not allowed
706
796
  # redo: after loop guard, which is same as break
707
797
  env_break, _ = tc(scope, env, e.children[0]) # guard can have any type, may exit after checking guard
708
- scope_merge(scope, break: env_break, tbreak: $__rdl_nil_type, next: env, redo: env_break) { |lscope|
798
+ scope_merge(scope, break: env_break, tbreak: RDL::Globals.types[:nil], next: env, redo: env_break) { |lscope|
709
799
  begin
710
800
  old_break = lscope[:break]
711
801
  old_next = lscope[:next]
@@ -724,7 +814,7 @@ RUBY
724
814
  # next: before loop guard; argument not allowed
725
815
  # retry: not allowed
726
816
  # redo: beginning of body, which is same as after guard, i.e., same as break
727
- scope_merge(scope, break: nil, tbreak: $__rdl_nil_type, next: nil, redo: nil) { |lscope|
817
+ scope_merge(scope, break: nil, tbreak: RDL::Globals.types[:nil], next: nil, redo: nil) { |lscope|
728
818
  if e.children[1]
729
819
  env_body, _ = tc(lscope, env, e.children[1])
730
820
  lscope[:next] = Env.join(e, lscope[:next], env_body)
@@ -807,12 +897,16 @@ RUBY
807
897
  scope[tkw_name] = RDL::Type::UnionType.new(scope[tkw_name], tkw)
808
898
  end
809
899
  scope[e.type] = Env.join(e, scope[e.type], env)
810
- [env, $__rdl_bot_type]
900
+ [env, RDL::Globals.types[:bot]]
811
901
  when :return
812
902
  # TODO return in lambda returns from lambda and not outer scope
813
- env1, t1 = tc(scope, env, e.children[0])
903
+ if e.children[0]
904
+ env1, t1 = tc(scope, env, e.children[0])
905
+ else
906
+ env1, t1 = [env, RDL::Globals.types[:nil]]
907
+ end
814
908
  error :bad_return_type, [t1.to_s, scope[:tret]], e unless t1 <= scope[:tret]
815
- [env1, $__rdl_bot_type] # return is a void value expression
909
+ [env1, RDL::Globals.types[:bot]] # return is a void value expression
816
910
  when :begin, :kwbegin # sequencing
817
911
  envi = env
818
912
  ti = nil
@@ -864,12 +958,68 @@ RUBY
864
958
  texns << RDL::Type::NominalType.new(texn.val)
865
959
  }
866
960
  else
867
- texns = [$__rdl_standard_error_type]
961
+ texns = [RDL::Globals.types[:standard_error]]
868
962
  end
869
963
  if e.children[1]
870
964
  envi, _ = tc_vasgn(scope, envi, :lvasgn, e.children[1].children[0], RDL::Type::UnionType.new(*texns), e.children[1])
871
965
  end
872
966
  tc(scope, envi, e.children[2])
967
+ when :super
968
+ envi = env
969
+ tactuals = []
970
+ block = scope[:block]
971
+
972
+ if block
973
+ raise Exception, 'block in super method with block not supported'
974
+ end
975
+
976
+ scope_merge(scope, block: nil, break: env, next: env) { |sscope|
977
+ e.children.each { |ei|
978
+ if ei.type == :splat
979
+ envi, ti = tc(sscope, envi, ei.children[0])
980
+ if ti.is_a? RDL::Type::TupleType
981
+ tactuals.concat ti.params
982
+ elsif ti.is_a?(RDL::Type::GenericType) && ti.base == $__rdl_array_type
983
+ tactuals << RDL::Type::VarargType.new(ti.params[0]) # Turn Array<t> into *t
984
+ else
985
+ error :cant_splat, [ti], ei.children[0]
986
+ end
987
+ elsif ei.type == :block_pass
988
+ raise RuntimeError, "impossible to pass block arg and literal block" if scope[:block]
989
+ envi, ti = tc(sscope, envi, ei.children[0])
990
+ # convert using to_proc if necessary
991
+ ti = tc_send(sscope, envi, ti, :to_proc, [], nil, ei) unless ti.is_a? RDL::Type::MethodType
992
+ block = [ti, ei]
993
+ else
994
+ envi, ti = tc(sscope, envi, ei)
995
+ tactuals << ti
996
+ end
997
+ }
998
+
999
+ trecv = get_super_owner(envi[:self], @cur_meth[1])
1000
+ [envi, tc_send(sscope, envi, trecv, @cur_meth[1], tactuals, block, e).canonical]
1001
+ }
1002
+ when :zsuper
1003
+ envi = env
1004
+ block = scope[:block]
1005
+
1006
+ if block
1007
+ raise Exception, 'super method not supported'
1008
+ end
1009
+
1010
+ klass = RDL::Util.to_class @cur_meth[0]
1011
+ mname = @cur_meth[1]
1012
+ sklass = get_super_owner_from_class klass, mname
1013
+ sklass_str = RDL::Util.to_class_str sklass
1014
+ stype = RDL::Globals.info.get_with_aliases(sklass_str, mname, :type)
1015
+ error :no_instance_method_type, [sklass_str, mname], e unless stype
1016
+ raise Exception, "unsupported intersection type in super, e = #{e}" if stype.size > 1
1017
+ tactuals = stype[0].args
1018
+
1019
+ scope_merge(scope, block: nil, break: env, next: env) { |sscope|
1020
+ trecv = get_super_owner(envi[:self], @cur_meth[1])
1021
+ [envi, tc_send(sscope, envi, trecv, @cur_meth[1], tactuals, block, e).canonical]
1022
+ }
873
1023
  else
874
1024
  raise RuntimeError, "Expression kind #{e.type} unsupported"
875
1025
  end
@@ -890,13 +1040,13 @@ RUBY
890
1040
  end
891
1041
  when :ivar, :cvar, :gvar
892
1042
  klass = (if kind == :gvar then RDL::Util::GLOBAL_NAME else env[:self] end)
893
- unless $__rdl_info.has?(klass, name, :type)
1043
+ unless RDL::Globals.info.has?(klass, name, :type)
894
1044
  kind_text = (if kind == :ivar then "instance"
895
1045
  elsif kind == :cvar then "class"
896
1046
  else "global" end)
897
- error :untyped_var, [kind_text, name], e
1047
+ error :untyped_var, [kind_text, name, klass], e
898
1048
  end
899
- [env, $__rdl_info.get(klass, name, :type).canonical]
1049
+ [env, RDL::Globals.info.get(klass, name, :type).canonical]
900
1050
  else
901
1051
  raise RuntimeError, "unknown kind #{kind}"
902
1052
  end
@@ -919,13 +1069,13 @@ RUBY
919
1069
  end
920
1070
  when :ivasgn, :cvasgn, :gvasgn
921
1071
  klass = (if kind == :gvasgn then RDL::Util::GLOBAL_NAME else env[:self] end)
922
- unless $__rdl_info.has?(klass, name, :type)
1072
+ unless RDL::Globals.info.has?(klass, name, :type)
923
1073
  kind_text = (if kind == :ivasgn then "instance"
924
1074
  elsif kind == :cvasgn then "class"
925
1075
  else "global" end)
926
- error :untyped_var, [kind_text, name], e
1076
+ error :untyped_var, [kind_text, name, klass], e
927
1077
  end
928
- tleft = $__rdl_info.get(klass, name, :type)
1078
+ tleft = RDL::Globals.info.get(klass, name, :type)
929
1079
  error :vasgn_incompat, [tright.to_s, tleft.to_s], e unless tright <= tleft
930
1080
  [env, tright.canonical]
931
1081
  when :send
@@ -955,24 +1105,24 @@ RUBY
955
1105
  typ_str = e.children[3].children[0] if (e.children[3].type == :str) || (e.children[3].type == :string)
956
1106
  error :var_type_format, [], e.children[3] if typ_str.nil?
957
1107
  begin
958
- typ = $__rdl_parser.scan_str("#T " + typ_str)
1108
+ typ = RDL::Globals.parser.scan_str("#T " + typ_str)
959
1109
  rescue Racc::ParseError => err
960
1110
  error :generic_error, [err.to_s[1..-1]], e.children[3] # remove initial newline
961
1111
  end
962
- [env.fix(var, typ), $__rdl_nil_type]
1112
+ [env.fix(var, typ), RDL::Globals.types[:nil]]
963
1113
  end
964
1114
 
965
1115
  def self.tc_type_cast(scope, env, e)
966
- error :type_cast_format, [], e unless e.children.length <= 4
967
- typ_str = e.children[2].children[0] if (e.children[2].type == :str) || (e.children[2].type == :string)
968
- error :type_cast_format, [], e.children[2] if typ_str.nil?
1116
+ error :type_cast_format, [], e unless e.children.length <= 5
1117
+ typ_str = e.children[3].children[0] if (e.children[3].type == :str) || (e.children[3].type == :string)
1118
+ error :type_cast_format, [], e.children[3] if typ_str.nil?
969
1119
  begin
970
- typ = $__rdl_parser.scan_str("#T " + typ_str)
1120
+ typ = RDL::Globals.parser.scan_str("#T " + typ_str)
971
1121
  rescue Racc::ParseError => err
972
- error :generic_error, [err.to_s[1..-1]], e.children[2] # remove initial newline
1122
+ error :generic_error, [err.to_s[1..-1]], e.children[3] # remove initial newline
973
1123
  end
974
- if e.children[3]
975
- fh = e.children[3]
1124
+ if e.children[4]
1125
+ fh = e.children[4]
976
1126
  error :type_cast_format, [], fh unless fh.type == :hash && fh.children.length == 1
977
1127
  pair = fh.children[0]
978
1128
  error :type_cast_format, [], fh unless pair.type == :pair && pair.children[0].type == :sym && pair.children[0].children[0] == :force
@@ -983,12 +1133,66 @@ RUBY
983
1133
  end
984
1134
 
985
1135
  def self.tc_note_type(scope, env, e)
986
- error :note_type_format, [], e unless e.children.length == 3 && scope[:block].nil?
987
- env, typ = tc(scope, env, e.children[2])
988
- note :note_type, [typ], e.children[2]
1136
+ error :note_type_format, [], e unless e.children.length == 4 && scope[:block].nil?
1137
+ env, typ = tc(scope, env, e.children[3])
1138
+ note :note_type, [typ], e.children[3]
989
1139
  [env, typ]
990
1140
  end
991
1141
 
1142
+ def self.tc_instantiate!(scope, env, e)
1143
+ error :instantiate_format, [], e if e.children.length < 4
1144
+ env, obj_typ = tc(scope, env, e.children[2])
1145
+ case obj_typ
1146
+ when RDL::Type::GenericType
1147
+ klass = obj_typ.base.name.to_s
1148
+ when RDL::Type::NominalType
1149
+ klass = obj_typ.name.to_s
1150
+ when RDL::Type::TupleType
1151
+ klass = "Array"
1152
+ when RDL::Type::FiniteHashType
1153
+ klass = "Hash"
1154
+ when RDL::Type::SingletonType
1155
+ klass = if obj_typ.val.is_a?(Class) then obj_typ.val.to_s else obj_typ.val.class.to_s end
1156
+ else
1157
+ error :bad_inst_type, [obj_typ], e
1158
+ end
1159
+
1160
+ formals, _, _ = RDL::Globals.type_params[klass]
1161
+
1162
+ if e.children.last.type == :hash
1163
+ typ_args = e.children[3..-2]
1164
+ else
1165
+ typ_args = e.children[3..-1]
1166
+ end
1167
+ error :inst_not_param, [klass], e unless formals
1168
+ error :inst_num_args, [formals.size, typ_args.size], e unless formals.size == typ_args.size
1169
+
1170
+ new_typs = []
1171
+ typ_args.each { |a|
1172
+ env, arg_typ = tc(scope, env, a)
1173
+ case arg_typ
1174
+ when RDL::Type::SingletonType
1175
+ error :instantiate_format, [], a unless arg_typ.val.is_a?(Class)
1176
+ new_typs << RDL::Globals.parser.scan_str("#T #{arg_typ.val}")
1177
+ else
1178
+ error :instantiate_format, [], a unless (a.type == :str) || (a.type == :string) || (a.type == :sym)
1179
+ new_typs << RDL::Globals.parser.scan_str("#T #{a.children[0]}")
1180
+ end
1181
+ }
1182
+
1183
+ t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs)
1184
+ case e.children[2].type
1185
+ when :lvar
1186
+ var_name = e.children[2].children[0]
1187
+ else
1188
+ raise RuntimeError, "instantiate! expects local variable as receiver"
1189
+ error :inst_lvar, [], e
1190
+ end
1191
+
1192
+ env = env.bind(var_name, t)
1193
+ [env, t]
1194
+ end
1195
+
992
1196
  # Type check a send
993
1197
  # [+ scope +] is the scope; used only for checking block arguments
994
1198
  # [+ env +] is the environment; used only for checking block arguments.
@@ -1016,14 +1220,24 @@ RUBY
1016
1220
  # Like tc_send but trecv should never be a union type
1017
1221
  # Returns array of possible return types, or throws exception if there are none
1018
1222
  def self.tc_send_one_recv(scope, env, trecv, meth, tactuals, block, e)
1223
+ return tc_send_class(trecv, e) if (meth == :class) && (tactuals.empty?)
1019
1224
  tmeth_inter = [] # Array<MethodType>, i.e., an intersection types
1020
1225
  case trecv
1021
1226
  when RDL::Type::SingletonType
1022
1227
  if trecv.val.is_a? Class or trecv.val.is_a? Module
1023
- ts = lookup(scope, RDL::Util.add_singleton_marker(trecv.val.to_s), meth, e)
1228
+ if meth == :new then
1229
+ meth_lookup = :initialize
1230
+ trecv_lookup = trecv.val.to_s
1231
+ self_inst = RDL::Type::NominalType.new(trecv.val)
1232
+ else
1233
+ meth_lookup = meth
1234
+ trecv_lookup = RDL::Util.add_singleton_marker(trecv.val.to_s)
1235
+ self_inst = trecv
1236
+ end
1237
+ ts = lookup(scope, trecv_lookup, meth_lookup, e)
1024
1238
  ts = [RDL::Type::MethodType.new([], nil, RDL::Type::NominalType.new(trecv.val))] if (meth == :new) && (ts.nil?) # there's always a nullary new if initialize is undefined
1025
1239
  error :no_singleton_method_type, [trecv.val, meth], e unless ts
1026
- inst = {self: trecv}
1240
+ inst = {self: self_inst}
1027
1241
  tmeth_inter = ts.map { |t| t.instantiate(inst) }
1028
1242
  elsif trecv.val.is_a?(Symbol) && meth == :to_proc
1029
1243
  # Symbol#to_proc on a singleton symbol type produces a Proc for the method of the same name
@@ -1064,10 +1278,10 @@ RUBY
1064
1278
  tmeth_inter = [trecv]
1065
1279
  else
1066
1280
  # treat as Proc
1067
- tc_send_one_recv(scope, env, $__rdl_proc_type, meth, tactuals, block, e)
1281
+ tc_send_one_recv(scope, env, RDL::Globals.types[:proc], meth, tactuals, block, e)
1068
1282
  end
1069
1283
  else
1070
- raise RuntimeError, "receiver type #{trecv} not supported yet"
1284
+ raise RuntimeError, "receiver type #{trecv} not supported yet, meth=#{meth}"
1071
1285
  end
1072
1286
 
1073
1287
  trets = [] # all possible return types
@@ -1082,7 +1296,19 @@ RUBY
1082
1296
  tmeth_inst = tc_arg_types(tmeth, tactuals_expanded)
1083
1297
  if tmeth_inst
1084
1298
  tc_block(scope, env, tmeth.block, block, tmeth_inst) if block
1085
- trets_tmp << tmeth.ret.instantiate(tmeth_inst) # found a match for this subunion; add its return type to trets_tmp
1299
+ if trecv.is_a?(RDL::Type::SingletonType) && meth == :new
1300
+ init_typ = RDL::Type::NominalType.new(trecv.val)
1301
+ if (tmeth.ret.instance_of?(RDL::Type::GenericType))
1302
+ error :bad_initialize_type, [], e unless (tmeth.ret.base == init_typ)
1303
+ elsif (tmeth.ret.instance_of?(RDL::Type::AnnotatedArgType) || tmeth.ret.instance_of?(RDL::Type::DependentArgType))
1304
+ error :bad_initialize_type, [], e unless (tmeth.ret.type == init_typ)
1305
+ else
1306
+ error :bad_initialize_type, [], e unless (tmeth.ret == init_typ)
1307
+ end
1308
+ trets_tmp << init_typ
1309
+ else
1310
+ trets_tmp << tmeth.ret.instantiate(tmeth_inst) # found a match for this subunion; add its return type to trets_tmp
1311
+ end
1086
1312
  end
1087
1313
  end
1088
1314
  }
@@ -1119,6 +1345,33 @@ RUBY
1119
1345
  return trets
1120
1346
  end
1121
1347
 
1348
+ def self.tc_send_class(trecv, e)
1349
+ case trecv
1350
+ when RDL::Type::SingletonType
1351
+ if trecv.val.is_a? Class
1352
+ [RDL::Type::SingletonType.new(Class)]
1353
+ elsif trecv.val.is_a? Module
1354
+ [RDL::Type::SingletonType.new(Module)]
1355
+ else
1356
+ [RDL::Type::SingletonType.new(trecv.val.class)]
1357
+ end
1358
+ when RDL::Type::NominalType
1359
+ [RDL::Type::SingletonType.new(trecv.klass)]
1360
+ when RDL::Type::GenericType
1361
+ [RDL::Type::SingletonType.new(trecv.base.klass)]
1362
+ when RDL::Type::TupleType
1363
+ [RDL::Type::SingletonType.new(Array)]
1364
+ when RDL::Type::FiniteHashType
1365
+ [RDL::Type::SingletonType.new(Hash)]
1366
+ when RDL::Type::VarType
1367
+ error :recv_var_type, [trecv], e
1368
+ when RDL::Type::MethodType
1369
+ [RDL::Type::SingletonType.new(Proc)]
1370
+ else
1371
+ raise RuntimeError, "Unexpected receiver type #{trecv}"
1372
+ end
1373
+ end
1374
+
1122
1375
  # [+ tmeth +] is MethodType
1123
1376
  # [+ actuals +] is Array<Type> containing the actual argument types
1124
1377
  # return instiation (possibly empty) that makes actuals match method type (if any), nil otherwise
@@ -1194,7 +1447,7 @@ RUBY
1194
1447
  scope_merge(scope, outer_env: env) { |bscope|
1195
1448
  # note: okay if outer_env shadows, since nested scope will include outer scope by next line
1196
1449
  env = env.merge(Env.new(targs))
1197
- _, body_type = if body.nil? then [nil, $__rdl_nil_type] else tc(bscope, env.merge(Env.new(targs)), body) end
1450
+ _, body_type = if body.nil? then [nil, RDL::Globals.types[:nil]] else tc(bscope, env.merge(Env.new(targs)), body) end
1198
1451
  error :bad_return_type, [body_type, tblock.ret], body unless body.nil? || RDL::Type::Type.leq(body_type, tblock.ret, inst, false)
1199
1452
  #
1200
1453
  }
@@ -1223,7 +1476,7 @@ RUBY
1223
1476
  return t if k == klass && m = name
1224
1477
  }
1225
1478
  end
1226
- t = $__rdl_info.get_with_aliases(klass, name, :type)
1479
+ t = RDL::Globals.info.get_with_aliases(klass, name, :type)
1227
1480
  return t if t # simplest case, no need to walk inheritance hierarchy
1228
1481
  the_klass = RDL::Util.to_class(klass)
1229
1482
  is_singleton = RDL::Util.has_singleton_marker(the_klass.to_s)
@@ -1234,11 +1487,11 @@ RUBY
1234
1487
  next if (ancestor.instance_of? Module) && (included.member? ancestor) && is_singleton
1235
1488
  # extended (i.e., not included) modules' instance methods get added as singleton methods, so can't be in class
1236
1489
  next if (ancestor.instance_of? Module) && (not (included.member? ancestor)) && (not is_singleton)
1237
- tancestor = $__rdl_info.get_with_aliases(ancestor.to_s, name, :type)
1490
+ tancestor = RDL::Globals.info.get_with_aliases(ancestor.to_s, name, :type)
1238
1491
  return tancestor if tancestor
1239
1492
  # special caes: Kernel's singleton methods are *also* added when included?!
1240
1493
  if ancestor == Kernel
1241
- tancestor = $__rdl_info.get_with_aliases(RDL::Util.add_singleton_marker('Kernel'), name, :type)
1494
+ tancestor = RDL::Globals.info.get_with_aliases(RDL::Util.add_singleton_marker('Kernel'), name, :type)
1242
1495
  return tancestor if tancestor
1243
1496
  end
1244
1497
  if ancestor.instance_methods(false).member?(name)
@@ -1255,56 +1508,66 @@ RUBY
1255
1508
  end
1256
1509
  end
1257
1510
 
1258
- # Modify Parser::MESSAGES so can use the awesome parser diagnostics printing!
1259
- type_error_messages = {
1260
- bad_return_type: "got type `%s' where return type `%s' expected",
1261
- undefined_local_or_method: "undefined local variable or method `%s'",
1262
- nonmatching_range_type: "attempt to construct range with non-matching types `%s' and `%s'",
1263
- no_instance_method_type: "no type information for instance method `%s#%s'",
1264
- no_singleton_method_type: "no type information for class/singleton method `%s.%s'",
1265
- arg_type_single_receiver_error: "argument type error for instance method `%s#%s'\n%s",
1266
- untyped_var: "no type for %s variable `%s'",
1267
- vasgn_incompat: "incompatible types: `%s' can't be assigned to variable of type `%s'",
1268
- inconsistent_var_type: "local variable `%s' has declared type on some paths but not all",
1269
- inconsistent_var_type_type: "local variable `%s' declared with inconsistent types %s",
1270
- no_each_type: "can't find `each' method with signature `() { (t1) -> t2 } -> t3' in class `%s'",
1271
- tuple_finite_hash_promote: "can't promote `%s' to `%s'",
1272
- masgn_bad_rhs: "multiple assignment has right-hand side of type `%s' where tuple or array expected",
1273
- masgn_num: "can't multiple-assign %d values to %d variables",
1274
- masgn_bad_lhs: "no corresponding right-hand side elemnt for left-hand side assignee",
1275
- kw_not_allowed: "can't use `%s' in current scope",
1276
- kw_arg_not_allowed: "argument to `%s' not allowed in current scope",
1277
- no_block: "attempt to call yield in method not declared to take a block argument",
1278
- block_block: "can't call yield on a block expecting another block argument",
1279
- block_type_error: "argument type error for block\n%s",
1280
- missing_ancestor_type: "ancestor `%s' of `%s' has method `%s' but no type for it",
1281
- type_cast_format: "type_cast must be called as `type_cast type-string' or `type_cast type-string, force: expr'",
1282
- var_type_format: "var_type must be called as `var_type :var-name, type-string'",
1283
- puts_type_format: "puts_type must be called as `puts_type e'",
1284
- generic_error: "%s",
1285
- exn_type: "can't determine exception type",
1286
- cant_splat: "can't type splat with element of type `%s'",
1287
- for_collection: "can't type for with collection of type `%s'",
1288
- note_type: "Type is `%s'",
1289
- note_message: "%s",
1290
- recv_var_type: "receiver whose type is unconstrained variable `%s' not allowed",
1291
- type_args_more: "%s type accepts more arguments than actual %s definition",
1292
- type_args_fewer: "%s type accepts fewer arguments than actual %s definition",
1293
- type_arg_kind_mismatch: "%s type has %s argument but actual argument is %s",
1294
- type_args_no_kws: "%s type does not expect keyword arguments but actual expects keywords",
1295
- type_args_no_kw: "%s type does not expect keyword argument `%s'",
1296
- type_args_kw_mismatch: "%s type has %s keyword `%s' but actual argument is %s",
1297
- type_args_kw_more: "%s type expects keywords `%s' that are not expected by actual %s",
1298
- type_args_no_kw_rest: "%s type has no rest keyword but actual method accepts rest keywords",
1299
- type_args_kw_rest: "%s type has rest keyword but actual method does not accept rest keywords",
1300
- optional_default_type: "default value has type `%s' where type `%s' expected",
1301
- optional_default_kw_type: "default value for `%s' has type `%s' where type `%s' expected",
1302
- type_arg_block: "%s type does not expect block but actual %s takes block",
1303
- bad_block_arg_type: "block argument has type `%s' but expecting type `%s'",
1304
- non_block_block_arg: "block argument should have a block type but instead has type `%s'",
1305
- proc_block_arg_type: "block argument is a Proc; can't tell if it matches expected type `%s'",
1306
- no_type_for_symbol: "can't find type for method corresponding to `%s.to_proc'",
1307
- }
1308
- old_messages = Parser::MESSAGES
1309
- Parser.send(:remove_const, :MESSAGES)
1310
- Parser.const_set :MESSAGES, (old_messages.merge(type_error_messages))
1511
+ # Use parser's Diagnostic to output RDL typechecker error messages
1512
+ class Diagnostic < Parser::Diagnostic
1513
+
1514
+ def message
1515
+ RDL_MESSAGES[@reason] % @arguments
1516
+ end
1517
+
1518
+ RDL_MESSAGES = {
1519
+ bad_return_type: "got type `%s' where return type `%s' expected",
1520
+ bad_inst_type: "instantiate! called on object of type `%s' where Generic Type was expected",
1521
+ inst_not_param: "instantiate! receiver is of class `%s' which is not parameterized",
1522
+ inst_num_args: "instantiate! expecting `%s' type parameters, got `%s' parameters",
1523
+ inst_lvar: "instantiate! expects local variable as receiver",
1524
+ bad_initialize_type: 'initialize method must always be annotated to return type "self" or a GenericType where the base is "self"',
1525
+ undefined_local_or_method: "undefined local variable or method `%s'",
1526
+ nonmatching_range_type: "attempt to construct range with non-matching types `%s' and `%s'",
1527
+ no_instance_method_type: "no type information for instance method `%s#%s'",
1528
+ no_singleton_method_type: "no type information for class/singleton method `%s.%s'",
1529
+ arg_type_single_receiver_error: "argument type error for instance method `%s#%s'\n%s",
1530
+ untyped_var: "no type for %s variable `%s' in class %s",
1531
+ vasgn_incompat: "incompatible types: `%s' can't be assigned to variable of type `%s'",
1532
+ inconsistent_var_type: "local variable `%s' has declared type on some paths but not all",
1533
+ inconsistent_var_type_type: "local variable `%s' declared with inconsistent types %s",
1534
+ no_each_type: "can't find `each' method with signature `() { (t1) -> t2 } -> t3' in class `%s'",
1535
+ tuple_finite_hash_promote: "can't promote `%s' to `%s'",
1536
+ masgn_bad_rhs: "multiple assignment has right-hand side of type `%s' where tuple or array expected",
1537
+ masgn_num: "can't multiple-assign %d values to %d variables",
1538
+ masgn_bad_lhs: "no corresponding right-hand side elemnt for left-hand side assignee",
1539
+ kw_not_allowed: "can't use `%s' in current scope",
1540
+ kw_arg_not_allowed: "argument to `%s' not allowed in current scope",
1541
+ no_block: "attempt to call yield in method not declared to take a block argument",
1542
+ block_block: "can't call yield on a block expecting another block argument",
1543
+ block_type_error: "argument type error for block\n%s",
1544
+ missing_ancestor_type: "ancestor `%s' of `%s' has method `%s' but no type for it",
1545
+ type_cast_format: "type_cast must be called as `type_cast obj, type-string' or `type_cast obj, type-string, force: expr'",
1546
+ instantiate_format: "instantiate! must be called as `instantiate! type*' or `instantiate! type*, check: bool' where type is a string, symbol, or class for static type checking.",
1547
+ var_type_format: "var_type must be called as `var_type :var-name, type-string'",
1548
+ puts_type_format: "puts_type must be called as `puts_type e'",
1549
+ generic_error: "%s",
1550
+ exn_type: "can't determine exception type",
1551
+ cant_splat: "can't type splat with element of type `%s'",
1552
+ for_collection: "can't type for with collection of type `%s'",
1553
+ note_type: "Type is `%s'",
1554
+ note_message: "%s",
1555
+ recv_var_type: "receiver whose type is unconstrained variable `%s' not allowed",
1556
+ type_args_more: "%s type accepts more arguments than actual %s definition",
1557
+ type_args_fewer: "%s type accepts fewer arguments than actual %s definition",
1558
+ type_arg_kind_mismatch: "%s type has %s argument but actual argument is %s",
1559
+ type_args_no_kws: "%s type does not expect keyword arguments but actual expects keywords",
1560
+ type_args_no_kw: "%s type does not expect keyword argument `%s'",
1561
+ type_args_kw_mismatch: "%s type has %s keyword `%s' but actual argument is %s",
1562
+ type_args_kw_more: "%s type expects keywords `%s' that are not expected by actual %s",
1563
+ type_args_no_kw_rest: "%s type has no rest keyword but actual method accepts rest keywords",
1564
+ type_args_kw_rest: "%s type has rest keyword but actual method does not accept rest keywords",
1565
+ optional_default_type: "default value has type `%s' where type `%s' expected",
1566
+ optional_default_kw_type: "default value for `%s' has type `%s' where type `%s' expected",
1567
+ type_arg_block: "%s type does not expect block but actual %s takes block",
1568
+ bad_block_arg_type: "block argument has type `%s' but expecting type `%s'",
1569
+ non_block_block_arg: "block argument should have a block type but instead has type `%s'",
1570
+ proc_block_arg_type: "block argument is a Proc; can't tell if it matches expected type `%s'",
1571
+ no_type_for_symbol: "can't find type for method corresponding to `%s.to_proc'",
1572
+ }
1573
+ end