rdl 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a08748b1afa6ca7710e6bf7c31e1162aa034de66
4
- data.tar.gz: 104e8ede0573645fcd3c571000e402875ba94fa8
3
+ metadata.gz: aabf7af1d05594fdd962964b90285fa322cc9aef
4
+ data.tar.gz: 435dff6920f147343d71bf459fa8de1462358195
5
5
  SHA512:
6
- metadata.gz: 341fc4e02d341179c93cea2a94c4f60c451a3ff4b5f1b1d7fb7ff01218e5309182e0d421cdbe6eaae1d4d04b00a7dca26f9650d0f8fff55157cf256881a50241
7
- data.tar.gz: f38cd8208c3b22ef65ecc317521a28dc03a068b7425d875be9d8df91946a3f5b5caec55cf3940a9a871b76215251305effea50f2b8cf8a448d0f3e221bfde962
6
+ metadata.gz: 9ae6a8193a9589662d98b35ab30eec6836dcbd123317e7e820916728a8686b0b3e1d914f433d91a44c904468d763eac316bab00886441675246fc46e8ce410e3
7
+ data.tar.gz: b6503f4c82c45555249c85e08c4ae9d10dc287f62462c22cf36dfaa48d63d6a4151b27b747871024fc4b398ea280bb3584355a08dc0b097f11a0c346f08fc9fb
@@ -16,6 +16,19 @@ rvm:
16
16
  - 2.2.2
17
17
  - 2.2.3
18
18
  - 2.2.4
19
+ - 2.2.5
20
+ - 2.2.6
19
21
  - 2.3.0
20
22
  - 2.3.1
23
+ - 2.3.2
24
+ - 2.3.3
25
+ - 2.3.4
26
+ - 2.4.0
27
+ - 2.4.1
21
28
  sudo: false
