rdl 2.0.0.rc2 → 2.0.0.rc3

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +7 -1
  3. data/README.md +94 -20
  4. data/lib/rdl.rb +4 -1
  5. data/lib/rdl/config.rb +90 -3
  6. data/lib/rdl/info.rb +16 -0
  7. data/lib/rdl/typecheck.rb +207 -79
  8. data/lib/rdl/types/bot.rb +1 -1
  9. data/lib/rdl/types/dependent_arg.rb +17 -8
  10. data/lib/rdl/types/{finitehash.rb → finite_hash.rb} +3 -29
  11. data/lib/rdl/types/generic.rb +1 -37
  12. data/lib/rdl/types/intersection.rb +1 -0
  13. data/lib/rdl/types/lexer.rex +2 -1
  14. data/lib/rdl/types/lexer.rex.rb +4 -1
  15. data/lib/rdl/types/method.rb +2 -12
  16. data/lib/rdl/types/nominal.rb +1 -22
  17. data/lib/rdl/types/non_null.rb +50 -0
  18. data/lib/rdl/types/parser.racc +3 -1
  19. data/lib/rdl/types/parser.tab.rb +222 -190
  20. data/lib/rdl/types/singleton.rb +1 -6
  21. data/lib/rdl/types/structural.rb +1 -10
  22. data/lib/rdl/types/top.rb +1 -2
  23. data/lib/rdl/types/tuple.rb +3 -19
  24. data/lib/rdl/types/type.rb +223 -0
  25. data/lib/rdl/types/union.rb +12 -2
  26. data/lib/rdl/types/var.rb +4 -1
  27. data/lib/rdl/types/wild_query.rb +1 -0
  28. data/lib/rdl/wrap.rb +199 -169
  29. data/lib/rdl_disable.rb +41 -0
  30. data/lib/rdl_types.rb +1 -4
  31. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/_aliases.rb +0 -0
  32. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/abbrev.rb +0 -0
  33. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/array.rb +56 -56
  34. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/base64.rb +0 -0
  35. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/basic_object.rb +0 -0
  36. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/benchmark.rb +0 -0
  37. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/bigdecimal.rb +0 -0
  38. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/bigmath.rb +0 -0
  39. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/bignum.rb +0 -0
  40. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/class.rb +0 -0
  41. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/complex.rb +0 -0
  42. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/coverage.rb +0 -0
  43. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/csv.rb +0 -0
  44. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/date.rb +0 -0
  45. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/dir.rb +0 -0
  46. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/encoding.rb +0 -0
  47. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/enumerable.rb +0 -0
  48. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/enumerator.rb +0 -0
  49. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/exception.rb +0 -0
  50. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/file.rb +0 -0
  51. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/fileutils.rb +0 -0
  52. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/fixnum.rb +0 -0
  53. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/float.rb +26 -26
  54. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/gem.rb +0 -0
  55. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/hash.rb +0 -0
  56. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/integer.rb +8 -8
  57. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/io.rb +0 -0
  58. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/kernel.rb +12 -11
  59. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/marshal.rb +0 -0
  60. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/matchdata.rb +0 -0
  61. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/math.rb +0 -0
  62. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/module.rb +0 -0
  63. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/nil.rb +0 -0
  64. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/numeric.rb +0 -0
  65. data/lib/types/core-ruby-2.x/object.rb +75 -0
  66. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/pathname.rb +0 -0
  67. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/process.rb +0 -0
  68. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/random.rb +0 -0
  69. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/range.rb +0 -0
  70. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/rational.rb +0 -0
  71. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/regexp.rb +0 -0
  72. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/set.rb +0 -0
  73. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/string.rb +0 -0
  74. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/strscan.rb +0 -0
  75. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/symbol.rb +0 -0
  76. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/time.rb +0 -0
  77. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/uri.rb +0 -0
  78. data/{types/ruby-2.x → lib/types/core-ruby-2.x}/yaml.rb +0 -0
  79. data/lib/types/core.rb +4 -0
  80. data/rdl.gemspec +2 -2
  81. data/test/test_le.rb +77 -35
  82. data/test/test_parser.rb +75 -59
  83. data/test/test_rdl.rb +18 -0
  84. data/test/test_typecheck.rb +73 -4
  85. metadata +54 -57
  86. data/lib/rails_types.rb +0 -1
  87. data/types/rails-4.2.1/fixnum.rb +0 -3
  88. data/types/rails-4.2.1/string.rb +0 -3
  89. data/types/rails-tmp/action_dispatch.rb +0 -406
  90. data/types/rails-tmp/active_record.rb +0 -406
  91. data/types/rails-tmp/devise_contracts.rb +0 -216
  92. data/types/ruby-2.x/object.rb +0 -73
@@ -53,12 +53,7 @@ module RDL::Type
53
53
  end
54
54
 
55
55
  def <=(other)
56
- other = other.canonical
57
- other.instance_of?(TopType) ||
58
- (@val.nil? && (not (other.instance_of?(SingletonType)))) ||
59
- (other.instance_of?(SingletonType) && other.val == @val) ||
60
- (other.instance_of?(UnionType) && other.types.any? { |ot| self <= ot }) ||
61
- (@nominal <= other)
56
+ return Type.leq(self, other)
62
57
  end
63
58
 
64
59
  def member?(obj, *args)
@@ -34,16 +34,7 @@ module RDL::Type
34
34
  end
35
35
 
36
36
  def <=(other)
