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
@@ -59,6 +59,7 @@ module RDL::Type
59
59
  other = other.canonical
60
60
  other = other.type if other.instance_of? AnnotatedArgType
61
61
  return true if other.instance_of? WildQuery
62
+ return false unless other.instance_of? StructuralType
62
63
  return (@methods.length == other.methods.length &&
63
64
  @methods.all? { |k, v| (other.methods.has_key? k) && (v.match(other.methods[k]))})
64
65
  end
@@ -41,12 +41,12 @@ module RDL::Type
41
41
  other = other.canonical
42
42
  other = other.type if other.instance_of? AnnotatedArgType
43
43
  return true if other.instance_of? WildQuery
44
- return @params.length == other.params.length && @params.zip(other.params).all? { |t,o| t.match(o) }
44
+ return (other.instance_of? TupleType) && (@params.length == other.params.length) && (@params.zip(other.params).all? { |t,o| t.match(o) })
45
45
  end
46
46
 
47
47
  def promote!
48
48
  return false if @cant_promote
49
- @array = GenericType.new($__rdl_array_type, UnionType.new(*@params))
49
+ @array = GenericType.new(RDL::Globals.types[:array], UnionType.new(*@params))
50
50
  # note since we promoted this, lbounds and ubounds will be ignored in future constraints, which
51
51
  # is good because otherwise we'd get infinite loops
52
52
  return (@lbounds.all? { |lbound| lbound <= self }) && (@ubounds.all? { |ubound| self <= ubound })
@@ -75,7 +75,7 @@ module RDL::Type
75
75
  if left.is_a?(NominalType) && right.is_a?(StructuralType)