29
+ notifications:
30
+ email:
31
+ recipients:
32
+ - rdl-devel@googlegroups.com
33
+ on_success: never # default: change
34
+ on_failure: always # default: always
data/CHANGES.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.1.0] - 2017-06-14
6
+
7
+ ### Fixed
8
+ - Type checking bug in const expressions when env[:self] is SingletonType
9
+ - Type for unary minus in numeric type files (changed :- to :-@)
10
+ - Type checking initialize method bugs
11
+ - Type checking of Module methods
12
+ - Type checking method when class name is included in type annotation
13
+ - Dynamic type checks after calls to instantiate!
14
+ - Ruby 2.4 compatibility!
15
+ - Various core and standard library types
16
+ - Parsing bug with `or`
17
+ - Sub-classes not wrapped bug
18
+ - Exception from case/when branch with empty body
19
+
20
+ ### Added
21
+ - Support operator assignment when left-hand side has method args
22
+ - Support nested class names
23
+ - Type for unary plus in numeric type files
24
+ - Support for instantiate! for binding type parameters during static type checking
25
+ - New "check" flag for calls to instantiate! indicating whether we want to check type of receiving object on call
26
+ - More precise static type checking for `Object#class` method
27
+ - Klass argument to rdl_nowrap, rdl_alias
28
+ - Some more support for Rails
29
+ - Support for next/break in block arguments
30
+ - Support for super in static analysis
31
+
32
+ ### Changed
33
+ - Global variables are now module variables of RDL::Globals
34
+ - at_exit handler only installed if `Config.report` or `.guess_types` are accessed
35
+ - Subclass Parser::Diagnostic instead of monkey patching it
36
+ - Replaced `Fixnum` with `Integer` in README (suggested by https://github.com/Dorian)
37
+ - All annotations removed from `Object` and added to `RDL::Annotate`
38
+ - `type_cast`, `instantiate!`, and `deinstantiate!` are now part of the `RDL` module to avoid adding them to `Object`
39
+
5
40
  ## [2.0.1] - 2016-11-11
6
41
 
7
42
  ### Fixed
data/README.md CHANGED
@@ -34,12 +34,13 @@
34
34
  * [Type Casts](#type-casts)
35
35
  * [Bottom Type (%bot)](#bottom-type-bot)
36
36
  * [Non-null Type](#non-null-type)
37
+ * [Constructor Type](#constructor-type)
37
38
  * [Static Type Checking](#static-type-checking)
38
39
  * [Types for Variables](#types-for-variables)
39
40
  * [Tuples, Finite Hashes, and Subtyping](#tuples-finite-hashes-and-subtyping)
40
41
  * [Other Features and Limitations](#other-features-and-limitations)
41
42
  * [Assumptions](#assumptions)
42
- * [Other RDL Methods](#other-rdl-methods)
43
+ * [RDL Method Reference](#rdl-method-reference)
43
44
  * [Performance](#performance)
44
45
  * [Queries](#queries)
45
46
  * [Configuration](#configuration)
@@ -54,20 +55,22 @@ RDL is a lightweight system for adding types, type checking, and contracts to Ru
54
55
 
55
56
  ```ruby
56
57
  require 'rdl'
58
+ extend RDL::Annotate # add annotation methods to current scope
57
59
 
58
- type '(Fixnum, Fixnum) -> String'
60
+ type '(Integer, Integer) -> String'
59
61
  def m(x,y) ... end
60
62
  ```
61
63
 
62
- This indicates that `m` returns a `String` if given two `Fixnum` arguments. When written as above, RDL enforces this type as a *contract* checked at run time: When `m` is called, RDL checks that `m` is given exactly two arguments and both are `Fixnums`, and that `m` returns an instance of `String`.
64
+ This indicates that `m` returns a `String` if given two `Integer` arguments. When written as above, RDL enforces this type as a *contract* checked at run time: When `m` is called, RDL checks that `m` is given exactly two arguments and both are `Integers`, and that `m` returns an instance of `String`.
63
65
 
64
66
  RDL can also *statically type check* method bodies against their signatures. For example:
65
67
 
66
68
  ```ruby
67
69
  file.rb:
68
70
  require 'rdl'
71
+ extend RDL::Annotate
69
72
 
70
- type '(Fixnum) -> Fixnum', typecheck: :now
73
+ type '(Integer) -> Integer', typecheck: :now
71
74
  def id(x)
72
75
  "forty-two"
73
76
  end
@@ -75,15 +78,22 @@ file.rb:
75
78
 
76
79
  ```
77
80
  $ ruby file.rb
78
- .../lib/rdl/typecheck.rb:32:in `error': (RDL::Typecheck::StaticTypeError)
79
- .../file.rb:5:5: error: got type `String' where return type `Fixnum' expected
80
- .../file.rb:5: "forty-two"
81
- .../file.rb:5: ^~~~~~~~~~~
81
+ .../lib/rdl/typecheck.rb:158:in `error': (RDL::Typecheck::StaticTypeError)
82
+ .../file.rb:6:3: error: got type `String' where return type `Integer' expected
83
+ .../file.rb:6: "forty-two"
84
+ .../file.rb:6: ^~~~~~~~~~~
82
85
  ```
83
86
 
84
- Passing `typecheck: :now` to `type` checks the method body immediately or as soon as it is defined. Passing `typecheck: :call` to `type` statically type checks the method body whenever it is called. Passing `typecheck: sym` for some other symbol statically type checks the method body when `rdl_do_typecheck sym` is called.
87
+ Passing `typecheck: :now` to `type` checks the method body immediately or as soon as it is defined. Passing `typecheck: :call` to `type` statically type checks the method body whenever it is called. Passing `typecheck: sym` for some other symbol statically type checks the method body when `RDL.do_typecheck sym` is called.
85
88
 
86
- Note that RDL tries to follow the philosophy that you get what you pay for. Methods with type annotations can be checked dynamically or statically; methods without type annotations are unaffected by RDL. See the [performance](#performance) discussion for more detail.
89
+ The `type` method can also be called with the class and method to be annotated, and it can also be invoked as `RDL.type` in case `extend RDL::Annotate` would cause namespace issues:
90
+
91
+ ```
92
+ type :A, :id, '(Integer) -> Integer', typecheck: :now # Add a type annotation for A#id.
93
+ RDL.type :A, :id, '(Integer) -> Integer', typecheck: :now # Note class and method name required when calling like this
94
+ ```
95
+
96
+ RDL tries to follow the philosophy that you get what you pay for. Methods with type annotations can be checked dynamically or statically; methods without type annotations are unaffected by RDL. See the [performance](#performance) discussion for more detail.
87
97
 
88
98
  RDL supports many more complex type annotations; see below for a complete discussion and examples.
89
99
 
@@ -93,13 +103,13 @@ RDL types are stored in memory at run time, so it's also possible for programs t
93
103
  $ rdl_query String#include? # print type for instance method of another class
94
104
  $ rdl_query Pathname.glob # print type for singleton method of a class
95
105
  $ rdl_query Array # print types for all methods of a class
96
- $ rdl_query "(Fixnum) -> Fixnum" # print all methods that take a Fixnum and return a Fixnum
97
- $ rdl_query "(.) -> Fixnum" # print all methods that take a single arg of any type
98
- $ rdl_query "(..., Fixnum, ...) -> ." # print all methods that take a Fixnum as some argument
106
+ $ rdl_query "(Integer) -> Integer" # print all methods that take an Integer and return an Integer
107
+ $ rdl_query "(.) -> Integer" # print all methods that take a single arg of any type
108
+ $ rdl_query "(..., Integer, ...) -> ." # print all methods that take an Integer as some argument
99
109
 
100
110
  ```
101
111
 
102
- See below for more details of the query format. The `rdl_query` method performs the same function as long as the gem is loaded, so you can use this in `irb`.
112
+ See below for more details of the query format. The `RDL.query` method performs the same function as long as the gem is loaded, so you can use this in `irb`.
103
113
 
104
114
  ```ruby
105
115
  $ irb
@@ -108,13 +118,14 @@ $ irb
108
118
  > require 'types/core'
109
119
  => true
110
120
 
111
- > rdl_query '...' # as above
121
+ > RDL.query '...' # as above
112
122
  ```
113
123
 
114
124
  RDL also supports more general contracts, though these can only be enforced at run time and are not statically checked. These more general contracts take the form of *preconditions*, describing what a method assumes about its inputs, and *postconditions*, describing what a method guarantees about its outputs. For example:
115
125
 
116
126
  ```ruby
117
127
  require 'rdl'
128
+ extend RDL::Annotate
118
129
 
119
130
  pre { |x| x > 0 }
120
131
  post { |r,x| r > 0 }
@@ -123,7 +134,7 @@ def sqrt(x)
123
134
  end
124
135
  ```
125
136
 
126
- Given this program, RDL intercepts the call to `sqrt` and passes its argument to the `pre` block, which checks that the argument is positive. Then when `sqrt` returns, RDL passes the return value (as `r`) and the initial argument (as `x`) to the `post` block, which checks that the return is positive. (Let's ignore complex numbers to keep things simple...) RDL contracts are enforced at method entry and exit. For example, if we call `sqrt(49)`, RDL first checks that `49 > 0`; then it passes `49` to `sqrt`, which (presumably) returns `7`; then RDL checks that `7 > 0`; and finally it returns `7`. Note that pre- and postconditions can't be searched for using `rdl_query`.
137
+ Given this program, RDL intercepts the call to `sqrt` and passes its argument to the `pre` block, which checks that the argument is positive. Then when `sqrt` returns, RDL passes the return value (as `r`) and the initial argument (as `x`) to the `post` block, which checks that the return is positive. (Let's ignore complex numbers to keep things simple...) RDL contracts are enforced at method entry and exit. For example, if we call `sqrt(49)`, RDL first checks that `49 > 0`; then it passes `49` to `sqrt`, which (presumably) returns `7`; then RDL checks that `7 > 0`; and finally it returns `7`. The `pre` and `post` methods can also be called as `RDL.pre` and `RDL.post`, as long as they are also given class and method arguments, similarly to `type`. Note that pre- and postconditions can't be searched for using `RDL.query`.
127
138
 
128
139
  # Using RDL
129
140
 
@@ -137,12 +148,10 @@ RDL currently supports Ruby 2.x. It may or may not work with other versions.
137
148
 
138
149
  ## Loading RDL
139
150
 
140
- Use `require 'rdl'` to load the RDL library. If you want to use the core and standard library type signatures that come with RDL, follow it with `require 'types/core'`. This will load the types based on the current `RUBY_VERSION`. Currently RDL has types for the following versions of Ruby:
151
+ Use `require 'rdl'` to load the RDL library. If you want to access the annotation language, add `extend RDL::Annotate` as appropriate. If you want to use the core and standard library type signatures that come with RDL, follow it with `require 'types/core'`. Currently RDL has types for the following versions of Ruby:
141
152
 
142
153
  * 2.x
143
154
 
144
- (Currently all 2.x versions are assumed to have the same library type signatures, which may not be correct.)
145
-
146
155
  ## Disabling RDL
147
156
 
148
157
  For performance reasons you probably don't want to use RDL in production code. To disable RDL, replace `require 'rdl'` with `require 'rdl_disable'`. This will cause all invocations of RDL methods to either be no-ops or to do the minimum necessary to preserve the program's semantics (e.g., if the RDL method returns `self`, then so does the `rdl_disable` method.)
@@ -165,18 +174,7 @@ to get the head version from github.
165
174
 
166
175
  In development and test mode, you will now have access to `rdl`, `types/core` from RDL, and extra type annotations for Rails and some related gems. In production mode, RDL will be disabled (by loading `rdl_disable`).
167
176
 
168
- **Warning:** Rails support is currently extremely limited, not well tested, and generally needs more work...please send bug reports/pull requests/etc and we will fix things.
169
-
170
- Currently, RDL has types for the following versions of Rails:
171
-
172
- * Rails 5.x support - limited to the following:
173
- * Models
174
- * Generates type annotations for model column getters and setters
175
- * `find_by` and `find_by!`
176
- * Generates types annotations for methods added by `belongs_to`, `has_one`, `has_many`, `has_and_belongs_to_many`.
177
- * Note currently RDL doesn't do very precise type checking of relations
178
- * Controllers
179
- * `errors`
177
+ **Warning:** Rails support is currently extremely limited, not well tested, and generally needs more work...please send bug reports/pull requests/etc and we will try to fix things.
180
178
 
181
179
  ## Preconditions and Postconditions
182
180
 
@@ -196,6 +194,8 @@ The `post` method can be called in the same ways as `pre`.
196
194
 
197
195
  Methods can have no contracts, `pre` by itself, `post` by itself, both, or multiple instances of either. If there are multiple contracts, RDL checks that *all* contracts are satisfied, in the order that the contracts were bound to the method.
198
196
 
197
+ Both `pre` and `post` accept an optional named argument `version` that takes a rubygems version requirement string or array of version requirement students. If the current Ruby version does not match the requirement, then the call to `pre` and `post` is ignored.
198
+
199
199
  ## Type Annotations
200
200
 
201
201
  The `type` method adds a type contract to a method. It supports the same calling patterns as `pre` and `post`, except rather than a block, it takes a string argument describing the type. More specifically, `type` can be called as:
@@ -209,11 +209,13 @@ A type string generally has the form `(typ1, ..., typn) -> typ` indicating a met
209
209
  The `type` method can be called with `wrap: false` so the type information is stored but the type is not enforced. For example, due to the way RDL is implemented, the method `String#=~` can't have a type or contract on it because then it won't set the correct `$1` etc variables:
210
210
 
211
211
  ```ruby
212
- type :=~, '(Object) -> Fixnum or nil', wrap: false # Wrapping this messes up $1 etc
212
+ type :=~, '(Object) -> Integer or nil', wrap: false # Wrapping this messes up $1 etc
213
213
  ```
214
214
 
215
215
  For consistency, `pre` and `post` can also be called with `wrap: false`, but this is generally not as useful.
216
216
 
217
+ The `type` method also accepts an optional `version` named argument.
218
+
217
219
  # RDL Types
218
220
 
219
221
  ## Nominal Types
@@ -221,7 +223,7 @@ For consistency, `pre` and `post` can also be called with `wrap: false`, but thi
221
223
  A nominal type is simply a class name, and it matches any object of that class or any subclass.
222
224
 
223
225
  ```ruby
224
- type String, :insert, '(Fixnum, String) -> String'
226
+ type String, :insert, '(Integer, String) -> String'
225
227
  ```
226
228
 
227
229
  ## Nil Type
@@ -253,7 +255,7 @@ Many Ruby methods can take several different types of arguments or return differ
253
255
 
254
256
  ```ruby
255
257
  type IO, :putc, '(Numeric or String) -> %any'
256
- type String, :getbyte, '(Fixnum) -> Fixnum or nil'
258
+ type String, :getbyte, '(Integer) -> Integer or nil'
257
259
  ```
258
260
 
259
261
  Note that for `getbyte`, we could leave off the `nil`, but we include it to match the current documentation of this method.
@@ -263,10 +265,10 @@ Note that for `getbyte`, we could leave off the `nil`, but we include it to matc
263
265
  Sometimes Ruby methods have several different type signatures. (In Java these would be called *overloaded* methods.) In RDL, such methods are assigned a set of type signatures:
264
266
 
265
267
  ```ruby
266
- type String, :[], '(Fixnum) -> String or nil'
267
- type String, :[], '(Fixnum, Fixnum) -> String or nil'
268
+ type String, :[], '(Integer) -> String or nil'
269
+ type String, :[], '(Integer, Integer) -> String or nil'
268
270
  type String, :[], '(Range or Regexp) -> String or nil'
269
- type String, :[], '(Regexp, Fixnum) -> String or nil'
271
+ type String, :[], '(Regexp, Integer) -> String or nil'
270
272
  type String, :[], '(Regexp, String) -> String or nil'
271
273
  type String, :[], '(String) -> String or nil'
272
274
  ```
@@ -322,7 +324,7 @@ type String, :delete, '(String, *String) -> String'
322
324
  RDL allows arguments to be named, for documentation purposes. Names are given after the argument's type, and they do not affect type contract checking in any way. For example:
323
325
 
324
326
  ```ruby
325
- type Fixnum, :to_s, '(?Fixnum base) -> String'
327
+ type Integer, :to_s, '(?Integer base) -> String'
326
328
  ```
327
329
 
328
330
  Here we've named the first argument of `to_s` as `base` to give some extra hint as to its meaning.
@@ -343,7 +345,7 @@ Here, RDL will check that the `sqrt` method is called on an argument of type `Fl
343
345
  Dependencies can also exist across a method's arguments and return value:
344
346
 
345
347
  ```ruby
346
- type '(Fixnum x {{ x>y }}, Fixnum y) -> Float z {{ z==(x+y) }}'
348
+ type '(Integer x {{ x>y }}, Integer y) -> Float z {{ z==(x+y) }}'
347
349
  def m(x,y) ... end
348
350
  ```
349
351
 
@@ -352,7 +354,7 @@ Any arbitrary code can be placed between the double braces of a type refinement,
352
354
  Most pre- and postconditions can be translated into a dependent type by attaching the precondition to one of the arguments and the postcondition to the return. Note, however, that dependently typed positions must always have a name, even if the associated refinment doesn't refer to that name:
353
355
 
354
356
  ```ruby
355
- type '(Fixnum x {{ $y > 0 }}) -> nil' # argument name must be present even though refinment doesn't use it.
357
+ type '(Integer x {{ $y > 0 }}) -> nil' # argument name must be present even though refinment doesn't use it.
356
358
  ```
357
359
 
358
360
  ## Higher-order Types
@@ -360,14 +362,14 @@ type '(Fixnum x {{ $y > 0 }}) -> nil' # argument name must be present even th
360
362
  RDL supports types for arguments or return values which are themselves `Proc` objects. Simply enclose the corresponding argument's type with braces to denote that it is a `Proc`. For example:
361
363
 
362
364
  ```ruby
363
- type '(Fixnum, {(Fixnum) -> Fixnum}) -> Fixnum'
365
+ type '(Integer, {(Integer) -> Integer}) -> Integer'
364
366
  def m(x, y) ... end
365
367
  ```
366
368
 
367
- The type annotation above states that the method m takes two arguments: one of type `Fixnum`, and another which is a `Proc` which itself takes a `Fixnum` and returns a `Fixnum`. A `Proc` may be the return value of a method as well:
369
+ The type annotation above states that the method m takes two arguments: one of type `Integer`, and another which is a `Proc` which itself takes an `Integer` and returns an `Integer`. A `Proc` may be the return value of a method as well:
368
370
 
369
371
  ```ruby
370
- type '(Fixnum) -> {(Float) -> Float}'
372
+ type '(Integer) -> {(Float) -> Float}'
371
373
  def m(x) ... end
372
374
  ```
373
375
 
@@ -376,18 +378,18 @@ These higher-order types are checked by wrapping the corresponding `Proc` argume
376
378
  A type contract can be provided for a method block as well. The block's type should be included after the method argument types:
377
379
 
378
380
  ```ruby
379
- type '(Fixnum, Float) {(Fixnum, String) -> String } -> Float'
381
+ type '(Integer, Float) {(Integer, String) -> String } -> Float'
380
382
  def m(x,y,&blk) ... end
381
383
  ```
382
384
 
383
385
  Note that this notation will work whether or not a method block is explicitly referenced in the parameters, i.e., whether or not `&blk` is included above. Finally, dependent types work across higher order contracts:
384
386
 
385
387
  ```ruby
386
- type '(Fixnum x, Float y) -> {(Fixnum z {{ z>y }}) -> Fixnum}'
388
+ type '(Integer x, Float y) -> {(Integer z {{ z>y }}) -> Integer}'
387
389
  def m(x,y,&blk) ... end
388
390
  ```
389
391
 
390
- The type contract above states that method `m` returns a `Proc` which takes a `Fixnum z` which must be greater than the argument `Float y`. Whenever this `Proc` is called, it will be checked that this contract holds.
392
+ The type contract above states that method `m` returns a `Proc` which takes an `Integer z` which must be greater than the argument `Float y`. Whenever this `Proc` is called, it will be checked that this contract holds.
391
393
 
392
394
  ## Class/Singleton Method Types
393
395
 
@@ -399,12 +401,6 @@ type File, 'self.dirname', '(String file) -> String dir'
399
401
 
400
402
  (Notice also the use of a named return type, which we haven't seen before.)
401
403
 
402
- Type signatures can be added to `initialize` by giving a type signature for `self.new`:
403
-
404
- ```ruby
405
- type File, 'self.new', '(String file, ?String mode, ?String perm, ?Fixnum opt) -> File'
406
- ```
407
-
408
404
  ## Structural Types
409
405
 
410
406
  Some Ruby methods are intended to take any object that has certain methods. RDL uses *structural types* to denote such cases:
@@ -422,7 +418,7 @@ The actual checking that RDL does here varies depending on what type information
422
418
  Not to be confused with types for singleton methods, RDL includes *singleton types* that denote positions that always have one particular value; this typically happens only in return positions. For example, `Dir#mkdir` always returns the value 0:
423
419
 
424
420
  ```ruby
425
- type Dir, 'self.mkdir', '(String, ?Fixnum) -> 0'
421
+ type Dir, 'self.mkdir', '(String, ?Integer) -> 0'
426
422
  ```
427
423
 
428
424
  In RDL, any integer or floating point number denotes a singleton type. Arbitrary values can be turned into singleton types by wrapping them in `${.}`. For example, `Float#angle` always returns 0 or pi.
@@ -478,7 +474,7 @@ type String, :==, '(%any) -> %bool'
478
474
 
479
475
  Note it is not a bug that `==` is typed to allow any object. Though you would think that developers would generally only compare objects of the same class (since otherwise `==` almost always returns false), in practice a lot of code does compare objects of different classes.
480
476
 
481
- Method `type_alias(name, typ)` can be used to create a user-defined type alias, where `name` must begin with `%`:
477
+ Method `type_alias(name, typ)` (part of `RDL::Annotate`) can be used to create a user-defined type alias, where `name` must begin with `%`:
482
478
 
483
479
  ```ruby
484
480
  type_alias '%real', 'Integer or Float or Rational'
@@ -490,7 +486,7 @@ Type aliases have to be created before they are used (so above, `%path` must be
490
486
 
491
487
  ## Generic Class Types
492
488
 
493
- RDL supports *parametric polymorphism* for classes, a.k.a. *generics*. The `type_params` method names the type parameters of the class, and those parameters can then be used inside type signatures:
489
+ RDL supports *parametric polymorphism* for classes, a.k.a. *generics*. The `type_params` method (part of `RDL::Annotate`) names the type parameters of the class, and those parameters can then be used inside type signatures:
494
490
 
495
491
  ```ruby
496
492
  class Array
@@ -500,27 +496,27 @@ class Array
500
496
  end
501
497
  ```
502
498
 
503
- Here the first argument to `type_params` is a list of symbols or strings that name the type parameters. In this case there is one parameter, `t`, and it is the return type of `shift`.
499
+ Here the first argument to `type_params` is a list of symbols or strings that name the type parameters. In this case there is one parameter, `t`, and it is the return type of `shift`. The `type_params` method accepts an optional first argument, the class whose type parameters to set (this defaults to `self`).
504
500
 
505
- Generic types are applied to type arguments using `<...>` notation, e.g., `Array<Fixnum>` is an `Array` class where `t` is replaced by `Fixnum`. Thus, for example, if `o` is an `Array<Fixnum>`, then `o.shift` returns `Fixnum`. As another example, here is the type for the `[]` method of `Array`:
501
+ Generic types are applied to type arguments using `<...>` notation, e.g., `Array<Integer>` is an `Array` class where `t` is replaced by `Integer`. Thus, for example, if `o` is an `Array<Integer>`, then `o.shift` returns `Integer`. As another example, here is the type for the `[]` method of `Array`:
506
502
 
507
503
  ```ruby
508
504
  type Array, :[], '(Range) -> Array<t>'
509
- type Array, :[], '(Fixnum or Float) -> t'
510
- type Array, :[], '(Fixnum, Fixnum) -> Array<t>'
505
+ type Array, :[], '(Integer or Float) -> t'
506
+ type Array, :[], '(Integer, Integer) -> Array<t>'
511
507
  ```
512
508
 
513
- Thus if `o` is again an `Array<Fixnum>`, then `o[0]` returns a `Fixnum` and `o[0..5]` returns an `Array<Fixnum>`.
509
+ Thus if `o` is again an `Array<Integer>`, then `o[0]` returns an `Integer` and `o[0..5]` returns an `Array<Integer>`.
514
510
 
515
- In general it's impossible to assign generic types to objects without knowing the programmer's intention. For example, consider code as simple as `x = [1,2]`. Is it the programmer's intention that `x` is an `Array<Fixnum>`? `Array<Numeric>`? `Array<Object>`?
511
+ In general it's impossible to assign generic types to objects without knowing the programmer's intention. For example, consider code as simple as `x = [1,2]`. Is it the programmer's intention that `x` is an `Array<Integer>`? `Array<Numeric>`? `Array<Object>`?
516
512
 
517
513
  Thus, by default, even though `Array` is declared to take type parameters, by default RDL treats array objects at the *raw* type `Array`, which means the type parameters are ignored whenever they appear in types. For our example, this means a call such as `x.push("three")` would not be reported as an error (the type signature of `Array#push` is `'(?t) -> Array<t>'`).
518
514
 
519
- To fully enforce generic types, RDL requires that the developer `instantiate!` an object with the desired type parameters:
515
+ To fully enforce generic types, RDL requires that the developer `RDL.instantiate!` an object with the desired type parameters:
520
516
 
521
517
  ```ruby
522
518
  x = [1,2]
523
- x.instantiate!('Fixnum')
519
+ RDL.instantiate!(x, 'Integer')
524
520
  x.push("three") # type error
525
521
  ```
526
522
 
@@ -530,11 +526,11 @@ y = x
530
526
  y.push("three") # also a type error
531
527
  ```
532
528
 
533
- When RDL instantiates an object with type parameters, it needs to ensure the object's contents are consistent with the type. Currently this is enforced using the second parameter to `type_params`, which must name a method that behaves like `Array#all?`, i.e., it iterates through the contents, checking that a block argument is satisfied. As seen above, for `Array` we call `type_params(:t, :all?)`. Then at the call `x.instantiate('Fixnum')`, RDL will call `Array#all?` to iterate through the contents of `x` to check they have type `Fixnum`.
529
+ Calls to `RDL.instantiate!` may also come with a `check` flag. By default, `check` is set to false. When `check` is set to true, we ensure that the receiving object's contents are consistent with the given type *at the time of the call to* `RDL.instantiate!`. Currently this is enforced using the second parameter to `type_params`, which must name a method that behaves like `Array#all?`, i.e., it iterates through the contents, checking that a block argument is satisfied. As seen above, for `Array` we call `type_params(:t, :all?)`. Then at the call `x.instantiate('Integer', check: true)`, RDL will call `Array#all?` to iterate through the contents of `x` to check they have type `Integer`. A simple call to `RDL.instantiate!(x, 'Integer')`, on the other hand, will not check the types of the elements of `x`. The `check` flag thus leaves to the programmer this choice between dynamic type safety and performance.
534
530
 
535
- RDL also includes a `deinstantiate!` method to remove the type instantiation from an object:
531
+ RDL also includes a `RDL.deinstantiate!` method to remove the type instantiation from an object:
536
532
  ```ruby
537
- x.deinstantiate!
533
+ RDL.deinstantiate!(x)
538
534
  x.push("three") # no longer a type error
539
535
  ```
540
536
 
@@ -549,31 +545,33 @@ The rules for variances are standard. Let's assume `A` is a subclass of `B`. Als
549
545
 
550
546
  ## Tuple Types
551
547
 
552
- A type such as `Array<Fixnum>` is useful for homogeneous arrays, where all elements have the same type. But Ruby programs often use heterogeneous arrays, e.g., `[1, "two"]`. The best generic type we can give this is `Array<Fixnum or String>`, but that's imprecise.
548
+ A type such as `Array<Integer>` is useful for homogeneous arrays, where all elements have the same type. But Ruby programs often use heterogeneous arrays, e.g., `[1, "two"]`. The best generic type we can give this is `Array<Integer or String>`, but that's imprecise.
553
549
 
554
- RDL includes special *tuple types* to handle this situation. Tuple types are written `[t1, ..., tn]`, denoting an `Array` of `n` elements of types `t1` through `tn`, in that order. For example, `[1, "two"]` has type `[Fixnum, String]`. As another example, here is the type of `Process#getrlimit`, which returns a two-element array of `Fixnums`:
550
+ RDL includes special *tuple types* to handle this situation. Tuple types are written `[t1, ..., tn]`, denoting an `Array` of `n` elements of types `t1` through `tn`, in that order. For example, `[1, "two"]` has type `[Integer, String]`. As another example, here is the type of `Process#getrlimit`, which returns a two-element array of `Integers`:
555
551
 
556
552
  ```ruby
557
- type Process, 'self.getrlimit', '(Symbol or String or Fixnum resource) -> [Fixnum, Fixnum] cur_max_limit'
553
+ type Process, 'self.getrlimit', '(Symbol or String or Integer resource) -> [Integer, Integer] cur_max_limit'
558
554
  ```
559
555
 
560
556
  ## Finite Hash Types
561
557
 
562
558
  Similarly to tuple types, RDL also supports *finite hash types* for heterogeneous hashes. Finite hash types are written `{k1 => v1, ..., kn => vn}` to indicate a `Hash` with `n` mappings of type `ki` maps to `vi`. The `ki` may be strings, integers, floats, or constants denoted with `${.}`. If a key is a symbol, then the mapping should be written `ki: vi`. In the latter case, the `{}`'s can be left off:
563
559
  ```ruby
564
- type MyClass, :foo, '(a: Fixnum, b: String) { () -> %any } -> %any'
560
+ type MyClass, :foo, '(a: Integer, b: String) { () -> %any } -> %any'
565
561
  ```
566
- Here `foo`, takes a hash where key `:a` is mapped to a `Fixnum` and key `:b` is mapped to a `String`. Similarly, `{'a'=>Fixnum, 2=>String}` types a hash where keys `'a'` and `2` are mapped to a `Fixnum` and `String`, respectively. Both syntaxes can be used to define hash types.
562
+ Here `foo`, takes a hash where key `:a` is mapped to an `Integer` and key `:b` is mapped to a `String`. Similarly, `{'a'=>Integer, 2=>String}` types a hash where keys `'a'` and `2` are mapped to `Integer` and `String`, respectively. Both syntaxes can be used to define hash types.
567
563
 
568
564
  RDL also allows a "rest" type in finite hashes (of course, they're not so finite if they use it!):
569
565
  ```ruby
570
- type MyClass, :foo, '(a: Fixnum, b: String, **Float) -> %any'
566
+ type MyClass, :foo, '(a: Integer, b: String, **Float) -> %any'
571
567
  ```
572
- In this method, `a` is a `Fixnum`, `b` is a `String`, and any number (zero or more) remaining keyword arguments can be passed where the values have type `Float`, e.g., a call `foo(a: 3, b: 'b', pi: 3.14)` is allowed.
568
+ In this method, `a` is an `Integer`, `b` is a `String`, and any number (zero or more) remaining keyword arguments can be passed where the values have type `Float`, e.g., a call `foo(a: 3, b: 'b', pi: 3.14)` is allowed.
573
569
 
574
570
  ## Type Casts
575
571
 
576
- Sometimes RDL does not have precise information about an object's type (this is most useful during static type checking). For these cases, RDL supports type casts of the form `o.type_cast(t)`. This call returns a new object that delegates all methods to `o` but that will be treated by RDL as if it had type `t`. If `force: true` is passed to `type_cast`, RDL will perform the cast without checking whether `o` is actually a member of the given type. For example, `x = "a".type_cast('nil', force: true)` will make RDL treat `x` as if it had type `nil`, even though it's a `String`.
572
+ Sometimes RDL does not have precise information about an object's type (this is most useful during static type checking). For these cases, RDL supports type casts of the form `RDL.type_cast(o, t)`. This call returns a new object that delegates all methods to `o` but that will be treated by RDL as if it had type `t`. If `force: true` is passed to `RDL.type_cast`, RDL will perform the cast without checking whether `o` is actually a member of the given type. For example, `x = RDL.type_cast('a', 'nil', force: true)` will make RDL treat `x` as if it had type `nil`, even though it's a `String`.
573
+
574
+ Similarly, if an object's type is parameterized (see [Generic Types](#generic-class-types) above), RDL might not statically know the correct instantiation of the object's type parameters. In this case, we can use `RDL.instantiate!` to provide the proper type parameter bindings. For instance, if `a` has type `Array`, but we want RDL to know that `a`'s elements are all `Integer`s or `String`s, we can call `RDL.instantiate!(a, 'Integer or String')`.
577
575
 
578
576
  ## Bottom Type (%bot)
579
577
 
@@ -583,15 +581,23 @@ RDL also includes a special *bottom* type `%bot` that is a subtype of any type,
583
581
 
584
582
  Types can be prefixed with `!` to indicate the associated value is not `nil`. For example:
585
583
 
586
- `type :x=, '(!Fixnum) -> !Fixnum' # x's argument must not be nil`
584
+ `type :x=, '(!Integer) -> !Integer' # x's argument must not be nil`
587
585
 
588
586
  **Warning:** This is simply *documentation* of non-nullness, and **is not checked** by the static type checker. The contract checker might or might not enforce non-nullness. (For those who are curious: RDL has this annotation because it seems useful for descriptive purposes. However, it's quite challenging to build a practical analysis that enforces non-nilness without reporting too many false positives.)
589
587
 
588
+ ## Constructor Type
589
+
590
+ Type signatures can be added to constructors by giving a type signature for `initialize` (not for `new` or `self.new`). The return type for `initialize` must always be `self` or a [generic type](#generic-class-types) where the base is `self`:
591
+
592
+ ```ruby
593
+ type :initialize, '(String, Fixnum) -> self'
594
+ ```
595
+
590
596
  # Static Type Checking
591
597
 
592
598
  As mentioned in the introduction, calling `type` with `typecheck: :now` statically type checks the body of the annotated method body against the given signature. If the method has already been defined, RDL will try to check the method immediately. Otherwise, RDL will statically type check the method as soon as it is loaded.
593
599
 
594
- Often method bodies cannot be type checked as soon as they are loaded because they refer to classes, methods, and variables that have not been created yet. To support these cases, some other symbol can be supplied as `typecheck: sym`. Then when `rdl_do_typecheck sym` is called, all methods typechecked at `sym` will be statically checked.
600
+ Often method bodies cannot be type checked as soon as they are loaded because they refer to classes, methods, and variables that have not been created yet. To support these cases, some other symbol can be supplied as `typecheck: sym`. Then when `RDL.do_typecheck sym` is called, all methods typechecked at `sym` will be statically checked.
595
601
 
596
602
  Additionally, `type` can be called with `typecheck: :call`, which will delay checking the method's type until the method is called. Currently these checks are not cached, so expect a big performance hit for using this feature.
597
603
 
@@ -600,11 +606,11 @@ To perform type checking, RDL needs source code, which it gets by parsing the fi
600
606
  ```ruby
601
607
  [2] pry(main)> require 'rdl'
602
608
  [3] pry(main)> require 'types/core'
603
- [4] pry(main)> type '() -> Fixnum', typecheck: :later # note: typecheck: :now doesn't work in pry
609
+ [4] pry(main)> type '() -> Integer', typecheck: :later # note: typecheck: :now doesn't work in pry
604
610
  [5] pry(main)> def f; 'haha'; end
605
- [6] pry(main)> rdl_do_typecheck :later
611
+ [6] pry(main)> RDL.do_typecheck :later
606
612
  RDL::Typecheck::StaticTypeError:
607
- (string):2:3: error: got type `String' where return type `Fixnum' expected
613
+ (string):2:3: error: got type `String' where return type `Integer' expected
608
614
  (string):2: 'haha'
609
615
  (string):2: ^~~~~~
610
616
  from .../typecheck.rb:158:in `error'
@@ -619,27 +625,27 @@ Next we discuss some special features of RDL's type system and some of its limit
619
625
  In a standard type system, local variables have one type throughout a method or function body. For example, in C and Java, declaring `int x` means `x` can only be used as an integer. However, in Ruby, variables need not be declared before they are used. Thus, by default, RDL treats local variables *flow-sensitively*, meaning at each assignment to a local variable, the variable's type is replaced by the type of the right hand side. For example:
620
626
 
621
627
  ```ruby
622
- x = 3 # Here `x` is a `Fixnum`
628
+ x = 3 # Here `x` is a `Integer`
623
629
  x = "three" # Now `x` is a `String`
624
630
  ```
625
- (Note this is a slight fib, since after the first line, `x` will actually have the singleton type `3`. But we'll ignore this just to keep the discussion a bit simpler, especially since `3` is a subtype of `Fixnum`.)
631
+ (Note this is a slight fib, since after the first line, `x` will actually have the singleton type `3`. But we'll ignore this just to keep the discussion a bit simpler, especially since `3` is a subtype of `Integer`.)
626
632
 
627
633
  After conditionals, variables have the union of the types they have along both branches:
628
634
 
629
635
  ```ruby
630
636
  if (some condition) then x = 3 else x = "three" end
631
- # x has type `Fixnum or String`
637
+ # x has type `Integer or String`
632
638
  ```
633
639
 
634
- RDL also provides a method `var_type` that can be used to force a local variable to have a single type through a method body, i.e., to treat it *flow-insensitively* like a standard type system:
640
+ RDL also provides a method `RDL.var_type` that can be used to force a local variable to have a single type through a method body, i.e., to treat it *flow-insensitively* like a standard type system:
635
641
 
636
642
  ```ruby
637
- var_type :x, 'Fixnum'
643
+ RDL.var_type :x, 'Integer'
638
644
  x = 3 # okay
639
645
  x = "three" # type error
640
646
  ```
641
647
 
642
- The first argument to `var_type` is a symbol with the local variable name, and the second argument is a string containing the variable's type. Note that `var_type` is most useful at the beginning of method or code block. Using it elsewhere may result in surprising error messages, since RDL requires variables with fixed types to have the same type along all paths. Method parameters are treated as if `var_type` was called on them at the beginning of the method, fixing them to their declared type. This design choice may be revisited in the future.
648
+ The first argument to `RDL.var_type` is a symbol with the local variable name, and the second argument is a string containing the variable's type. Note that `RDL.var_type` is most useful at the beginning of method or code block. Using it elsewhere may result in surprising error messages, since RDL requires variables with fixed types to have the same type along all paths. Method parameters are treated as if `RDL.var_type` was called on them at the beginning of the method, fixing them to their declared type. This design choice may be revisited in the future.
643
649
 
644
650
  There is one subtlety for local variables and code blocks. Consider the following code:
645
651
  ```ruby
@@ -649,11 +655,12 @@ m() { x = 'bar' }
649
655
  ```
650
656
  If `m` invokes the code block, `x` will be a `String` after the call. Otherwise `x` will be `1`. Since RDL can't tell whether the code block is ever called, it assigns `x` type `1 or String`. It's actually quite tricky to do very precise reasoning about code blocks. For example, `m` could (pathologically) store its block in a global variable and then only call it the second time `m` is invoked. To keep its reasoning simple, RDL treats any local variables captured (i.e., imported from an outer scope) by a code block flow-insensitively for the lifetime of the method. The type of any such local variable is the union of all types that are ever assigned to it.
651
657
 
652
- RDL always treats instance, class, and global variables flow-insensitively, hence their types must be defined with `var_type`:
658
+ RDL always treats instance, class, and global variables flow-insensitively, hence their types must be defined with `var_type`. In this case, `var_type` can optionally be accessed without the `RDL` prefix by adding in the annotation syntax:
653
659
 
654
660
  ```ruby
655
661
  class A
656
- var_type :@f, 'Fixnum'
662
+ extend RDL::Annotate
663
+ var_type :@f, 'Integer'
657
664
  def m
658
665
  @f = 3 # type safe
659
666
  @f = "three" # type error, incompatible type in assignment
@@ -664,13 +671,13 @@ end
664
671
 
665
672
  The `var_type` method may also be called as `var_type klass, :name, typ` to assign a type to an instance or class variable of class `klass`.
666
673
 
667
- As a short-hand, RDL defines methods `attr_accessor_type`, `attr_reader_type`, and `attr_writer_type` to behave like their corresponding non-`_type` analogs but assign types to the attributes. For example, `attr_accessor_type :f, 'Fixnum', :g, 'String'` is equivalent to:
674
+ As a short-hand, RDL defines methods `attr_accessor_type`, `attr_reader_type`, and `attr_writer_type` (also part of `RDL::Annotate`) to behave like their corresponding non-`_type` analogs but assign types to the attributes. For example, `attr_accessor_type :f, 'Integer', :g, 'String'` is equivalent to:
668
675
 
669
676
  ```ruby
670
- var_type :@f, 'Fixnum'
677
+ var_type :@f, 'Integer'
671
678
  var_type :@g, 'String'
672
- type :f, '() -> Fixnum'
673
- type :f=, '(Fixnum) -> Fixnum'
679
+ type :f, '() -> Integer'
680
+ type :f=, '(Integer) -> Integer'
674
681
  type :g, '() -> String'
675
682
  type :g=, '(String) -> String'
676
683
  ```
@@ -687,7 +694,7 @@ a, b = x # a has type 1, b has type String
687
694
  RDL also allows a tuple `[t1, ..., tn]` to be used where `Array<t1 or ... or tn>` is expected. This means both when a tuple is passed to an `Array` position, and when any method is invoked on the tuple (even if RDL could safely apply that method to the tuple; this may change in the future):
688
695
 
689
696
  ```ruby
690
- var_type @f, 'Array<Fixnum or String>'
697
+ var_type @f, 'Array<Integer or String>'
691
698
  @f = [1, 'foo'] # okay
692
699
  @f.length # also okay
693
700
  ```
@@ -698,21 +705,21 @@ To maintain soundness, a tuple that is used as an `Array` is treated as if it we
698
705
  x = [1, 'foo'] # at this point, x has type [1, String]
699
706
  var_type @f, '[1, String]'
700
707
  @f = x # okay so far
701
- var_type @g, 'Array<Fixnum or String>'
708
+ var_type @g, 'Array<Integer or String>'
702
709
  @g = x # uh oh
703
710
  ```
704
711
 
705
- When RDL encounters the assignment to `@g`, it retroactively changes `x` to have type `Array<Fixnum or String>`, which is incompatible with type `[1, String]` of `@f`, so the assignment to `@g` signals an error.
712
+ When RDL encounters the assignment to `@g`, it retroactively changes `x` to have type `Array<Integer or String>`, which is incompatible with type `[1, String]` of `@f`, so the assignment to `@g` signals an error.
706
713
 
707
714
  RDL uses the same approach for hashes: hash literals are treated as finite hashes. A finite hash `{k1=>v1, ..., kn=>vn}` can be used where `Hash<k1 or ... or kn, v1 or ... or vn>` is expected. And if a finite hash is used as a `Hash` (including invoking methods on the finite hash; this may change in the future), then it is retroactively converted to a `Hash`.
708
715
 
709
716
  ## Other Features and Limitations
710
717
 
711
- *Displaying types.* As an aid to debugging, the method `rdl_note_type e` will display the type of `e` during type checking. At run time, this method returns its argument. Note that in certain cases RDL may type check the same code repeatedly, in which case an expression's type could be printed multiple times.
718
+ *Displaying types.* As an aid to debugging, the method `RDL.note_type e` will display the type of `e` during type checking. At run time, this method returns its argument. Note that in certain cases RDL may type check the same code repeatedly, in which case an expression's type could be printed multiple times.
712
719
 
713
720
  * *Conditional guards and singletons.* If an `if` or `unless` guard has a singleton type, RDL will typecheck both branches but not include types from the unrealizable branch in the expression type. For example, `if true then 1 else 'two' end` has type `1`. RDL behaves similarly for `&&` and `||`. However, RDL does not implement this logic for `case`.
714
721
 
715
- * *Case analysis by class.* If the guard of a `case` statement is a variable, and then `when` branches compare against classes, RDL refines the type of the guard to be those classes within the corresponding `when` branch. For example, in `case x when Fixnum ...(1)... when String ...(2)... end`, RDL will assume `x` is a `Fixnum` within `(1)` and a `String` within `(2)`.
722
+ * *Case analysis by class.* If the guard of a `case` statement is a variable, and then `when` branches compare against classes, RDL refines the type of the guard to be those classes within the corresponding `when` branch. For example, in `case x when Integer ...(1)... when String ...(2)... end`, RDL will assume `x` is an `Integer` within `(1)` and a `String` within `(2)`.
716
723
 
717
724
  * *Multiple Assignment and nil.* In Ruby, extra left-hand sides of multiple assignments are set to `nil`, e.g., `x, y = [1]` sets `x` to `1` and `y` to `nil`. However, RDL reports an error in this case; this may change in the future.
718
725
 
@@ -720,7 +727,7 @@ RDL uses the same approach for hashes: hash literals are treated as finite hashe
720
727
 
721
728
  * *Caching.* If `typecheck: :call` is specified on a method, Ruby will type check the method every time it is called. In the future, RDL will cache these checks.
722
729
 
723
- * *Dependent Types.* RDL ignores refinements in checking code with dependent types. E.g., given a `Fixnum x {{ x > 0 }}`, RDL will simply treat `x` as a `Fixnum` and ignore the requirement that it be positive.
730
+ * *Dependent Types.* RDL ignores refinements in checking code with dependent types. E.g., given an `Integer x {{ x > 0 }}`, RDL will simply treat `x` as an `Integer` and ignore the requirement that it be positive.
724
731
 
725
732
  * *Unsupported Features.* There are several features of Ruby that are currently not handled by RDL. Here is a non-exhaustive list:
726
733
  * `super` is not supported.
@@ -735,22 +742,52 @@ RDL's static type checker makes some assumptions that should hold unless your Ru
735
742
 
736
743
  * `Class#===` is not redefined
737
744
  * `Proc#call` is not redefined
745
+ * `Object#class` is not redefined
738
746
 
739
747
  (More assumptions will be added here as they are added to RDL...)
740
748
 
741
- # Other RDL Methods
749
+ # RDL Method Reference
750
+
751
+ The following methods are available in `RDL::Annotate`.
752
+
753
+ * `pre [klass], [meth], &blk, wrap: true, version: nil` - add `blk` as a precondition contract on `klass#meth`. If `klass` is omitted, applies to `self`. If `meth` is also omitted, applies to next defined method. If `wrap` is true, wrap the method to actually check the precondition. If it's false, don't wrap the method (this is probably useless). If a `version` string or array of strings is specified (in rubygems format), only apply when the current Ruby version matches.
754
+
755
+ * `post [klass], [meth], &blk, wrap: true, version: nil` - same as `pre`, but add a postcondition.
756
+
757
+ * `type [klass], [meth], typ, wrap: true, typecheck: nil, version: nil` - same as `pre`, but add a type specification. If `typecheck` is `nil`, does no static type checking. If it's `:call`, will type check the method each time it's called. If it's `:now`, will type check the method after it's defined. If it's some other `symbol`, will type check the method when `RDL.do_typecheck symbol` is called.
758
+
759
+ * `var_type [klass], var, typ` - indicate the `typ` is the type for `var`, which may be a `:@field` or `:local_variable`.
760
+
761
+ * `attr_accessor_type :name1, typ1, ...` calls `attr_accessor :name1, ...` and creates type annotations for the given field and its getters and setters.
762
+
763
+ * `attr_reader_type`, `attr_type`, and `attr_writer_type` - analogous to `attr_accessor_type`
764
+
765
+ * `rdl_alias [klass], new_name, old_name` tells RDL that method `new_name` of `klass` is an alias for method `old_name` (of the same class), and therefore they should have the same contracts and types. This method is only needed when adding contracts and types to method that have already been aliased; it's not needed if the method is aliased after the contract or type has been added. If the `klass` argument is omitted it's assumed to be `self`.
766
+
767
+ * `type_params [klass] [:param1, ...], :all, variance: nil, [&blk]` - indicates that `klass` should be treated as a generic type with parameters `:param1...`. The `:all` argument names a method of `klass` that iterates through a `klass` instance's contents. Alternatively, if a block is passed as an argument, that block is used as the iterator. The `variance` argument gives an array of variances of the parameters, `:+` for covariant, `:-` for contravaraiant, and `:~` for invariant. If `variance` is omitted, the parameters are assumed to be invariant.
768
+
769
+ The methods above can also be accessed as `rdl_method` after `extend RDL::RDLAnnotate`. They can also be accessed as `RDL.method`, but when doing so, however, the `klass` and `meth` arguments are not optional and must be specified. The `RDL` module also includes several other useful methods:
770
+
771
+ * `RDL.type_alias '%name', typ` - indicates that if `%name` appears in a type annotations, it should be expanded to `typ`.
772
+
773
+ * `RDL.nowrap [klass]`, if called at the top-level of a class, causes RDL to behave as if `wrap: false` were passed to all `type`, `pre`, and `post` calls in `klass`. This is mostly used for the core and standard libraries, which have trustworthy behavior hence enforcing their types and contracts is not worth the overhead. If `klass` is omitted it's assumed to be `self`.
774
+
775
+ * `RDL.do_typecheck(sym)` statically type checks all methods whose type annotations include argument `typecheck: sym`.
776
+
777
+ * `RDL.at(sym, &blk)` invokes `blk.call(sym)` when `RDL.do_typecheck(sym)` is called. Useful when type annotations need to be generated at some later time, e.g., because not all classes are loaded.
778
+
779
+ * `RDL.note_type e` - evaluates `e` and returns it at run time. During static type checking, prints out the type of `e`.
742
780
 
743
- RDL also includes a few other useful methods:
781
+ * `RDL.remove_type klass, meth` removes the type annotation for meth in klass. Fails if meth does not have a type annotation.
744
782
 
745
- * `rdl_alias new_name, old_name` tells RDL that method `new_name` is an alias for method `old_name`, and therefore they should have the same contracts and types. This method is only needed when adding contracts and types to method that have already been aliased; it's not needed if the method is aliased after the contract or type has been added.
783
+ * `RDL.insantiate!(var, typ1, ...)` - `var` must have a generic type. Instantiates the type of `x` with type parameters `typ1`, ...
746
784
 
747
- * `rdl_nowrap`, if called at the top-level of a class, causes RDL to behave as if `wrap: false` were passed to all `type`, `pre`, and `post` calls in the class. This is mostly used for the core and standard libraries, which have trustworthy behavior hence enforcing their types and contracts is not worth the overhead.
785
+ * `RDL.deinsantiate!(var)` - remove `var`'s instantiation.
748
786
 
749
- * `rdl_remove_type klass, meth` removes the type annotation for meth in klass. Fails if meth does not have a type annotation.
787
+ * `RDL.type_cast(e, typ, force: false)` - evaluate `e` and return it at run time. During dynamic contract checking, the returned object will have `typ` associated with it. If `force` is `false`, will also check that `e`'s run-time type is compatible with `typ`. If `force` is true then `typ` will be applied regardless of `e`'s type. During static type checking, the type checker will treat the object returned by `type_cast` has having type `typ`.
750
788
 
751
- * `rdl_query` prints information about types; see below for details.
789
+ * `RDL.query` prints information about types; see below for details.
752
790
 
753
- * `rdl_do_at(sym, &blk)` invokes `blk.call(sym)` when `rdl_do_typecheck(sym)` is called. Useful when type annotations need to be generated at some later time, e.g., because not all classes are loaded.
754
791
 
755
792
  # Performance
756
793
 
@@ -764,9 +801,9 @@ RDL supports some tradeoffs between safety and performance. There are three main
764
801
 
765
802
  For uses of `pre` and `post`, there's not a lot of choice: those contracts are enforced at run-time and will incur the costs of wrapped methods. However, note that any methods that are not annotated with `pre` or `post` will not incur the cost of wrapping. (Similarly, methods not annotated with `type` never incur any wrapping cost.)
766
803
 
767
- For uses of `type`, there are more choices, which can be split into two main use cases. First, suppose there's a method `m` that we want a type for but don't want to type check (for example, it may come from some external library). So suppose we read the documentation and give `m` type `(Fixnum) -> Fixnum`. We now have to decide whether to wrap `m`. If we don't wrap `m`, then we incur no overhead on calls to `m`, but we are trusting the type. If we do wrap `m`, then on every call to it RDL will check that we call it with a `Fixnum` and it actually returns a `Fixnum`. So if we're not completely sure of `m`'s type, it might be useful to wrap it and then run test cases against it to see if the type annotation is every violated. (For example, the RDL developers did this to test out many of the core library annotations in RDL.)
804
+ For uses of `type`, there are more choices, which can be split into two main use cases. First, suppose there's a method `m` that we want a type for but don't want to type check (for example, it may come from some external library). So suppose we read the documentation and give `m` type `(Integer) -> Integer`. We now have to decide whether to wrap `m`. If we don't wrap `m`, then we incur no overhead on calls to `m`, but we are trusting the type. If we do wrap `m`, then on every call to it RDL will check that we call it with an `Integer` and it actually returns an `Integer`. So if we're not completely sure of `m`'s type, it might be useful to wrap it and then run test cases against it to see if the type annotation is every violated. (For example, the RDL developers did this to test out many of the core library annotations in RDL.)
768
805
 
769
- Second, suppose there's a method `m` that we do want to type check, and again `m` has type `(Fixnum) -> Fixnum`. Now RDL will use type checking to ensure that if `m` is given a `Fixnum` then it returns `Fixnum`. But now we again have to decide whether to wrap `m`. If we don't wrap `m`, then we get the most efficiency, since typechecking (assuming we do not do it at calls) will only happen once and calls will incur no overhead. On the other hand, it could be that some non-typechecked code calls `m` with something that's not a `Fixnum`, in which case `m` might do anything, including report a type error. (Notice the type checking of `m` assumed its input was a `Fixnum`, and it doesn't say anything about the case when its argument is not.) To protect against this case, we can wrap `m`. Then if a caller violates `m`'s type, we'll get an error in the caller code when it tries to call `m`.
806
+ Second, suppose there's a method `m` that we do want to type check, and again `m` has type `(Integer) -> Integer`. Now RDL will use type checking to ensure that if `m` is given an `Integer` then it returns `Integer`. But now we again have to decide whether to wrap `m`. If we don't wrap `m`, then we get the most efficiency, since typechecking (assuming we do not do it at calls) will only happen once and calls will incur no overhead. On the other hand, it could be that some non-typechecked code calls `m` with something that's not an `Integer`, in which case `m` might do anything, including report a type error. (Notice the type checking of `m` assumed its input was an `Integer`, and it doesn't say anything about the case when its argument is not.) To protect against this case, we can wrap `m`. Then if a caller violates `m`'s type, we'll get an error in the caller code when it tries to call `m`.
770
807
 
771
808
  (Side note: If typed methods are wrapped, then their type contracts are checked at run time for *all* callers, including ones that are were statically type checked and hence couldn't call methods at incorrect types. A future version of RDL will fix this, but it will require some significant changes to RDL's implementation strategy.)
772
809
 
@@ -800,9 +837,9 @@ $ rdl_query Array
800
837
  * Methods can also be search for by their type signature:
801
838
 
802
839
  ```shell
803
- $ rdl_query "(Fixnum) -> Fixnum" # print all methods of type (Fixnum) -> Fixnum
804
- BigDecimal.limit: (Fixnum) -> Fixnum
805
- Dir#pos=: (Fixnum) -> Fixnum
840
+ $ rdl_query "(Integer) -> Integer" # print all methods of type (Integer) -> Integer
841
+ BigDecimal.limit: (Integer) -> Integer
842
+ Dir#pos=: (Integer) -> Integer
806
843
  ... and a lot more
807
844
  ```
808
845
 
@@ -810,15 +847,15 @@ The type signature uses the standard RDL syntax, with two extensions: `.` can be
810
847
 
811
848
  ```shell
812
849
  $ rdl_query "(.) -> ." # methods that take one argument and return anything
813
- $ rdl_query "(Fixnum, .) -> ." # methods that take two arguments, the first of which is a Fixnum
814
- $ rdl_query "(Fixnum, ...) -> ." # methods whose first argument is a Fixnum
815
- $ rdl_query "(..., Fixnum) -> ." # methods whose last argument is a Fixnum
816
- $ rdl_query "(..., Fixnum, ...) -> ." # methods that take a Fixnum somewhere
817
- $ rdl_query "(Fixnum or .) -> ." # methods that take a single argument that is a union containing a Fixnum
850
+ $ rdl_query "(Integer, .) -> ." # methods that take two arguments, the first of which is an Integer
851
+ $ rdl_query "(Integer, ...) -> ." # methods whose first argument is an Integer
852
+ $ rdl_query "(..., Integer) -> ." # methods whose last argument is an Integer
853
+ $ rdl_query "(..., Integer, ...) -> ." # methods that take an Integer somewhere
854
+ $ rdl_query "(Integer or .) -> ." # methods that take a single argument that is a union containing an Integer
818
855
  $ rdl_query "(.?) -> ." # methods that take one, optional argument
819
856
  ```
820
857
 
821
- Note that aside from `.` and `...`, the matching is exact. For example `(Fixnum) -> Fixnum` will not match a method of type `(Fixnum or String) -> Fixnum`.
858
+ Note that aside from `.` and `...`, the matching is exact. For example `(Integer) -> Integer` will not match a method of type `(Integer or String) -> Integer`.
822
859
 
823
860
  # Configuration
824
861
 
@@ -882,7 +919,7 @@ In Object-Oriented Program Languages and Systems (OOPS) Track at ACM Symposium o
882
919
 
883
920
  # Copyright
884
921
 
885
- Copyright (c) 2014-2016, University of Maryland, College Park. All rights reserved.
922
+ Copyright (c) 2014-2017, University of Maryland, College Park. All rights reserved.
886
923
 
887
924
  # Authors
888
925