37
- other = other.canonical
38
- return true if other.instance_of? TopType
39
- # in theory a StructuralType could contain all the methods of a NominalType or GenericType,
40
- # but it seems unlikely in practice, so disallow this case.
41
- return RuntimeError, "Structural subtype can't be subtype of #{other.class}" unless other.instance_of? StructuralType
42
- # allow width subtyping
43
- other.methods.each_pair { |m, t|
44
- return false unless @methods.has_key?(m) && @methods[m] <= t
45
- }
46
- return true
37
+ return Type.leq(self, other)
47
38
  end
48
39
 
49
40
  def member?(obj, *args)
@@ -35,8 +35,7 @@ module RDL::Type
35
35
  end
36
36
 
37
37
  def <=(other)
38
- other = other.canonical
39
- other.instance_of? TopType
38
+ return Type.leq(self, other)
40
39
  end
41
40
 
42
41
  def member?(obj, *args)
@@ -3,8 +3,8 @@ module RDL::Type
3
3
  class TupleType < Type
4
4
  attr_reader :params
5
5
  attr_reader :array # either nil or array type if self has been promoted to array
6
- attr_reader :ubounds # upper bounds this tuple has been compared with using <=
7
- attr_reader :lbounds # lower bounds...
6
+ attr_accessor :ubounds # upper bounds this tuple has been compared with using <=
7
+ attr_accessor :lbounds # lower bounds...
8
8
 
9
9
  # no caching because array might be mutated
10
10
  def initialize(*params)
@@ -58,23 +58,7 @@ module RDL::Type
58
58
  end
59
59
 
60
60
  def <=(other)
61
- return @array <= other if @array
62
- other = other.canonical
63
- return true if other.instance_of? TopType
64
- other = other.array if other.instance_of?(TupleType) && other.array
65
- if other.instance_of? TupleType
66
- # Tuples are immutable, so covariant subtyping allowed
67
- return false unless @params.length == other.params.length
68
- return false unless @params.zip(other.params).all? { |left, right| left <= right }
69
- # subyping check passed
70
- ubounds << other
71
- other.lbounds << self
72
- return true
73
- elsif (other.instance_of? GenericType) && (other.base == $__rdl_array_type)
74
- r = promote!
75
- return (self <= other) && r
76
- end
77
- return false
61
+ return Type.leq(self, other)
78
62
  end
79
63
 
80
64
  def member?(obj, *args)
@@ -29,5 +29,228 @@ module RDL::Type
29
29
  return self
30
30
  end
31
31
 