76
76
  right.methods.each_pair { |m, t|
77
77
  return false unless left.klass.method_defined? m
78
- types = $__rdl_info.get(left.klass, m, :type)
78
+ types = RDL::Globals.info.get(left.klass, m, :type)
79
79
  if types
80
80
  return false unless types.all? { |tlm| leq(tlm, t, nil, ileft) }
81
81
  # inst above is nil because the method types inside the class and
@@ -94,7 +94,7 @@ module RDL::Type
94
94
 
95
95
  # generic
96
96
  if left.is_a?(GenericType) && right.is_a?(GenericType)
97
- formals, variance, _ = $__rdl_type_params[left.base.name]
97
+ formals, variance, _ = RDL::Globals.type_params[left.base.name]
98
98
  # do check here to avoid hiding errors if generic type written
99
99
  # with wrong number of parameters but never checked against
100
100
  # instantiated instances
@@ -115,13 +115,13 @@ module RDL::Type
115
115
  end
116
116
  if left.is_a?(GenericType) && right.is_a?(StructuralType)
117
117
  # similar to logic above for leq(NominalType, StructuralType, ...)
118
- formals, variance, _ = $__rdl_type_params[left.base.name]
118
+ formals, variance, _ = RDL::Globals.type_params[left.base.name]
119
119
  raise TypeError, "No type parameters defined for #{base.name}" unless formals
120
120
  base_inst = Hash[*formals.zip(left.params).flatten] # instantiation for methods in base's class
121
121
  klass = left.base.klass
122
122
  right.methods.each_pair { |meth, t|
123
123
  return false unless klass.method_defined? meth
124
- types = $__rdl_info.get(klass, meth, :type)
124
+ types = RDL::Globals.info.get(klass, meth, :type)
125
125
  if types
126
126
  return false unless types.all? { |tlm| leq(tlm.instantiate(base_inst), t, nil, ileft) }
127
127
  end
@@ -166,7 +166,7 @@ module RDL::Type
166
166
  right.lbounds << left
167
167
  return true
168
168
  end
169
- if left.is_a?(TupleType) && right.is_a?(GenericType) && right.base == $__rdl_array_type
169
+ if left.is_a?(TupleType) && right.is_a?(GenericType) && right.base == RDL::Globals.types[:array]
170
170
  # TODO !ileft and right carries a free variable
171
171
  return false unless left.promote!
172
172
  return leq(left, right, inst, ileft) # recheck for promoted type
@@ -200,7 +200,7 @@ module RDL::Type
200
200
  right.lbounds << left
201
201
  return true
202
202
  end
203
- if left.is_a?(FiniteHashType) && right.is_a?(GenericType) && right.base == $__rdl_hash_type
203
+ if left.is_a?(FiniteHashType) && right.is_a?(GenericType) && right.base == RDL::Globals.types[:hash]
204
204
  # TODO !ileft and right carries a free variable
205
205
  return false unless left.promote!
206
206
  return leq(left, right, inst, ileft) # recheck for promoted type
@@ -237,8 +237,8 @@ module RDL::Type
237
237
 
238
238
  private
239
239
 
240
- # [+ a +] is Array<Fixnum>
241
- # returns Array<Array<Fixnum>> containing all combinations of 0..a[i] at index i
240
+ # [+ a +] is Array<Integer>
241
+ # returns Array<Array<Integer>> containing all combinations of 0..a[i] at index i
242
242
  # For example:
243
243
  #
244
244
  # combinations [0, 0] #=> [[0, 0]]
@@ -13,7 +13,7 @@ module RDL
13
13
  if current_types.size == 1
14
14
  current_types.to_a[0]
15
15
  elsif current_types.size == 0
16
- $__rdl_nil_type
16
+ RDL::Globals.types[:nil]
17
17
  else
18
18
  RDL::Type::UnionType.new(*self.unify_param_types(current_types))
19
19
  end
@@ -7,7 +7,7 @@ module RDL::Type
7
7
  end
8
8
 
9
9
  def self.new(*types)
10
- return $__rdl_nil_type if types.size == 0
10
+ return RDL::Globals.types[:bot] if types.size == 0
11
11
  ts = []
12
12
  # flatten nested unions, check that all args are types
13
13
  types.each { |t|
@@ -80,6 +80,7 @@ module RDL::Type
80
80
  other = other.canonical
81
81
  other = other.type if other.instance_of? AnnotatedArgType
82
82
  return true if other.instance_of? WildQuery
83
+ return false unless other.instance_of? UnionType
83
84
  return false if @types.length != other.types.length
84
85
  @types.all? { |t| other.types.any? { |ot| t.match(ot) } }
85
86
  end
@@ -15,6 +15,21 @@ class RDL::Util
15
15
  return c
16
16
  end
17
17
 
18
+ def self.singleton_class_to_class(cls)
19
+ cls_str = cls.to_s
20
+ cls_str = cls_str.split('(')[0] + '>' if cls_str['(']
21
+ to_class cls_str[8..-2]
22
+ end
23
+
24
+ def self.to_class_str(cls)
25
+ cls_str = cls.to_s
26
+ if cls_str.start_with? '#<Class:'
27
+ cls_str = cls_str.split('(')[0] + '>' if cls_str['(']
28
+ cls_str = RDL::Util.add_singleton_marker(cls_str[8..-2])
29
+ end
30
+ cls_str
31
+ end
32
+
18
33
  def self.has_singleton_marker(klass)
19
34
  return (klass =~ /^#{SINGLETON_MARKER_REGEXP}/)
20
35
  end
@@ -43,12 +58,22 @@ class RDL::Util
43
58
 
44
59
  def self.method_defined?(klass, method)
45
60
  begin
46
- (self.to_class klass).method_defined?(method.to_sym) ||
47
- (self.to_class klass).private_instance_methods.include?(method.to_sym) ||
48
- (self.to_class klass).protected_instance_methods.include?(method.to_sym)
61
+ sk = self.to_class klass
62
+ msym = method.to_sym
63
+ mstr = method.to_s
64
+ sk.instance_method msym
49
65
  rescue NameError
50
66
  return false
51
67
  end
68
+ klass_str = RDL::Util.to_class_str(klass).hash
69
+ if mstr.start_with?('__rdl') and mstr.end_with?('_old_#{klass_str}')
70
+ mstr0 = RDL::Wrap.unwrapped_name(klass, mstr)
71
+ owner0 = sk.instance_method(mstr0).owner
72
+ owner = sk.instance_method(mstr).owner
73
+ return false if owner0 != owner
74
+ end
75
+
76
+ true
52
77
  end
53
78
 
54
79
  # Returns the @__rdl_type field of [+obj+]
@@ -6,18 +6,18 @@ class RDL::Wrap
6
6
  def self.resolve_alias(klass, meth)
7
7
  klass = klass.to_s
8
8
  meth = meth.to_sym
9
- while $__rdl_aliases[klass] && $__rdl_aliases[klass][meth]
10
- if $__rdl_info.has_any?(klass, meth, [:pre, :post, :type])
9
+ while RDL::Globals.aliases[klass] && RDL::Globals.aliases[klass][meth]
10
+ if RDL::Globals.info.has_any?(klass, meth, [:pre, :post, :type])
11
11
  raise RuntimeError, "Alias #{RDL::Util.pp_klass_method(klass, meth)} has contracts. Contracts are only allowed on methods, not aliases."
12
12
  end
13
- meth = $__rdl_aliases[klass][meth]
13
+ meth = RDL::Globals.aliases[klass][meth]
14
14
  end
15
15
  return meth
16
16
  end
17
17
 
18
18
  def self.get_type_params(klass)
19
19
  klass = klass.to_s
20
- $__rdl_type_params[klass]
20
+ RDL::Globals.type_params[klass]
21
21
  end
22
22
 
23
23
  # [+klass+] may be a Class, String, or Symbol
@@ -26,11 +26,11 @@ class RDL::Wrap
26
26
  # Wraps klass#method to check contracts and types. Does not rewrap
27
27
  # if already wrapped. Also records source location of method.
28
28
  def self.wrap(klass_str, meth)
29
- $__rdl_wrap_switch.off {
29
+ RDL::Globals.wrap_switch.off {
30
30
  klass_str = klass_str.to_s
31
31
  klass = RDL::Util.to_class klass_str
32
32
  return if wrapped? klass, meth
33
- return if RDL::Config.instance.nowrap.member? klass
33
+ return if RDL::Config.instance.nowrap.member? klass_str.to_sym
34
34
  raise ArgumentError, "Attempt to wrap #{RDL::Util.pp_klass_method(klass, meth)}" if klass.to_s =~ /^RDL::/
35
35
  meth_old = wrapped_name(klass, meth) # meth_old is a symbol
36
36
  # return if (klass.method_defined? meth_old) # now checked above by wrapped? call
@@ -46,32 +46,32 @@ class RDL::Wrap
46
46
  bind = binding
47
47
  inst = nil
48
48
 
49
- $__rdl_wrap_switch.off {
50
- $__rdl_wrapped_calls["#{full_method_name}"] += 1 if RDL::Config.instance.gather_stats
49
+ RDL::Globals.wrap_switch.off {
50
+ RDL::Globals.wrapped_calls["#{full_method_name}"] += 1 if RDL::Config.instance.gather_stats
51
51
  inst = nil
52
- inst = @__rdl_inst if defined? @__rdl_inst
53
- inst = Hash[$__rdl_type_params[klass][0].zip []] if (not(inst) && $__rdl_type_params[klass])
52
+ inst = @__rdl_type.to_inst if ((defined? @__rdl_type) && @__rdl_type.is_a?(RDL::Type::GenericType))
53
+ inst = Hash[RDL::Globals.type_params[klass][0].zip []] if (not(inst) && RDL::Globals.type_params[klass])
54
54
  inst = {} if not inst
55
55
  #{if not(is_singleton_method) then "inst[:self] = RDL::Type::NominalType.new(self.class)" end}
56
56
  # puts "Intercepted #{full_method_name}(\#{args.join(", ")}) { \#{blk} }, inst = \#{inst.inspect}"
57
57
  meth = RDL::Wrap.resolve_alias(klass, #{meth.inspect})
58
- RDL::Typecheck.typecheck(klass, meth) if $__rdl_info.get(klass, meth, :typecheck) == :call
59
- pres = $__rdl_info.get(klass, meth, :pre)
58
+ RDL::Typecheck.typecheck(klass, meth) if RDL::Globals.info.get(klass, meth, :typecheck) == :call
59
+ pres = RDL::Globals.info.get(klass, meth, :pre)
60
60
  RDL::Contract::AndContract.check_array(pres, self, *args, &blk) if pres
61
- types = $__rdl_info.get(klass, meth, :type)
61
+ types = RDL::Globals.info.get(klass, meth, :type)
62
62
  if types
63
63
  matches, args, blk, bind = RDL::Type::MethodType.check_arg_types("#{full_method_name}", self, bind, types, inst, *args, &blk)
64
64
  end
65
65
  }
66
66
  ret = send(#{meth_old.inspect}, *args, &blk)
67
- $__rdl_wrap_switch.off {
68
- posts = $__rdl_info.get(klass, meth, :post)
67
+ RDL::Globals.wrap_switch.off {
68
+ posts = RDL::Globals.info.get(klass, meth, :post)
69
69
  RDL::Contract::AndContract.check_array(posts, self, ret, *args, &blk) if posts
70
70
  if matches
71
71
  ret = RDL::Type::MethodType.check_ret_types(self, "#{full_method_name}", types, inst, matches, ret, bind, *args, &blk)
72
72
  end
73
73
  if RDL::Config.instance.guess_types.include?("#{klass_str_without_singleton}".to_sym)
74
- $__rdl_info.add(klass, meth, :otype, { args: (args.map { |arg| arg.class }), ret: ret.class, block: block_given? })
74
+ RDL::Globals.info.add(klass, meth, :otype, { args: (args.map { |arg| arg.class }), ret: ret.class, block: block_given? })
75
75
  end
76
76
  return ret
77
77
  }
@@ -112,7 +112,7 @@ RUBY
112
112
  klass = default_class.to_s
113
113
  contract = RDL::Contract::FlatContract.new(name, &blk)
114
114
  else
115
- raise ArgumentError, "Invalid arguments"
115
+ raise ArgumentError, "Invalid arguments to `pre` or `post`"
116
116
  end
117
117
  raise ArgumentError, "#{contract.class} received where Contract expected" unless contract.class < RDL::Contract::Contract
118
118
  # meth = :initialize if meth && meth.to_sym == :new # actually wrap constructor
@@ -136,7 +136,7 @@ RUBY
136
136
  klass = default_class.to_s
137
137
  type = type_to_type args[0]
138
138
  else
139
- raise ArgumentError, "Invalid arguments"
139
+ raise ArgumentError, "Invalid arguments to `type`"
140
140
  end
141
141
  raise ArgumentError, "Excepting method type, got #{type.class} instead" if type.class != RDL::Type::MethodType
142
142
  # meth = :initialize if meth && slf && meth.to_sym == :new # actually wrap constructor
@@ -147,12 +147,22 @@ RUBY
147
147
  private
148
148
 
149
149
  def self.wrapped_name(klass, meth)
150
- "__rdl_#{meth.to_s}_old".to_sym
150
+ klass_str = RDL::Util.to_class_str(klass).hash
151
+ "__rdl_#{meth.to_s}_old_#{klass_str}".to_sym
152
+ end
153
+
154
+ def self.unwrapped_name(s)
155
+ if not s.start_with?('__rdl_') and s.include?('_old_')
156
+ raise Exception, "cannot get unwrapped name for #{s}"
157
+ end
158
+ klass_str = RDL::Util.to_class_str(klass).hash.to_s
159
+ s = klass_str.split("_#{klass_str}")
160
+ s[6..-5]
151
161
  end
152
162
 
153
163
  def self.class_to_string(klass)
154
164
  case klass
155
- when Class
165
+ when Class, Module
156
166
  return klass.to_s
157
167
  when String
158
168
  return klass
@@ -176,7 +186,7 @@ RUBY
176
186
  when RDL::Type::Type
177
187
  return type
178
188
  when String
179
- return $__rdl_parser.scan_str type
189
+ return RDL::Globals.parser.scan_str type
180
190
  end
181
191
  end
182
192
 
@@ -184,15 +194,15 @@ RUBY
184
194
  def self.do_method_added(the_self, sing, klass, meth)
185
195
  # Apply any deferred contracts and reset list
186
196
 
187
- if $__rdl_deferred.size > 0
197
+ if RDL::Globals.deferred.size > 0
188
198
  if sing
189
199
  loc = the_self.singleton_method(meth).source_location
190
200
  else
191
201
  loc = the_self.instance_method(meth).source_location
192
202
  end
193
- $__rdl_info.set(klass, meth, :source_location, loc)
194
- a = $__rdl_deferred
195
- $__rdl_deferred = [] # Reset before doing more work to avoid infinite recursion
203
+ RDL::Globals.info.set(klass, meth, :source_location, loc)
204
+ a = RDL::Globals.deferred
205
+ RDL::Globals.deferred = [] # Reset before doing more work to avoid infinite recursion
196
206
  a.each { |prev_klass, kind, contract, h|
197
207
  if RDL::Util.has_singleton_marker(klass)
198
208
  tmp_klass = RDL::Util.remove_singleton_marker(klass)
@@ -202,50 +212,51 @@ RUBY
202
212
  if (!h[:class_check] && (prev_klass != tmp_klass)) || (h[:class_check] && (h[:class_check].to_s != tmp_klass))
203
213
  raise RuntimeError, "Deferred #{kind} contract from class #{prev_klass} being applied in class #{tmp_klass} to #{meth}"
204
214
  end
205
- $__rdl_info.add(klass, meth, kind, contract)
215
+ RDL::Globals.info.add(klass, meth, kind, contract)
206
216
  RDL::Wrap.wrap(klass, meth) if h[:wrap]
207
- unless !h.has_key?(:typecheck) || $__rdl_info.set(klass, meth, :typecheck, h[:typecheck])
217
+ unless !h.has_key?(:typecheck) || RDL::Globals.info.set(klass, meth, :typecheck, h[:typecheck])
208
218
  raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}"
209
219
  end
210
220
  RDL::Typecheck.typecheck(klass, meth) if h[:typecheck] == :now
211
221
  if (h[:typecheck] && h[:typecheck] != :call)
212
- $__rdl_to_typecheck[h[:typecheck]] = Set.new unless $__rdl_to_typecheck[h[:typecheck]]
213
- $__rdl_to_typecheck[h[:typecheck]].add([klass, meth])
222
+ RDL::Globals.to_typecheck[h[:typecheck]] = Set.new unless RDL::Globals.to_typecheck[h[:typecheck]]
223
+ RDL::Globals.to_typecheck[h[:typecheck]].add([klass, meth])
214
224
  end
215
225
  }
216
226
  end
217
227
 
218
228
  # Wrap method if there was a prior contract for it.
219
- if $__rdl_to_wrap.member? [klass, meth]
220
- $__rdl_to_wrap.delete [klass, meth]
221
- RDL::Wrap.wrap(klass, meth)
229
+ if RDL::Globals.to_wrap.member? [klass, meth]
230
+ RDL::Globals.to_wrap.delete [klass, meth]
222
231
  if sing
223
232
  loc = the_self.singleton_method(meth).source_location
224
233
  else
225
234
  loc = the_self.instance_method(meth).source_location
226
235
  end
227
- $__rdl_info.set(klass, meth, :source_location, loc)
236
+ RDL::Globals.info.set(klass, meth, :source_location, loc)
237
+ RDL::Wrap.wrap(klass, meth)
228
238
  end
229
239
 
230
240
  # Type check method if requested
231
- if $__rdl_to_typecheck[:now].member? [klass, meth]
232
- $__rdl_to_typecheck[:now].delete [klass, meth]
241
+ if RDL::Globals.to_typecheck[:now].member? [klass, meth]
242
+ RDL::Globals.to_typecheck[:now].delete [klass, meth]
233
243
  RDL::Typecheck.typecheck(klass, meth)
234
244
  end
235
245
 
236
- if RDL::Config.instance.guess_types.include?(the_self.to_s.to_sym) && !$__rdl_info.has?(klass, meth, :type)
246
+ if RDL::Config.instance.guess_types.include?(the_self.to_s.to_sym) && !RDL::Globals.info.has?(klass, meth, :type)
237
247
  # Added a method with no type annotation from a class we want to guess types for
238
248
  RDL::Wrap.wrap(klass, meth)
239
249
  end
240
250
  end
241
251
  end
242
252
 
243
- class Object
244
-
253
+ module RDL::Annotate
245
254
  # [+klass+] may be Class, Symbol, or String
246
255
  # [+method+] may be Symbol or String
247
256
  # [+contract+] must be a Contract
248
257
  # [+wrap+] indicates whether the contract should be enforced (true) or just recorded (false)
258
+ # [+ version +] is a rubygems version requirement string (or array of such requirement strings)
259
+ # if the current Ruby version does not satisfy the version, the type call will be ignored
249
260
  #
250
261
  # Add a precondition to a method. Possible invocations:
251
262
  # pre(klass, meth, contract)
@@ -254,37 +265,39 @@ class Object
254
265
  # pre(meth) { block } = pre(self, meth, FlatContract.new { block })
255
266
  # pre(contract) = pre(self, next method, contract)
256
267
  # pre { block } = pre(self, next method, FlatContract.new { block })
257
- def pre(*args, wrap: RDL::Config.instance.pre_defaults[:wrap], &blk)
268
+ def pre(*args, wrap: RDL::Config.instance.pre_defaults[:wrap], version: nil, &blk)
269
+ return if version && !(Gem::Requirement.new(version).satisfied_by? Gem.ruby_version)
258
270
  klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Precondition", *args, &blk)
259
271
  if meth
260
- $__rdl_info.add(klass, meth, :pre, contract)
272
+ RDL::Globals.info.add(klass, meth, :pre, contract)
261
273
  if wrap
262
274
  if RDL::Util.method_defined?(klass, meth) || meth == :initialize # there is always an initialize
263
275
  RDL::Wrap.wrap(klass, meth)
264
276
  else
265
- $__rdl_to_wrap << [klass, meth]
277
+ RDL::Globals.to_wrap << [klass, meth]
266
278
  end
267
279
  end
268
280
  else
269
- $__rdl_deferred << [klass, :pre, contract, {wrap: wrap}]
281
+ RDL::Globals.deferred << [klass, :pre, contract, {wrap: wrap}]
270
282
  end
271
283
  nil
272
284
  end
273
285
 
274
286
  # Add a postcondition to a method. Same possible invocations as pre.
275
- def post(*args, wrap: RDL::Config.instance.post_defaults[:wrap], &blk)
287
+ def post(*args, wrap: RDL::Config.instance.post_defaults[:wrap], version: nil, &blk)
288
+ return if version && !(Gem::Requirement.new(version).satisfied_by? Gem.ruby_version)
276
289
  klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Postcondition", *args, &blk)
277
290
  if meth
278
- $__rdl_info.add(klass, meth, :post, contract)
291
+ RDL::Globals.info.add(klass, meth, :post, contract)
279
292
  if wrap
280
293
  if RDL::Util.method_defined?(klass, meth) || meth == :initialize
281
294
  RDL::Wrap.wrap(klass, meth)
282
295
  else
283
- $__rdl_to_wrap << [klass, meth]
296
+ RDL::Globals.to_wrap << [klass, meth]
284
297
  end
285
298
  end
286
299
  else
287
- $__rdl_deferred << [klass, :post, contract, {wrap: wrap}]
300
+ RDL::Globals.deferred << [klass, :post, contract, {wrap: wrap}]
288
301
  end
289
302
  nil
290
303
  end
@@ -297,12 +310,15 @@ class Object
297
310
  # if :call, indicates method should be typechecked when called
298
311
  # if :now, indicates method should be typechecked immediately
299
312
  # if other-symbol, indicates method should be typechecked when rdl_do_typecheck(other-symbol) is called
313
+ # [+ version +] is a rubygems version requirement string (or array of such requirement strings)
314
+ # if the current Ruby version does not satisfy the version, the type call will be ignored
300
315
  #
301
316
  # Set a method's type. Possible invocations:
302
317
  # type(klass, meth, type)
303
318
  # type(meth, type)
304
319
  # type(type)
305
- def type(*args, wrap: RDL::Config.instance.type_defaults[:wrap], typecheck: RDL::Config.instance.type_defaults[:typecheck])
320
+ def type(*args, wrap: RDL::Config.instance.type_defaults[:wrap], typecheck: RDL::Config.instance.type_defaults[:typecheck], version: nil)
321
+ return if version && !(Gem::Requirement.new(version).satisfied_by? Gem.ruby_version)
306
322
  klass, meth, type = begin
307
323
  RDL::Wrap.process_type_args(self, *args)
308
324
  rescue Racc::ParseError => err
@@ -310,37 +326,42 @@ class Object
310
326
  # Warning: Adjust the -5 below if the code (or this comment) changes
311
327
  bt = err.backtrace
312
328
  bt.shift until bt[0] =~ /^#{__FILE__}:#{__LINE__-5}/
313
- bt.shift # remove $__rdl_contract_switch.off call
329
+ bt.shift # remove RDL::Globals.contract_switch.off call
314
330
  bt.shift # remove type call itself
315
331
  err.set_backtrace bt
316
332
  raise err
317
333
  end
318
334
  if meth
319
335
  # It turns out Ruby core/stdlib don't always follow this convention...
320
- # if (meth.to_s[-1] == "?") && (type.ret != $__rdl_type_bool)
336
+ # if (meth.to_s[-1] == "?") && (type.ret != RDL::Globals.types[:bool])
321
337
  # warn "#{RDL::Util.pp_klass_method(klass, meth)}: methods that end in ? should have return type %bool"
322
338
  # end
323
- $__rdl_info.add(klass, meth, :type, type)
324
- unless $__rdl_info.set(klass, meth, :typecheck, typecheck)
339
+ RDL::Globals.info.add(klass, meth, :type, type)
340
+ unless RDL::Globals.info.set(klass, meth, :typecheck, typecheck)
325
341
  raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}"
326
342
  end
327
- if wrap || typecheck == :now
343
+ if wrap || typecheck
328
344
  if RDL::Util.method_defined?(klass, meth) || meth == :initialize
329
- $__rdl_info.set(klass, meth, :source_location, RDL::Util.to_class(klass).instance_method(meth).source_location)
330
- RDL::Typecheck.typecheck(klass, meth) if typecheck == :now
345
+ RDL::Globals.info.set(klass, meth, :source_location, RDL::Util.to_class(klass).instance_method(meth).source_location)
346
+ if typecheck == :now
347
+ RDL::Typecheck.typecheck(klass, meth)
348
+ elsif typecheck && (typecheck != :call)
349
+ RDL::Globals.to_typecheck[typecheck] = Set.new unless RDL::Globals.to_typecheck[typecheck]
350
+ RDL::Globals.to_typecheck[typecheck].add([klass, meth])
351
+ end
331
352
  RDL::Wrap.wrap(klass, meth) if wrap
332
353
  else
333
354
  if wrap
334
- $__rdl_to_wrap << [klass, meth]
355
+ RDL::Globals.to_wrap << [klass, meth]
335
356
  if (typecheck && typecheck != :call)
336
- $__rdl_to_typecheck[typecheck] = Set.new unless $__rdl_to_typecheck[typecheck]
337
- $__rdl_to_typecheck[typecheck].add([klass, meth])
357
+ RDL::Globals.to_typecheck[typecheck] = Set.new unless RDL::Globals.to_typecheck[typecheck]
358
+ RDL::Globals.to_typecheck[typecheck].add([klass, meth])
338
359
  end
339
360
  end
340
361
  end
341
362
  end
342
363
  else
343
- $__rdl_deferred << [klass, :type, type, {wrap: wrap,
364
+ RDL::Globals.deferred << [klass, :type, type, {wrap: wrap,
344
365
  typecheck: typecheck}]
345
366
  end
346
367
  nil
@@ -354,7 +375,7 @@ class Object
354
375
  return if var.to_s =~ /^[a-z]/ # local variables handled specially, inside type checker
355
376
  raise RuntimeError, "Global variables can't be typed in a class" unless klass = self
356
377
  klass = RDL::Util::GLOBAL_NAME if var.to_s =~ /^\$/
357
- unless $__rdl_info.set(klass, var, :type, $__rdl_parser.scan_str("#T #{typ}"))
378
+ unless RDL::Globals.info.set(klass, var, :type, RDL::Globals.parser.scan_str("#T #{typ}"))
358
379
  raise RuntimeError, "Type already declared for #{var}"
359
380
  end
360
381
  nil
@@ -394,42 +415,28 @@ class Object
394
415
  nil
395
416
  end
396
417
 
397
- def self.method_added(meth)
398
- klass = self.to_s
399
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
400
- RDL::Wrap.do_method_added(self, false, klass, meth)
401
- nil
402
- end
403
-
404
- def self.singleton_method_added(meth)
405
- klass = self.to_s
406
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
407
- sklass = RDL::Util.add_singleton_marker(klass)
408
- RDL::Wrap.do_method_added(self, true, sklass, meth)
409
- nil
410
- end
411
-
412
418
  # Aliases contracts for meth_old and meth_new. Currently, this must
413
419
  # be called for any aliases or they will not be wrapped with
414
420
  # contracts. Only creates aliases in the current class.
415
- def rdl_alias(new_name, old_name)
416
- klass = self.to_s
421
+ def rdl_alias(klass=self, new_name, old_name)
422
+ klass = klass.to_s
417
423
  klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
418
- $__rdl_aliases[klass] = {} unless $__rdl_aliases[klass]
419
- if $__rdl_aliases[klass][new_name]
424
+ RDL::Globals.aliases[klass] = {} unless RDL::Globals.aliases[klass]
425
+ if RDL::Globals.aliases[klass][new_name]
420
426
  raise RuntimeError,
421
- "Tried to alias #{new_name}, already aliased to #{$__rdl_aliases[klass][new_name]}"
427
+ "Tried to alias #{new_name}, already aliased to #{RDL::Globals.aliases[klass][new_name]}"
422
428
  end
423
- $__rdl_aliases[klass][new_name] = old_name
429
+ RDL::Globals.aliases[klass][new_name] = old_name
424
430
 
425
- if self.method_defined? new_name
431
+ if Module.const_defined?(klass) && RDL::Util.to_class(klass).method_defined?(new_name)
426
432
  RDL::Wrap.wrap(klass, new_name)
427
433
  else
428
- $__rdl_to_wrap << [klass, old_name]
434
+ RDL::Globals.to_wrap << [klass, old_name]
429
435
  end
430
436
  nil
431
437
  end
432
438
 
439
+ # [+ klass +] is the class whose type parameters to set; self if omitted
433
440
  # [+params+] is an array of symbols or strings that are the
434
441
  # parameters of this (generic) type
435
442
  # [+variance+] is an array of the corresponding variances, :+ for
@@ -442,12 +449,12 @@ class Object
442
449
  # block will be passed an array typs corresponding to the type
443
450
  # parameters of the class, and the block should return true if and
444
451
  # only if self is a member of self.class<typs>.
445
- def type_params(params, all, variance: nil, &blk)
452
+ def type_params(klass=self, params, all, variance: nil, &blk)
446
453
  raise RuntimeError, "Empty type parameters not allowed" if params.empty?
447
- klass = self.to_s
448
454
  klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
449
- if $__rdl_type_params[klass]
450
- raise RuntimeError, "#{klass} already has type parameters #{$__rdl_type_params[klass]}"
455
+ klass = klass.to_s
456
+ if RDL::Globals.type_params[klass]
457
+ raise RuntimeError, "#{klass} already has type parameters #{RDL::Globals.type_params[klass]}"
451
458
  end
452
459
  params = params.map { |v|
453
460
  raise RuntimeError, "Type parameter #{v.inspect} is not symbol or string" unless v.class == String || v.class == Symbol
@@ -461,123 +468,167 @@ class Object
461
468
  chk = all || blk
462
469
  raise RuntimeError, "At least one of {all, blk} required" unless chk
463
470
  variance = params.map { |p| :~ } unless variance # default to invariant
464
- $__rdl_type_params[klass] = [params, variance, chk]
465
- nil
466
- end
467
-
468
- def rdl_nowrap
469
- RDL.config { |config| config.add_nowrap(self, self.singleton_class) }
471
+ RDL::Globals.type_params[klass] = [params, variance, chk]
470
472
  nil
471
473
  end
472
474
 
473
- # [+typs+] is an array of types, classes, symbols, or strings to instantiate
474
- # the type parameters. If a class, symbol, or string is given, it is
475
- # converted to a NominalType.
476
- def instantiate!(*typs)
477
- klass = self.class.to_s
478
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
479
- formals, _, all = $__rdl_type_params[klass]
480
- raise RuntimeError, "Receiver is of class #{klass}, which is not parameterized" unless formals
481
- raise RuntimeError, "Expecting #{params.size} type parameters, got #{typs.size}" unless formals.size == typs.size
482
- raise RuntimeError, "Instance already has type instantiation" if (defined? @__rdl_type) && @rdl_type
483
- new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else $__rdl_parser.scan_str "#T #{t}" end }
484
- t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs)
485
- if all.instance_of? Symbol
486
- self.send(all) { |*objs|
487
- new_typs.zip(objs).each { |nt, obj|
488
- if nt.instance_of? RDL::Type::GenericType # require obj to be instantiated
489
- t_obj = RDL::Util.rdl_type(obj)
490
- raise RDL::Type::TypeError, "Expecting element of type #{nt.to_s}, but got uninstantiated object #{obj.inspect}" unless t_obj
491
- raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got type #{t_obj.to_s}" unless t_obj <= nt
492
- else
493
- raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got #{obj.inspect}" unless nt.member? obj
494
- end
495
- }
496
- }
497
- else
498
- raise RDL::Type::TypeError, "Not an instance of #{t}" unless instance_exec(*new_typs, &all)
499
- end
500
- @__rdl_type = t
501
- self
502
- end
475
+ # The following code attempts to warn about annotation methods already being defined on the class/module.
476
+ # But it doesn't work because `extended` gets called *after* the module's methods are already added...
477
+ # def self.extended(other)
478
+ # [:pre,
479
+ # :post,
480
+ # :type,
481
+ # :var_type,
482
+ # :attr_accessor_type,
483
+ # :attr_reader_type,
484
+ # :attr_type,
485
+ # :attr_writer_type,
486
+ # :rdl_alias,
487
+ # :type_params].each { |a|
488
+ # warn "RDL WARNING: #{other.to_s} extended RDL::Annotate but already has #{a} defined" if other.respond_to? a
489
+ # }
490
+ # end
491
+ end
503
492
 
504
- def deinstantiate!
505
- raise RuntimeError, "Class #{self.to_s} is not parameterized" unless $__rdl_type_params[klass]
506
- raise RuntimeError, "Instance is not instantiated" unless @__rdl_type && @@__rdl_type.instance_of?(RDL::Type::GenericType)
507
- @__rdl_type = nil
508
- self
509
- end
493
+ # all methods in RDL::Annotate but with an `rdl_` prefix
494
+ module RDL::RDLAnnotate
495
+ define_method :rdl_pre, RDL::Annotate.instance_method(:pre)
496
+ define_method :rdl_post, RDL::Annotate.instance_method(:post)
497
+ define_method :rdl_type, RDL::Annotate.instance_method(:type)
498
+ define_method :rdl_var_type, RDL::Annotate.instance_method(:var_type)
499
+ define_method :rdl_attr_accessor_type, RDL::Annotate.instance_method(:attr_accessor_type)
500
+ define_method :rdl_attr_reader_type, RDL::Annotate.instance_method(:attr_reader_type)
501
+ define_method :rdl_attr_type, RDL::Annotate.instance_method(:attr_type)
502
+ define_method :rdl_attr_writer_type, RDL::Annotate.instance_method(:attr_writer_type)
503
+ define_method :rdl_alias, RDL::Annotate.instance_method(:rdl_alias)
504
+ define_method :rdl_type_params, RDL::Annotate.instance_method(:type_params)
505
+ end
510
506
 
511
- # Returns a new object that wraps self in a type cast. If force is true this cast is *unchecked*, so use with caution
512
- def type_cast(typ, force: false)
513
- new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "#T #{typ}" end
514
- raise RuntimeError, "type cast error: self not a member of #{new_typ}" unless force || typ.member?(self)
515
- obj = SimpleDelegator.new(self)
516
- obj.instance_variable_set('@__rdl_type', new_typ)
517
- obj
518
- end
507
+ module RDL
508
+ extend RDL::Annotate
519
509
 
520
510
  # Add a new type alias.
521
511
  # [+name+] must be a string beginning with %.
522
512
  # [+typ+] can be either a string, in which case it will be parsed
523
513
  # into a type, or a Type.
524
- def type_alias(name, typ)
525
- raise RuntimeError, "Attempt to redefine type #{name}" if $__rdl_special_types[name]
514
+ def self.type_alias(name, typ)
515
+ raise RuntimeError, "Attempt to redefine type #{name}" if RDL::Globals.special_types[name]
526
516
  case typ
527
517
  when String
528
- t = $__rdl_parser.scan_str "#T #{typ}"
529
- $__rdl_special_types[name] = t
518
+ t = RDL::Globals.parser.scan_str "#T #{typ}"
519
+ RDL::Globals.special_types[name] = t
530
520
  when RDL::Type::Type
531
- $__rdl_special_types[name] = typ
521
+ RDL::Globals.special_types[name] = typ
532
522
  else
533
523
  raise RuntimeError, "Unexpected typ argument #{typ.inspect}"
534
524
  end
535
525
  nil
536
526
  end
537
527
 
528
+ def self.nowrap(klass=self)
529
+ RDL.config { |config| config.add_nowrap(klass) }
530
+ nil
531
+ end
532
+
538
533
  # Register [+ blk +] to be executed when `rdl_do_typecheck [+ sym +]` is called.
539
534
  # The blk will be called with sym as its argument. The order
540
535
  # in which multiple blks for the same sym will be executed is unspecified
541
- def rdl_at(sym, &blk)
542
- $__rdl_at[sym] = [] unless $__rdl_at[sym]
543
- $__rdl_at[sym] << blk
536
+ def self.at(sym, &blk)
537
+ RDL::Globals.to_do_at[sym] = [] unless RDL::Globals.to_do_at[sym]
538
+ RDL::Globals.to_do_at[sym] << blk
544
539
  end
545
540
 
546
541
  # Invokes all callbacks from rdl_at(sym), in unspecified order.
547
542
  # Afterwards, type checks all methods that had annotation `typecheck: sym' at type call, in unspecified order.
548
- def rdl_do_typecheck(sym)
549
- if $__rdl_at[sym]
550
- $__rdl_at[sym].each { |blk| blk.call(sym) }
543
+ def self.do_typecheck(sym)
544
+ if RDL::Globals.to_do_at[sym]
545
+ RDL::Globals.to_do_at[sym].each { |blk| blk.call(sym) }
551
546
  end
552
- $__rdl_at[sym] = Array.new
553
- return unless $__rdl_to_typecheck[sym]
554
- $__rdl_to_typecheck[sym].each { |klass, meth|
547
+ RDL::Globals.to_do_at[sym] = Array.new
548
+ return unless RDL::Globals.to_typecheck[sym]
549
+ RDL::Globals.to_typecheck[sym].each { |klass, meth|
555
550
  RDL::Typecheck.typecheck(klass, meth)
556
551
  }
557
- $__rdl_to_typecheck[sym] = Set.new
552
+ RDL::Globals.to_typecheck[sym] = Set.new
558
553
  nil
559
554
  end
560
555
 
561
556
  # Does nothing at run time
562
- def rdl_note_type(x)
557
+ def self.note_type(x)
563
558
  return x
564
559
  end
565
560
 
566
- def rdl_remove_type(klass, meth)
567
- raise RuntimeError, "No existing type for #{RDL::Util.pp_klass_method(klass, meth)}" unless $__rdl_info.has? klass, meth, :type
568
- $__rdl_info.remove klass, meth, :type
561
+ def self.remove_type(klass, meth)
562
+ raise RuntimeError, "No existing type for #{RDL::Util.pp_klass_method(klass, meth)}" unless RDL::Globals.info.has? klass, meth, :type
563
+ RDL::Globals.info.remove klass, meth, :type
569
564
  nil
570
565
  end
571
566
 
567
+ # Returns a new object that wraps self in a type cast. If force is true this cast is *unchecked*, so use with caution
568
+ def self.type_cast(obj, typ, force: false)
569
+ new_typ = if typ.is_a? RDL::Type::Type then typ else RDL::Globals.parser.scan_str "#T #{typ}" end
570
+ raise RuntimeError, "type cast error: self not a member of #{new_typ}" unless force || typ.member?(obj)
571
+ new_obj = SimpleDelegator.new(obj)
572
+ new_obj.instance_variable_set('@__rdl_type', new_typ)
573
+ new_obj
574
+ end
575
+
576
+ # [+typs+] is an array of types, classes, symbols, or strings to instantiate
577
+ # the type parameters. If a class, symbol, or string is given, it is
578
+ # converted to a NominalType.
579
+ def self.instantiate!(obj, *typs, check: false)
580
+ klass = obj.class.to_s
581
+ klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
582
+ formals, _, all = RDL::Globals.type_params[klass]
583
+ raise RuntimeError, "Receiver is of class #{klass}, which is not parameterized" unless formals
584
+ raise RuntimeError, "Expecting #{formals.size} type parameters, got #{typs.size}" unless formals.size == typs.size
585
+ raise RuntimeError, "Instance already has type instantiation" if obj.instance_variable_get(:@__rdl_type)
586
+ new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else RDL::Globals.parser.scan_str "#T #{t}" end }
587
+ t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs)
588
+ if check
589
+ if all.instance_of? Symbol
590
+ obj.send(all) { |*objs|
591
+ new_typs.zip(objs).each { |nt, o|
592
+ if nt.instance_of? RDL::Type::GenericType # require o to be instantiated
593
+ t_o = RDL::Util.rdl_type(o)
594
+ raise RDL::Type::TypeError, "Expecting element of type #{nt.to_s}, but got uninstantiated object #{o.inspect}" unless t_o
595
+ raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got type #{t_o.to_s}" unless t_o <= nt
596
+ else
597
+ raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got #{o.inspect}" unless nt.member? o
598
+ end
599
+ }
600
+ }
601
+ else
602
+ raise RDL::Type::TypeError, "Not an instance of #{t}" unless instance_exec(*new_typs, &all)
603
+ end
604
+ end
605
+ obj.instance_variable_set(:@__rdl_type, t)
606
+ obj
607
+ end
608
+
609
+ def self.deinstantiate!(obj)
610
+ klass = obj.class.to_s
611
+ klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
612
+ raise RuntimeError, "Class #{self.to_s} is not parameterized" unless RDL::Globals.type_params[klass]
613
+ raise RuntimeError, "Instance is not instantiated" unless obj.instance_variable_get(:@__rdl_type).instance_of?(RDL::Type::GenericType)
614
+ obj.instance_variable_set(:@__rdl_type, nil)
615
+ obj
616
+ end
572
617
  end
573
618
 
574
- # method_added for Object doesn't get called on module methods...bug?
575
- # class Module
576
- # def method_added(meth)
577
- # $__rdl_contract_switch.off {
578
- # klass = self.to_s
579
- # RDL::Wrap.do_method_added(self, false, klass, meth)
580
- # nil
581
- # }
582
- # end
583
- # end
619
+ class Module
620
+ def method_added(meth)
621
+ klass = self.to_s
622
+ klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
623
+ RDL::Wrap.do_method_added(self, false, klass, meth)
624
+ nil
625
+ end
626
+
627
+ def singleton_method_added(meth)
628
+ klass = self.to_s
629
+ klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
630
+ sklass = RDL::Util.add_singleton_marker(klass)
631
+ RDL::Wrap.do_method_added(self, true, sklass, meth)
632
+ nil
633
+ end
634
+ end