32
+ # [+ other +] is a Type
33
+ # [+ inst +] is a Hash<Symbol, Type> representing an instantiation
34
+ # [+ ileft +] is a %bool
35
+ # if inst is nil, returns self <= other
36
+ # if inst is non-nil and ileft, returns inst(self) <= other, possibly mutating inst to make this true
37
+ # if inst is non-nil and !ileft, returns self <= inst(other), again possibly mutating inst
38
+ def self.leq(left, right, inst=nil, ileft=true)
39
+ left = inst[left.name] if inst && ileft && left.is_a?(VarType) && inst[left.name]
40
+ right = inst[right.name] if inst && !ileft && right.is_a?(VarType) && inst[right.name]
41
+ left = left.type if left.is_a? DependentArgType
42
+ right = right.type if right.is_a? DependentArgType
43
+ left = left.type if left.is_a? NonNullType # ignore nullness!
44
+ right = right.type if right.is_a? NonNullType
45
+ left = left.canonical
46
+ right = right.canonical
47
+
48
+ # top and bottom
49
+ return true if left.is_a? BotType
50
+ return true if right.is_a? TopType
51
+
52
+ # type variables
53
+ begin inst.merge!(left.name => right); return true end if inst && ileft && left.is_a?(VarType)
54
+ begin inst.merge!(right.name => left); return true end if inst && !ileft && right.is_a?(VarType)
55
+ if left.is_a?(VarType) && right.is_a?(VarType)
56
+ return left.name == right.name
57
+ end
58
+
59
+ # union
60
+ return left.types.all? { |t| leq(t, right, inst, ileft) } if left.is_a?(UnionType)
61
+ if right.instance_of?(UnionType)
62
+ right.types.each { |t|
63
+ # return true at first match, updating inst accordingly to first succeessful match
64
+ new_inst = inst.dup unless inst.nil?
65
+ if leq(left, t, new_inst, ileft)
66
+ inst.update(new_inst) unless inst.nil?
67
+ return true
68
+ end
69
+ }
70
+ return false
71
+ end
72
+
73
+ # nominal
74
+ return left.klass.ancestors.member?(right.klass) if left.is_a?(NominalType) && right.is_a?(NominalType)
75
+ if left.is_a?(NominalType) && right.is_a?(StructuralType)
76
+ right.methods.each_pair { |m, t|
77
+ return false unless left.klass.method_defined? m
78
+ types = $__rdl_info.get(left.klass, m, :type)
79
+ if types
80
+ return false unless types.all? { |tlm| leq(tlm, t, nil, ileft) }
81
+ # inst above is nil because the method types inside the class and
82
+ # inside the structural type have an implicit quantifier on them. So
83
+ # even if we're allowed to instantiate type variables we can't do that
84
+ # inside those types
85
+ end
86
+ }
87
+ return true
88
+ end
89
+
90
+ # singleton
91
+ return left.val == right.val if left.is_a?(SingletonType) && right.is_a?(SingletonType)
92
+ return true if left.is_a?(SingletonType) && left.val.nil? # right cannot be a SingletonType due to above conditional
93
+ return leq(left.nominal, right, inst, ileft) if left.is_a?(SingletonType) # fall through case---use nominal type for reasoning
94
+
95
+ # generic
96
+ if left.is_a?(GenericType) && right.is_a?(GenericType)
97
+ formals, variance, _ = $__rdl_type_params[left.base.name]
98
+ # do check here to avoid hiding errors if generic type written
99
+ # with wrong number of parameters but never checked against
100
+ # instantiated instances
101
+ raise TypeError, "No type parameters defined for #{base.name}" unless formals
102
+ return false unless left.base == right.base
103
+ return variance.zip(left.params, right.params).all? { |v, tl, tr|
104
+ case v
105
+ when :+
106
+ leq(tl, tr, inst, ileft)
107
+ when :-
108
+ leq(tr, tl, inst, !ileft)
109
+ when :~
110
+ leq(tl, tr, inst, ileft) && leq(tr, tl, inst, !ileft)
111
+ else
112
+ raise RuntimeError, "Unexpected variance #{v}" # shouldn't happen
113
+ end
114
+ }
115
+ end
116
+ if left.is_a?(GenericType) && right.is_a?(StructuralType)
117
+ # similar to logic above for leq(NominalType, StructuralType, ...)
118
+ formals, variance, _ = $__rdl_type_params[left.base.name]
119
+ raise TypeError, "No type parameters defined for #{base.name}" unless formals
120
+ base_inst = Hash[*formals.zip(left.params).flatten] # instantiation for methods in base's class
121
+ klass = left.base.klass
122
+ right.methods.each_pair { |meth, t|
123
+ return false unless klass.method_defined? meth
124
+ types = $__rdl_info.get(klass, meth, :type)
125
+ if types
126
+ return false unless types.all? { |tlm| leq(tlm.instantiate(base_inst), t, nil, ileft) }
127
+ end
128
+ }
129
+ return true
130
+ end
131
+ # Note we do not allow raw subtyping leq(GenericType, NominalType, ...)
132
+
133
+ # method
134
+ if left.is_a?(MethodType) && right.is_a?(MethodType)
135
+ return false unless left.args.size == right.args.size
136
+ return false unless left.args.zip(right.args).all? { |tl, tr| leq(tr, tl, inst, !ileft) } # contravariance
137
+ return false unless leq(left.ret, right.ret, inst, ileft) # covariance
138
+ if left.block && right.block
139
+ return leq(right.block, left.block, inst, !ileft) # contravariance
140
+ elsif left.block.nil? && right.block.nil?
141
+ return true
142
+ else
143
+ return false # one has a block and the other doesn't
144
+ end
145
+ end
146
+
147
+ # structural
148
+ if left.is_a?(StructuralType) && right.is_a?(StructuralType)
149
+ # allow width subtyping - methods of right have to be in left, but not vice-versa
150
+ return right.methods.all? { |m, t|
151
+ # in recursive call set inst to nil since those method types have implicit quantifier
152
+ left.methods.has_key?(m) && leq(left.methods[m], t, nil, ileft)
153
+ }
154
+ end
155
+ # Note we do not allow a structural type to be a subtype of a nominal type or generic type,
156
+ # even though in theory that would be possible.
157
+
158
+ # tuple
159
+ if left.is_a?(TupleType) && right.is_a?(TupleType)
160
+ # Tuples are immutable, so covariant subtyping allowed
161
+ return false unless left.params.length == right.params.length
162
+ return false unless left.params.zip(right.params).all? { |lt, rt| leq(lt, rt, inst, ileft) }
163
+ # subyping check passed
164
+ left.ubounds << right
165
+ right.lbounds << left
166
+ return true
167
+ end
168
+ if left.is_a?(TupleType) && right.is_a?(GenericType) && right.base == $__rdl_array_type
169
+ # TODO !ileft and right carries a free variable
170
+ return false unless left.promote!
171
+ return leq(left, right, inst, ileft) # recheck for promoted type
172
+ end
173
+
174
+ # finite hash
175
+ if left.is_a?(FiniteHashType) && right.is_a?(FiniteHashType)
176
+ # Like Tuples, FiniteHashes are immutable, so covariant subtyping allowed
177
+ # But note, no width subtyping allowed, to match #member?
178
+ rest = right.elts.clone # shallow copy
179
+ left.elts.each_pair { |k, tl|
180
+ return false unless rest.has_key? k
181
+ tr = rest[k]
182
+ tl = tl.type if tl.is_a? OptionalType
183
+ tr = tr.type if tr.is_a? OptionalType
184
+ return false unless leq(tl, tr, inst, ileft)
185
+ rest.delete k
186
+ }
187
+ rest.each_pair { |k, t|
188
+ return false unless t.is_a? OptionalType
189
+ }
190
+ left.ubounds << right
191
+ right.lbounds << left
192
+ return true
193
+ end
194
+ if left.is_a?(FiniteHashType) && right.is_a?(GenericType) && right.base == $__rdl_hash_type
195
+ # TODO !ileft and right carries a free variable
196
+ return false unless left.promote!
197
+ return leq(left, right, inst, ileft) # recheck for promoted type
198
+ end
199
+
200
+ return false
201
+ end
32
202
  end
203
+
204
+ # [+ a +] is an Array<Type> that may contain union types.
205
+ # returns Array<Array<Type>> containing all possible expansions of the union types.
206
+ # For example, slightly abusing notation:
207
+ #
208
+ # expand_product [A, B] #=> [[A, B]]
209
+ # expand_product [A or B, C] #=> [[A, C], [B, C]]
210
+ # expand_product [A or B, C or D] #=> [[A, C], [B, C], [A, D], [B, D]]
211
+ def self.expand_product(a)
212
+ return [[]] if a.empty? # logic below only applies if at least one element
213
+ a.map! { |t| t.canonical }
214
+ counts = a.map { |t| if t.is_a? UnionType then t.types.length - 1 else 0 end }
215
+ res = []
216
+ # now iterate through ever combination of indices
217
+ # using combinations is not quite as memory efficient as inlining that code here,
218
+ # but it's a lot easier to think about combinations separate from this code
219
+ combinations(counts).each { |inds|
220
+ tmp = []
221
+ # set tmp to be a with elts in positions in ind selected from unions
222
+ a.each_with_index { |t, i| if t.is_a? UnionType then tmp << t.types[inds[i]] else tmp << t end }
223
+ res << tmp
224
+ }
225
+ return res
226
+ # return [a]
227
+ end
228
+
229
+ private
230
+
231
+ # [+ a +] is Array<Fixnum>
232
+ # returns Array<Array<Fixnum>> containing all combinations of 0..a[i] at index i
233
+ # For example:
234
+ #
235
+ # combinations [0, 0] #=> [[0, 0]]
236
+ # combinations [1, 0] #=> [[0, 0], [1, 0]]
237
+ # combinations [1, 1] #=> [[0, 0], [0, 1][, [1, 0], [1, 1]]]
238
+ #
239
+ # yes, this is used in expand_product above!
240
+ def self.combinations(a)
241
+ cur = a.map { |x| 0 }
242
+ res = []
243
+ while ((cur <=> a) < 1) # Array#<=> uses lexicographic order, so this will repeat until cur == a
244
+ res << cur.dup
245
+ i = cur.length - 1 # start at right since want next in lexicographic order
246
+ while i >= 0
247
+ cur[i] += 1
248
+ break if (cur[i] <= a[i]) # increment did not overflow position, or it overflowed in position 0 so allow inc to break outer loop
249
+ cur[i] = 0 unless i == 0 # increment overflowed; reset to 0 and continue looping, except allow overflow to exit when i == 0
250
+ i -= 1
251
+ end
252
+ end
253
+ return res
254
+ end
255
+
33
256
  end
@@ -82,10 +82,20 @@ module RDL::Type
82
82
  end
83
83
 
84
84
  def <=(other)
85
+ return Type.leq(self, other)
86
+ end
87
+
88
+ def leq_inst(other, inst=nil, ileft=true)
85
89
  canonicalize!
86
- return @canonical <= other if @canonical
90
+ return @canonical.leq_inst(other, inst, ileft) if @canonical
91
+ other = other.type if other.is_a? DependentArgType
87
92
  other = other.canonical
88
- @types.all? { |t| t <= other }
93
+ if inst && !ileft && other.is_a?(VarType)
94
+ return leq_inst(inst[other.name], inst, ileft) if inst[other.name]
95
+ inst.merge!(other.name => self)
96
+ return true
97
+ end
98
+ return @types.all? { |t| t.leq_inst(other, inst, ileft) }
89
99
  end
90
100
 
91
101
  def member?(obj, *args)
@@ -32,7 +32,10 @@ module RDL::Type
32
32
 
33
33
  alias eql? ==
34
34
 
35
- alias <= == # hack to allow rdl_query to work with union types...
35
+ # an uninstantiated variable is only comparable to itself
36
+ def <=(other)
37
+ return Type.leq(self, other)
38
+ end
36
39
 
37
40
  def match(other)
38
41
  other = other.canonical
@@ -24,6 +24,7 @@ module RDL::Type
24
24
  alias eql? ==
25
25
 
26
26
  def <=(other)
27
+ other = other.type if other.is_a? DependentArgType
27
28
  other = other.canonical
28
29
  return self == other
29
30
  end
@@ -36,6 +36,7 @@ class RDL::Wrap
36
36
  # return if (klass.method_defined? meth_old) # now checked above by wrapped? call
37
37
  is_singleton_method = RDL::Util.has_singleton_marker(klass_str)
38
38
  full_method_name = RDL::Util.pp_klass_method(klass_str, meth)
39
+ klass_str_without_singleton = if is_singleton_method then RDL::Util.remove_singleton_marker(klass_str) else klass_str end
39
40
 
40
41
  klass.class_eval <<-RUBY, __FILE__, __LINE__
41
42
  alias_method meth_old, meth
@@ -59,18 +60,21 @@ class RDL::Wrap
59
60
  RDL::Contract::AndContract.check_array(pres, self, *args, &blk) if pres
60
61
  types = $__rdl_info.get(klass, meth, :type)
61
62
  if types
62
- matches,args,blk,bind = RDL::Type::MethodType.check_arg_types("#{full_method_name}", self, bind, types, inst, *args, &blk)
63
+ matches, args, blk, bind = RDL::Type::MethodType.check_arg_types("#{full_method_name}", self, bind, types, inst, *args, &blk)
63
64
  end
64
65
  }
65
- ret = send(#{meth_old.inspect}, *args, &blk)
66
+ ret = send(#{meth_old.inspect}, *args, &blk)
66
67
  $__rdl_wrap_switch.off {
67
68
  posts = $__rdl_info.get(klass, meth, :post)
68
69
  RDL::Contract::AndContract.check_array(posts, self, ret, *args, &blk) if posts
69
70
  if matches
70
71
  ret = RDL::Type::MethodType.check_ret_types(self, "#{full_method_name}", types, inst, matches, ret, bind, *args, &blk)
71
72
  end
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? })
75
+ end
76
+ return ret
72
77
  }
73
- return ret
74
78
  end
75
79
  if (public_method_defined? meth_old) then public meth
76
80
  elsif (protected_method_defined? meth_old) then protected meth
@@ -117,7 +121,7 @@ RUBY
117
121
  end
118
122
 
119
123
  # [+default_class+] should be a class
120
- def self.process_type_args(default_class, *args, &blk)
124
+ def self.process_type_args(default_class, *args)
121
125
  klass = meth = type = nil
122
126
  default_class = "Object" if (default_class.is_a? Object) && (default_class.to_s == "main") # special case for main
123
127
  if args.size == 3
@@ -179,13 +183,13 @@ RUBY
179
183
  # called by Object#method_added (sing=false) and Object#singleton_method_added (sing=true)
180
184
  def self.do_method_added(the_self, sing, klass, meth)
181
185
  # Apply any deferred contracts and reset list
182
- if sing
183
- loc = the_self.singleton_method(meth).source_location
184
- else
185
- loc = the_self.instance_method(meth).source_location
186
- end
187
186
 
188
187
  if $__rdl_deferred.size > 0
188
+ if sing
189
+ loc = the_self.singleton_method(meth).source_location
190
+ else
191
+ loc = the_self.instance_method(meth).source_location
192
+ end
189
193
  $__rdl_info.set(klass, meth, :source_location, loc)
190
194
  a = $__rdl_deferred
191
195
  $__rdl_deferred = [] # Reset before doing more work to avoid infinite recursion
@@ -195,10 +199,12 @@ RUBY
195
199
  else
196
200
  tmp_klass = klass
197
201
  end
198
- raise RuntimeError, "Deferred contract from class #{prev_klass} being applied in class #{tmp_klass}" if prev_klass != tmp_klass
202
+ if (!h[:class_check] && (prev_klass != tmp_klass)) || (h[:class_check] && (h[:class_check].to_s != tmp_klass))
203
+ raise RuntimeError, "Deferred #{kind} contract from class #{prev_klass} being applied in class #{tmp_klass} to #{meth}"
204
+ end
199
205
  $__rdl_info.add(klass, meth, kind, contract)
200
206
  RDL::Wrap.wrap(klass, meth) if h[:wrap]
201
- unless $__rdl_info.set(klass, meth, :typecheck, h[:typecheck])
207
+ unless !h.has_key?(:typecheck) || $__rdl_info.set(klass, meth, :typecheck, h[:typecheck])
202
208
  raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}"
203
209
  end
204
210
  RDL::Typecheck.typecheck(klass, meth) if h[:typecheck] == :now
@@ -213,14 +219,24 @@ RUBY
213
219
  if $__rdl_to_wrap.member? [klass, meth]
214
220
  $__rdl_to_wrap.delete [klass, meth]
215
221
  RDL::Wrap.wrap(klass, meth)
222
+ if sing
223
+ loc = the_self.singleton_method(meth).source_location
224
+ else
225
+ loc = the_self.instance_method(meth).source_location
226
+ end
216
227
  $__rdl_info.set(klass, meth, :source_location, loc)
217
228
  end
218
229
 
219
- # Type check method if requested; must typecheck before wrap
230
+ # Type check method if requested
220
231
  if $__rdl_to_typecheck[:now].member? [klass, meth]
221
232
  $__rdl_to_typecheck[:now].delete [klass, meth]
222
233
  RDL::Typecheck.typecheck(klass, meth)
223
234
  end
235
+
236
+ if RDL::Config.instance.guess_types.include?(the_self.to_s.to_sym) && !$__rdl_info.has?(klass, meth, :type)
237
+ # Added a method with no type annotation from a class we want to guess types for
238
+ RDL::Wrap.wrap(klass, meth)
239
+ end
224
240
  end
225
241
  end
226
242
 
@@ -238,41 +254,39 @@ class Object
238
254
  # pre(meth) { block } = pre(self, meth, FlatContract.new { block })
239
255
  # pre(contract) = pre(self, next method, contract)
240
256
  # pre { block } = pre(self, next method, FlatContract.new { block })
241
- def pre(*args, wrap: true, &blk)
242
- $__rdl_contract_switch.off { # Don't check contracts inside RDL code itself
243
- klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Precondition", *args, &blk)
244
- if meth
245
- $__rdl_info.add(klass, meth, :pre, contract)
246
- if wrap
247
- if RDL::Util.method_defined?(klass, meth) || meth == :initialize # there is always an initialize
248
- RDL::Wrap.wrap(klass, meth)
249
- else
250
- $__rdl_to_wrap << [klass, meth]
251
- end
257
+ def pre(*args, wrap: RDL::Config.instance.pre_defaults[:wrap], &blk)
258
+ klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Precondition", *args, &blk)
259
+ if meth
260
+ $__rdl_info.add(klass, meth, :pre, contract)
261
+ if wrap
262
+ if RDL::Util.method_defined?(klass, meth) || meth == :initialize # there is always an initialize
263
+ RDL::Wrap.wrap(klass, meth)
264
+ else
265
+ $__rdl_to_wrap << [klass, meth]
252
266
  end
253
- else
254
- $__rdl_deferred << [klass, :pre, contract, {wrap: wrap}]
255
267
  end
256
- }
268
+ else
269
+ $__rdl_deferred << [klass, :pre, contract, {wrap: wrap}]
270
+ end
271
+ nil
257
272
  end
258
273
 
259
274
  # Add a postcondition to a method. Same possible invocations as pre.
260
- def post(*args, wrap: true, &blk)
261
- $__rdl_contract_switch.off {
262
- klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Postcondition", *args, &blk)
263
- if meth
264
- $__rdl_info.add(klass, meth, :post, contract)
265
- if wrap
266
- if RDL::Util.method_defined?(klass, meth) || meth == :initialize
267
- RDL::Wrap.wrap(klass, meth)
268
- else
269
- $__rdl_to_wrap << [klass, meth]
270
- end
275
+ def post(*args, wrap: RDL::Config.instance.post_defaults[:wrap], &blk)
276
+ klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Postcondition", *args, &blk)
277
+ if meth
278
+ $__rdl_info.add(klass, meth, :post, contract)
279
+ if wrap
280
+ if RDL::Util.method_defined?(klass, meth) || meth == :initialize
281
+ RDL::Wrap.wrap(klass, meth)
282
+ else
283
+ $__rdl_to_wrap << [klass, meth]
271
284
  end
272
- else
273
- $__rdl_deferred << [klass, :post, contract, {wrap: wrap}]
274
285
  end
275
- }
286
+ else
287
+ $__rdl_deferred << [klass, :post, contract, {wrap: wrap}]
288
+ end
289
+ nil
276
290
  end
277
291
 
278
292
  # [+ klass +] may be Class, Symbol, or String
@@ -288,35 +302,35 @@ class Object
288
302
  # type(klass, meth, type)
289
303
  # type(meth, type)
290
304
  # type(type)
291
- def type(*args, wrap: true, typecheck: false, &blk)
292
- $__rdl_contract_switch.off {
293
- klass, meth, type = begin
294
- RDL::Wrap.process_type_args(self, *args, &blk)
295
- rescue Racc::ParseError => err
296
- # Remove enough backtrace to only include actual source line
297
- # Warning: Adjust the -5 below if the code (or this comment) changes
298
- bt = err.backtrace
299
- bt.shift until bt[0] =~ /^#{__FILE__}:#{__LINE__-5}/
300
- bt.shift # remove $__rdl_contract_switch.off call
301
- bt.shift # remove type call itself
302
- err.set_backtrace bt
303
- raise err
304
- end
305
- if meth
305
+ def type(*args, wrap: RDL::Config.instance.type_defaults[:wrap], typecheck: RDL::Config.instance.type_defaults[:typecheck])
306
+ klass, meth, type = begin
307
+ RDL::Wrap.process_type_args(self, *args)
308
+ rescue Racc::ParseError => err
309
+ # Remove enough backtrace to only include actual source line
310
+ # Warning: Adjust the -5 below if the code (or this comment) changes
311
+ bt = err.backtrace
312
+ bt.shift until bt[0] =~ /^#{__FILE__}:#{__LINE__-5}/
313
+ bt.shift # remove $__rdl_contract_switch.off call
314
+ bt.shift # remove type call itself
315
+ err.set_backtrace bt
316
+ raise err
317
+ end
318
+ if meth
306
319
  # It turns out Ruby core/stdlib don't always follow this convention...
307
320
  # if (meth.to_s[-1] == "?") && (type.ret != $__rdl_type_bool)
308
321
  # warn "#{RDL::Util.pp_klass_method(klass, meth)}: methods that end in ? should have return type %bool"
309
322
  # end
310
- $__rdl_info.add(klass, meth, :type, type)
311
- unless $__rdl_info.set(klass, meth, :typecheck, typecheck)
312
- raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}"
313
- end
314
- if wrap
315
- if RDL::Util.method_defined?(klass, meth) || meth == :initialize
316
- $__rdl_info.set(klass, meth, :source_location, RDL::Util.to_class(klass).instance_method(meth).source_location)
317
- RDL::Typecheck.typecheck(klass, meth) if typecheck == :now
318
- RDL::Wrap.wrap(klass, meth)
319
- else
323
+ $__rdl_info.add(klass, meth, :type, type)
324
+ unless $__rdl_info.set(klass, meth, :typecheck, typecheck)
325
+ raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}"
326
+ end
327
+ if wrap || typecheck == :now
328
+ 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
331
+ RDL::Wrap.wrap(klass, meth) if wrap
332
+ else
333
+ if wrap
320
334
  $__rdl_to_wrap << [klass, meth]
321
335
  if (typecheck && typecheck != :call)
322
336
  $__rdl_to_typecheck[typecheck] = Set.new unless $__rdl_to_typecheck[typecheck]
@@ -324,11 +338,12 @@ class Object
324
338
  end
325
339
  end
326
340
  end
327
- else
328
- $__rdl_deferred << [klass, :type, type, {wrap: wrap,
329
- typecheck: typecheck}]
330
341
  end
331
- }
342
+ else
343
+ $__rdl_deferred << [klass, :type, type, {wrap: wrap,
344
+ typecheck: typecheck}]
345
+ end
346
+ nil
332
347
  end
333
348
 
334
349
  # [+ klass +] is the class containing the variable; self if omitted; ignored for local and global variables
@@ -342,6 +357,7 @@ class Object
342
357
  unless $__rdl_info.set(klass, var, :type, $__rdl_parser.scan_str("#T #{typ}"))
343
358
  raise RuntimeError, "Type already declared for #{var}"
344
359
  end
360
+ nil
345
361
  end
346
362
 
347
363
  # In the following three methods
@@ -355,6 +371,7 @@ class Object
355
371
  type name, "() -> #{typ}"
356
372
  type name.to_s + "=", "(#{typ}) -> #{typ}"
357
373
  }
374
+ nil
358
375
  end
359
376
 
360
377
  def attr_reader_type(*args)
@@ -363,6 +380,7 @@ class Object
363
380
  var_type ("@" + name.to_s), typ
364
381
  type name, "() -> #{typ}"
365
382
  }
383
+ nil
366
384
  end
367
385
 
368
386
  alias_method :attr_type, :attr_reader_type
@@ -373,46 +391,43 @@ class Object
373
391
  var_type ("@" + name.to_s), typ
374
392
  type name.to_s + "=", "(#{typ}) -> #{typ}"
375
393
  }
394
+ nil
376
395
  end
377
396
 
378
-
379
397
  def self.method_added(meth)
380
- $__rdl_contract_switch.off {
381
- klass = self.to_s
382
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
383
- RDL::Wrap.do_method_added(self, false, klass, meth)
384
- }
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
385
402
  end
386
403
 
387
404
  def self.singleton_method_added(meth)
388
- $__rdl_contract_switch.off {
389
- klass = self.to_s
390
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
391
- sklass = RDL::Util.add_singleton_marker(klass)
392
- RDL::Wrap.do_method_added(self, true, sklass, meth)
393
- }
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
394
410
  end
395
411
 
396
412
  # Aliases contracts for meth_old and meth_new. Currently, this must
397
413
  # be called for any aliases or they will not be wrapped with
398
414
  # contracts. Only creates aliases in the current class.
399
415
  def rdl_alias(new_name, old_name)
400
- $__rdl_contract_switch.off {
401
- klass = self.to_s
402
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
403
- $__rdl_aliases[klass] = {} unless $__rdl_aliases[klass]
404
- if $__rdl_aliases[klass][new_name]
405
- raise RuntimeError,
406
- "Tried to alias #{new_name}, already aliased to #{$__rdl_aliases[klass][new_name]}"
407
- end
408
- $__rdl_aliases[klass][new_name] = old_name
416
+ klass = self.to_s
417
+ 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]
420
+ raise RuntimeError,
421
+ "Tried to alias #{new_name}, already aliased to #{$__rdl_aliases[klass][new_name]}"
422
+ end
423
+ $__rdl_aliases[klass][new_name] = old_name
409
424
 
410
- if self.method_defined? new_name
411
- RDL::Wrap.wrap(klass, new_name)
412
- else
413
- $__rdl_to_wrap << [klass, old_name]
414
- end
415
- }
425
+ if self.method_defined? new_name
426
+ RDL::Wrap.wrap(klass, new_name)
427
+ else
428
+ $__rdl_to_wrap << [klass, old_name]
429
+ end
430
+ nil
416
431
  end
417
432
 
418
433
  # [+params+] is an array of symbols or strings that are the
@@ -428,85 +443,78 @@ class Object
428
443
  # parameters of the class, and the block should return true if and
429
444
  # only if self is a member of self.class<typs>.
430
445
  def type_params(params, all, variance: nil, &blk)
431
- $__rdl_contract_switch.off {
432
- raise RuntimeError, "Empty type parameters not allowed" if params.empty?
433
- klass = self.to_s
434
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
435
- if $__rdl_type_params[klass]
436
- raise RuntimeError, "#{klass} already has type parameters #{$__rdl_type_params[klass]}"
437
- end
438
- params = params.map { |v|
439
- raise RuntimeError, "Type parameter #{v.inspect} is not symbol or string" unless v.class == String || v.class == Symbol
440
- v.to_sym
441
- }
442
- raise RuntimeError, "Duplicate type parameters not allowed" unless params.uniq.size == params.size
443
- raise RuntimeError, "Expecting #{params.size} variance annotations, got #{variance.size}" if variance && params.size != variance.size
444
- raise RuntimeError, "Only :+, +-, and :~ are allowed variance annotations" unless (not variance) || variance.all? { |v| [:+, :-, :~].member? v }
445
- raise RuntimeError, "Can't pass both all and a block" if all && blk
446
- raise RuntimeError, "all must be a symbol" unless (not all) || (all.instance_of? Symbol)
447
- chk = all || blk
448
- raise RuntimeError, "At least one of {all, blk} required" unless chk
449
- variance = params.map { |p| :~ } unless variance # default to invariant
450
- $__rdl_type_params[klass] = [params, variance, chk]
446
+ raise RuntimeError, "Empty type parameters not allowed" if params.empty?
447
+ klass = self.to_s
448
+ 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]}"
451
+ end
452
+ params = params.map { |v|
453
+ raise RuntimeError, "Type parameter #{v.inspect} is not symbol or string" unless v.class == String || v.class == Symbol
454
+ v.to_sym
451
455
  }
456
+ raise RuntimeError, "Duplicate type parameters not allowed" unless params.uniq.size == params.size
457
+ raise RuntimeError, "Expecting #{params.size} variance annotations, got #{variance.size}" if variance && params.size != variance.size
458
+ raise RuntimeError, "Only :+, +-, and :~ are allowed variance annotations" unless (not variance) || variance.all? { |v| [:+, :-, :~].member? v }
459
+ raise RuntimeError, "Can't pass both all and a block" if all && blk
460
+ raise RuntimeError, "all must be a symbol" unless (not all) || (all.instance_of? Symbol)
461
+ chk = all || blk
462
+ raise RuntimeError, "At least one of {all, blk} required" unless chk
463
+ variance = params.map { |p| :~ } unless variance # default to invariant
464
+ $__rdl_type_params[klass] = [params, variance, chk]
465
+ nil
452
466
  end
453
467
 
454
468
  def rdl_nowrap
455
- $__rdl_contract_switch.off {
456
- RDL.config { |config| config.add_nowrap(self, self.singleton_class) }
457
- }
469
+ RDL.config { |config| config.add_nowrap(self, self.singleton_class) }
470
+ nil
458
471
  end
459
472
 
460
473
  # [+typs+] is an array of types, classes, symbols, or strings to instantiate
461
474
  # the type parameters. If a class, symbol, or string is given, it is
462
475
  # converted to a NominalType.
463
476
  def instantiate!(*typs)
464
- $__rdl_contract_switch.off {
465
- klass = self.class.to_s
466
- klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main")
467
- formals, _, all = $__rdl_type_params[klass]
468
- raise RuntimeError, "Receiver is of class #{klass}, which is not parameterized" unless formals
469
- raise RuntimeError, "Expecting #{params.size} type parameters, got #{typs.size}" unless formals.size == typs.size
470
- raise RuntimeError, "Instance already has type instantiation" if (defined? @__rdl_type) && @rdl_type
471
- new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else $__rdl_parser.scan_str "#T #{t}" end }
472
- t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs)
473
- if all.instance_of? Symbol
474
- self.send(all) { |*objs|
475
- new_typs.zip(objs).each { |nt, obj|
476
- if nt.instance_of? RDL::Type::GenericType # require obj to be instantiated
477
- t_obj = RDL::Util.rdl_type(obj)
478
- raise RDL::Type::TypeError, "Expecting element of type #{nt.to_s}, but got uninstantiated object #{obj.inspect}" unless t_obj
479
- raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got type #{t_obj.to_s}" unless t_obj <= nt
480
- else
481
- raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got #{obj.inspect}" unless nt.member? obj
482
- end
483
- }
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
484
495
  }
485
- else
486
- raise RDL::Type::TypeError, "Not an instance of #{t}" unless instance_exec(*new_typs, &all)
487
- end
488
- @__rdl_type = t
489
- self
490
- }
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
491
502
  end
492
503
 
493
504
  def deinstantiate!
494
- $__rdl_contract_switch.off {
495
- raise RuntimeError, "Class #{self.to_s} is not parameterized" unless $__rdl_type_params[klass]
496
- raise RuntimeError, "Instance is not instantiated" unless @__rdl_type && @@__rdl_type.instance_of?(RDL::Type::GenericType)
497
- @__rdl_type = nil
498
- }
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
499
509
  end
500
510
 
501
511
  # Returns a new object that wraps self in a type cast. If force is true this cast is *unchecked*, so use with caution
502
512
  def type_cast(typ, force: false)
503
- $__rdl_contract_switch.off {
504
- new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "#T #{typ}" end
505
- raise RuntimeError, "type cast error: self not a member of #{new_typ}" unless force || typ.member?(self)
506
- obj = SimpleDelegator.new(self)
507
- obj.instance_variable_set('@__rdl_type', new_typ)
508
- return obj
509
- }
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
510
518
  end
511
519
 
512
520
  # Add a new type alias.
@@ -514,18 +522,17 @@ class Object
514
522
  # [+typ+] can be either a string, in which case it will be parsed
515
523
  # into a type, or a Type.
516
524
  def type_alias(name, typ)
517
- $__rdl_contract_switch.off {
518
- raise RuntimeError, "Attempt to redefine type #{name}" if $__rdl_special_types[name]
519
- case typ
520
- when String
521
- t = $__rdl_parser.scan_str "#T #{typ}"
522
- $__rdl_special_types[name] = t
523
- when RDL::Type::Type
524
- $__rdl_special_types[name] = typ
525
- else
526
- raise RuntimeError, "Unexpected typ argument #{typ.inspect}"
527
- end
528
- }
525
+ raise RuntimeError, "Attempt to redefine type #{name}" if $__rdl_special_types[name]
526
+ case typ
527
+ when String
528
+ t = $__rdl_parser.scan_str "#T #{typ}"
529
+ $__rdl_special_types[name] = t
530
+ when RDL::Type::Type
531
+ $__rdl_special_types[name] = typ
532
+ else
533
+ raise RuntimeError, "Unexpected typ argument #{typ.inspect}"
534
+ end
535
+ nil
529
536
  end
530
537
 
531
538
  # Type check all methods that had annotation `typecheck: sym' at type call
@@ -534,6 +541,29 @@ class Object
534
541
  RDL::Typecheck.typecheck(klass, meth)
535
542
  }
536
543
  $__rdl_to_typecheck[sym] = Array.new
544
+ nil
545
+ end
546
+
547
+ # Does nothing at run time
548
+ def rdl_note_type(x)
549
+ return x
550
+ end
551
+
552
+ def rdl_remove_type(klass, meth)
553
+ raise RuntimeError, "No existing type for #{RDL::Util.pp_klass_method(klass, meth)}" unless $__rdl_info.has? klass, meth, :type
554
+ $__rdl_info.remove klass, meth, :type
555
+ nil
537
556
  end
538
557
 
539
558
  end
559
+
560
+ # method_added for Object doesn't get called on module methods...bug?
561
+ # class Module
562
+ # def method_added(meth)
563
+ # $__rdl_contract_switch.off {
564
+ # klass = self.to_s
565
+ # RDL::Wrap.do_method_added(self, false, klass, meth)
566
+ # nil
567
+ # }
568
+ # end
569
+ # end