rdl 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +7 -6
  4. data/CHANGES.md +29 -0
  5. data/README.md +94 -26
  6. data/lib/rdl/boot.rb +82 -41
  7. data/lib/rdl/boot_rails.rb +5 -0
  8. data/lib/rdl/config.rb +9 -1
  9. data/lib/rdl/query.rb +2 -2
  10. data/lib/rdl/typecheck.rb +972 -225
  11. data/lib/rdl/types/annotated_arg.rb +8 -0
  12. data/lib/rdl/types/ast_node.rb +73 -0
  13. data/lib/rdl/types/bot.rb +8 -0
  14. data/lib/rdl/types/bound_arg.rb +63 -0
  15. data/lib/rdl/types/computed.rb +48 -0
  16. data/lib/rdl/types/dependent_arg.rb +9 -0
  17. data/lib/rdl/types/dynamic.rb +61 -0
  18. data/lib/rdl/types/finite_hash.rb +54 -9
  19. data/lib/rdl/types/generic.rb +33 -0
  20. data/lib/rdl/types/intersection.rb +8 -0
  21. data/lib/rdl/types/lexer.rex +6 -1
  22. data/lib/rdl/types/lexer.rex.rb +13 -1
  23. data/lib/rdl/types/method.rb +14 -0
  24. data/lib/rdl/types/nominal.rb +8 -0
  25. data/lib/rdl/types/non_null.rb +8 -0
  26. data/lib/rdl/types/optional.rb +8 -0
  27. data/lib/rdl/types/parser.racc +31 -5
  28. data/lib/rdl/types/parser.tab.rb +540 -302
  29. data/lib/rdl/types/rdl_types.rb +45 -0
  30. data/lib/rdl/types/singleton.rb +14 -1
  31. data/lib/rdl/types/string.rb +104 -0
  32. data/lib/rdl/types/structural.rb +8 -0
  33. data/lib/rdl/types/top.rb +8 -0
  34. data/lib/rdl/types/tuple.rb +32 -8
  35. data/lib/rdl/types/type.rb +54 -11
  36. data/lib/rdl/types/union.rb +41 -2
  37. data/lib/rdl/types/var.rb +10 -0
  38. data/lib/rdl/types/vararg.rb +8 -0
  39. data/lib/rdl/util.rb +13 -10
  40. data/lib/rdl/wrap.rb +271 -27
  41. data/lib/rdl_disable.rb +16 -2
  42. data/lib/types/active_record.rb +1 -0
  43. data/lib/types/core/array.rb +442 -23
  44. data/lib/types/core/basic_object.rb +3 -3
  45. data/lib/types/core/bigdecimal.rb +5 -0
  46. data/lib/types/core/class.rb +2 -0
  47. data/lib/types/core/dir.rb +3 -3
  48. data/lib/types/core/enumerable.rb +4 -4
  49. data/lib/types/core/enumerator.rb +1 -1
  50. data/lib/types/core/file.rb +4 -4
  51. data/lib/types/core/float.rb +203 -0
  52. data/lib/types/core/hash.rb +390 -15
  53. data/lib/types/core/integer.rb +223 -10
  54. data/lib/types/core/io.rb +2 -2
  55. data/lib/types/core/kernel.rb +8 -5
  56. data/lib/types/core/marshal.rb +3 -0
  57. data/lib/types/core/module.rb +3 -3
  58. data/lib/types/core/numeric.rb +0 -2
  59. data/lib/types/core/object.rb +5 -5
  60. data/lib/types/core/pathname.rb +2 -2
  61. data/lib/types/core/process.rb +1 -3
  62. data/lib/types/core/range.rb +1 -1
  63. data/lib/types/core/regexp.rb +2 -2
  64. data/lib/types/core/set.rb +1 -1
  65. data/lib/types/core/string.rb +408 -16
  66. data/lib/types/core/symbol.rb +3 -3
  67. data/lib/types/core/time.rb +1 -1
  68. data/lib/types/core/uri.rb +13 -13
  69. data/lib/types/rails/_helpers.rb +7 -1
  70. data/lib/types/rails/action_controller/mime_responds.rb +2 -0
  71. data/lib/types/rails/active_record/associations.rb +42 -30
  72. data/lib/types/rails/active_record/comp_types.rb +637 -0
  73. data/lib/types/rails/active_record/finder_methods.rb +1 -1
  74. data/lib/types/rails/active_record/model_schema.rb +28 -16
  75. data/lib/types/rails/active_record/relation.rb +5 -3
  76. data/lib/types/rails/active_record/sql-strings.rb +166 -0
  77. data/lib/types/rails/string.rb +1 -1
  78. data/lib/types/sequel.rb +1 -0
  79. data/lib/types/sequel/comp_types.rb +581 -0
  80. data/rdl.gemspec +5 -4
  81. data/test/test_alias.rb +4 -0
  82. data/test/test_array_types.rb +244 -0
  83. data/test/test_bound_types.rb +80 -0
  84. data/test/test_contract.rb +4 -0
  85. data/test/test_dsl.rb +5 -0
  86. data/test/test_dyn_comptype_checks.rb +206 -0
  87. data/test/test_generic.rb +21 -20
  88. data/test/test_hash_types.rb +322 -0
  89. data/test/test_intersection.rb +1 -0
  90. data/test/test_le.rb +29 -4
  91. data/test/test_member.rb +3 -1
  92. data/test/test_parser.rb +5 -0
  93. data/test/test_query.rb +1 -0
  94. data/test/test_rdl.rb +63 -28
  95. data/test/test_rdl_type.rb +4 -0
  96. data/test/test_string_types.rb +102 -0
  97. data/test/test_type_contract.rb +59 -37
  98. data/test/test_typecheck.rb +480 -75
  99. data/test/test_types.rb +17 -0
  100. data/test/test_wrap.rb +5 -0
  101. metadata +35 -5
  102. data/lib/types/rails/active_record/schema_types.rb +0 -51
@@ -5,8 +5,8 @@ RDL.type :Regexp, 'self.last_match', '() -> MatchData', wrap: false # Can't wrap
5
5
  RDL.type :Regexp, 'self.last_match', '(Integer) -> String', wrap: false
6
6
  RDL.type :Regexp, :initialize, '(String, ?%any options, ?String kcode) -> self'
7
7
  RDL.type :Regexp, :initialize, '(Regexp) -> self'
8
- RDL.rdl_alias :Regexp, 'self.compile', 'self.new'
9
- RDL.rdl_alias :Regexp, 'self.quote', 'self.escape'
8
+ RDL.rdl_alias :Regexp, :'self.compile', :initialize
9
+ RDL.rdl_alias :Regexp, :'self.quote', :'self.escape'
10
10
  RDL.type :Regexp, 'self.try_convert', '(%any obj) -> Regexp or nil'
11
11
  RDL.type :Regexp, 'self.union', '(*(Regexp or String) pats) -> Regexp'
12
12
  RDL.type :Regexp, 'self.union', '(Array<Regexp or String> pats) -> Regexp'
@@ -18,7 +18,7 @@ RDL.type :Set, :add, '(t o) -> self'
18
18
  RDL.type :Set, :add?, '(t o) -> self or nil'
19
19
  RDL.type :Set, :classify, '() { (u) -> t } -> Hash<u, Set<t>>'
20
20
  RDL.type :Set, :clear, '() -> self'
21
- RDL.rdl_alias :Set, :collect!, :map
21
+ RDL.rdl_alias :Set, :collect!, :map!
22
22
  RDL.type :Set, :delete, '(t o) -> self'
23
23
  RDL.type :Set, :delete?, '(t o) -> self or nil'
24
24
  RDL.type :Set, :delete_if, '() { (t) -> %bool } -> self'
@@ -1,19 +1,411 @@
1
1
  RDL.nowrap :String
2
+
3
+ def String.output_type(trec, targs, meth, type)
4
+ case trec
5
+ when RDL::Type::PreciseStringType
6
+ return RDL::Globals.parser.scan_str "#T #{type}" unless trec.vals.size == 1 ## Can maybe get more precise than this for some methods, but in most cases we have to sacrifice precision. Might return to this.
7
+ if targs.empty?
8
+ res = trec.vals[0].send(meth)
9
+ elsif targs.size == 1
10
+ case targs[0]
11
+ when RDL::Type::SingletonType
12
+ res = trec.vals[0].send(meth, targs[0].val)
13
+ when RDL::Type::PreciseStringType
14
+ res = trec.vals[0].send(meth, targs.vals[0])
15
+ else
16
+ RDL::Globals.parser.scan_str "#T #{type}"
17
+ end
18
+ elsif targs.size > 1 && targs.all? { |a| a.is_a?(RDL::Type::SingletonType) }
19
+ vals = targs.map { |t| t.val }
20
+ to_type(trec.vals[0].send(meth, *vals))
21
+ else
22
+ raise "not yet implemented"
23
+ end
24
+ to_type(res)
25
+ else
26
+ RDL::Globals.parser.scan_str "#T #{type}"
27
+ end
28
+ end
29
+
30
+ RDL.type String, 'self.output_type', "(RDL::Type::Type, Array<RDL::Type::Type>, Symbol, String) -> RDL::Type::Type", effect: [:+, :+]
31
+
32
+ def String.to_type(v)
33
+ case v
34
+ when RDL::Type::Type
35
+ v
36
+ when Array
37
+ RDL::Type::TupleType.new(*(v.map { |i| to_type(i) }))
38
+ when String
39
+ RDL::Type::PreciseStringType.new(v)
40
+ when Symbol, Integer, Float, Class, TrueClass, FalseClass
41
+ RDL::Type::SingletonType.new(v)
42
+ else
43
+ RDL::Type::NominalType.new(v.class)
44
+ end
45
+ end
46
+
47
+ RDL.type String, 'self.to_type', "(%any) -> RDL::Type::Type", effect: [:+, :+]
48
+
49
+ def String.any_string(a)
50
+ case a
51
+ when RDL::Type::PreciseStringType
52
+ a
53
+ else
54
+ RDL::Globals.types[:string]
55
+ end
56
+ end
57
+
58
+ RDL.type String, 'self.any_string', "(%any) -> RDL::Type::Type", effect: [:+, :+]
59
+
60
+ def String.string_promote!(trec)
61
+ case trec
62
+ when RDL::Type::PreciseStringType
63
+ raise "Unable to promote string #{trec}." unless trec.promote!
64
+ trec
65
+ else
66
+ RDL::Globals.types[:string]
67
+ end
68
+ end
69
+
70
+ RDL.type String, 'self.string_promote!', "(%any) -> RDL::Type::Type", effect: [:~, :+]
71
+
72
+
2
73
  RDL.type :String, :initialize, '(?String str) -> self new_str'
3
- RDL.type :String, :try_convert, '(Object obj) -> String or nil new_string'
74
+ RDL.type :String, 'self.try_convert', '(Object obj) -> String or nil new_string'
75
+ RDL.type :String, :%, '(Object) -> ``output_type(trec, targs, :%, "String")``'
76
+ RDL.type :String, :*, '(Integer) -> ``output_type(trec, targs, :*, "String")``'
77
+
78
+ def String.plus_output(trec, targs)
79
+ if trec.is_a?(RDL::Type::PreciseStringType) && targs[0].is_a?(RDL::Type::PreciseStringType)
80
+ then RDL::Type::PreciseStringType.new(*(trec.vals+targs[0].vals))
81
+ else RDL::Globals.types[:string]
82
+ end
83
+ end
84
+
85
+ RDL.type String, 'self.plus_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", effect: [:+, :+]
86
+
87
+
88
+ RDL.type :String, :+, '(``any_string(targs[0])``) -> ``plus_output(trec, targs)``'
89
+ RDL.type :String, :<<, '(Object) -> ``append_output(trec, targs)``'
90
+
91
+ def String.append_output(trec, targs)
92
+ if trec.is_a?(RDL::Type::PreciseStringType) && targs[0].is_a?(RDL::Type::PreciseStringType)
93
+ targs[0].vals.each { |v|
94
+ if trec.vals.last.is_a?(String) && v.is_a?(String)
95
+ trec.vals.last << v
96
+ else
97
+ trec.vals << v
98
+ end
99
+ }
100
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
101
+ trec
102
+ elsif trec.is_a?(RDL::Type::PreciseStringType)
103
+ trec.promote!
104
+ trec
105
+ else
106
+ RDL::Globals.types[:string]
107
+ end
108
+ end
109
+
110
+ RDL.type String, 'self.append_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", effect: [:+, :+]
111
+
112
+ RDL.type :String, :<=>, '(String other) -> ``output_type(trec, targs, :<=>, "Integer")``'
113
+ RDL.type :String, :==, '(%any) -> ``output_type(trec, targs, :==, "%bool")``', effect: [:+, :+]
114
+ RDL.type :String, :===, '(%any) -> ``output_type(trec, targs, :===, "%bool")``'
115
+ RDL.type :String, :=~, '(Object) -> ``output_type(trec, targs, :=~, "Integer")``', wrap: false # Wrapping this messes up $1 etc
116
+ RDL.type :String, :[], '(Integer, ?Integer) -> ``output_type(trec, targs, :[], "String")``', effect: [:+, :+]
117
+ RDL.type :String, :[], '(Range<Integer> or Regexp) -> ``output_type(trec, targs, :[], "String")``', effect: [:+, :+]
118
+ RDL.type :String, :[], '(Regexp, Integer) -> ``output_type(trec, targs, :[], "String")``', effect: [:+, :+]
119
+ RDL.type :String, :[], '(Regexp, String) -> ``output_type(trec, targs, :[], "String")``', effect: [:+, :+]
120
+ RDL.type :String, :[], '(String) -> ``output_type(trec, targs, :[], "String")``', effect: [:+, :+]
121
+ RDL.type :String, :ascii_only?, '() -> ``output_type(trec, targs, :ascii_only?, "%bool")``'
122
+ RDL.type :String, :b, '() -> ``output_type(trec, targs, :b, "String")``'
123
+ RDL.type :String, :bytes, '() -> ``output_type(trec, targs, :bytes, "Array")``'
124
+ RDL.type :String, :bytesize, '() -> ``output_type(trec, targs, :bytesize, "Integer")``'
125
+ RDL.type :String, :byteslice, '(Integer, ?Integer) -> ``output_type(trec, targs, :byteslice, "String")``'
126
+ RDL.type :String, :byteslice, '(Range<Integer>) -> ``output_type(trec, targs, :byteslice, "String")``'
127
+ RDL.type :String, :capitalize, '() -> ``output_type(trec, targs, :capitalize, "String")``'
128
+ RDL.type :String, :capitalize!, '() -> ``cap_down_output(trec, :capitalize!)``'
129
+ def String.cap_down_output(trec, meth)
130
+ case trec
131
+ when RDL::Type::PreciseStringType
132
+ trec.vals.each { |v| v.send(meth) if v.is_a?(String) }
133
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
134
+ trec
135
+ else
136
+ RDL::Globals.types[:string]
137
+ end
138
+ end
139
+
140
+ RDL.type String, 'self.cap_down_output', "(RDL::Type::Type, Symbol) -> RDL::Type::Type", effect: [:+, :+]
141
+
142
+ RDL.type :String, :casecmp, '(String) -> ``output_type(trec, targs, :casecmp, "Integer")``'
143
+ RDL.type :String, :center, '(Integer, ?String) -> ``output_type(trec, targs, :center, "String")``'
144
+ RDL.type :String, :chars, '() -> ``output_type(trec, targs, :chars, "Array")``' #deprecated
145
+ RDL.type :String, :chomp, '(?String) -> ``output_type(trec, targs, :chomp, "String")``'
146
+ RDL.type :String, :chomp!, '(?String) -> ``string_promote!(trec)``' ## chomp! depends on the value of $/, which is hard to reason about during type checking. So, keeping this imprecise.
147
+ RDL.type :String, :chop, '() -> ``output_type(trec, targs, :chop, "String")``'
148
+ RDL.type :String, :chop!, '() -> ``chop_output(trec)``'
149
+
150
+ def String.chop_output(trec)
151
+ case trec
152
+ when RDL::Type::PreciseStringType
153
+ if trec.vals.last.is_a?(String)
154
+ trec.vals.last.chop!
155
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
156
+ trec
157
+ else
158
+ trec.promote!
159
+ trec
160
+ end
161
+ else
162
+ RDL::Globals.types[:string]
163
+ end
164
+ end
165
+
166
+ RDL.type String, 'self.chop_output', "(RDL::Type::Type) -> RDL::Type::Type", effect: [:+, :+]
167
+
168
+ RDL.type :String, :chr, '() -> ``output_type(trec, targs, :chr, "String")``'
169
+ RDL.type :String, :clear, '() -> ``clear_output(trec)``'
170
+
171
+ def String.clear_output(trec)
172
+ case trec
173
+ when RDL::Type::PreciseStringType
174
+ trec.vals = [""]
175
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
176
+ trec
177
+ else
178
+ RDL::Type::PreciseStringType.new("")
179
+ end
180
+ end
181
+
182
+ RDL.type String, 'self.clear_output', "(RDL::Type::Type) -> RDL::Type::Type", effect: [:+, :+]
183
+
184
+ RDL.type :String, :codepoints, '() -> ``output_type(trec, targs, :codepoints, "Array<Integer>")``'
185
+ RDL.type :String, :concat, '(Integer or Object) -> ``append_output(trec, targs)``'
186
+ RDL.type :String, :count, '(String, *String) -> ``output_type(trec, targs, :count, "Integer")``'
187
+ RDL.type :String, :crypt, '(String) -> ``output_type(trec, targs, :crypt, "String")``'
188
+ RDL.type :String, :delete, '(String, *String) -> ``output_type(trec, targs, :delete, "String")``'
189
+ RDL.type :String, :delete!, '(String, *String) -> ``string_promote!(trec)``'
190
+ RDL.type :String, :downcase, '() -> ``output_type(trec, targs, :downcase, "String")``'
191
+ RDL.type :String, :downcase!, '() -> ``cap_down_output(trec, :downcase!)``'
192
+ RDL.type :String, :dump, '() -> ``output_type(trec, targs, :dump, "String")``'
193
+ RDL.type :String, :each_byte, '() {(Integer) -> %any} -> String'
194
+ RDL.type :String, :each_byte, '() -> Enumerator'
195
+ RDL.type :String, :each_char, '() {(String) -> %any} -> String'
196
+ RDL.type :String, :each_char, '() -> Enumerator'
197
+ RDL.type :String, :each_codepoint, '() {(Integer) -> %any} -> String'
198
+ RDL.type :String, :each_codepoint, '() -> Enumerator'
199
+ RDL.type :String, :each_line, '(?String) {(Integer) -> %any} -> String'
200
+ RDL.type :String, :each_line, '(?String) -> Enumerator'
201
+ RDL.type :String, :empty?, '() ->``output_type(trec, targs, :empty?, "%bool")``'
202
+ # RDL.type :String, :encode, '(?Encoding, ?Encoding, *Symbol) -> String' # TODO: fix Hash arg:String,
203
+ # RDL.type :String, :encode!, '(Encoding, ?Encoding, *Symbol) -> String'
204
+ RDL.type :String, :encoding, '() -> Encoding'
205
+ RDL.type :String, :end_with?, '(*String) -> ``output_type(trec, targs, :end_with?, "%bool")``'
206
+ RDL.type :String, :eql?, '(String) -> ``output_type(trec, targs, :eql?, "%bool")``'
207
+ RDL.type :String, :force_encoding, '(String or Encoding) -> String'
208
+ RDL.type :String, :getbyte, '(Integer) -> ``output_type(trec, targs, :getbyte, "Integer")``'
209
+ RDL.type :String, :gsub, '(Regexp or String, String) -> ``output_type(trec, targs, :gsub, "String")``', wrap: false # Can't wrap these:String, , since they mess with $1 etc
210
+ RDL.type :String, :gsub, '(Regexp or String, Hash) -> ``output_type(trec, targs, :gsub, "String")``'
211
+ RDL.type :String, :gsub, '(Regexp or String, String) -> ``output_type(trec, targs, :gsub, "String")``', wrap: false
212
+ RDL.type :String, :gsub, '(Regexp or String) {(String) -> %any } -> ``output_type(trec, targs, :gsub, "String")``'
213
+ RDL.type :String, :gsub, '(Regexp or String, String) -> ``output_type(trec, targs, :gsub, "String")``', wrap: false
214
+ RDL.type :String, :gsub, '(Regexp or String) -> ``output_type(trec, targs, :gsub, "String")``'
215
+ RDL.type :String, :gsub!, '(Regexp or String, String) -> ``string_promote!(trec)``', wrap: false
216
+ RDL.type :String, :gsub!, '(Regexp or String) {(String) -> %any } -> ``string_promote!(trec)``', wrap: false
217
+ RDL.type :String, :gsub!, '(Regexp or String) -> ``string_promote!(trec); RDL::Type::NominalType.new(Enumerator)``', wrap: false
218
+ RDL.type :String, :hash, '() -> Integer'
219
+ RDL.type :String, :hex, '() -> ``output_type(trec, targs, :getbyte, "Integer")``'
220
+ RDL.type :String, :include?, '(String) -> ``output_type(trec, targs, :include?, "%bool")``', effect: [:+, :+]
221
+ RDL.type :String, :index, '(Regexp or String, ?Integer) -> ``output_type(trec, targs, :index, "Integer")``'
222
+ RDL.type :String, :replace, '(String) -> ``replace_output(trec, targs)``'
223
+
224
+ def String.replace_output(trec, targs)
225
+ case trec
226
+ when RDL::Type::PreciseStringType
227
+ case targs[0]
228
+ when RDL::Type::PreciseStringType
229
+ trec.vals = targs[0].vals
230
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
231
+ trec
232
+ else
233
+ raise RDL::Typecheck::StaticTypeError, "Failed to promote string #{trec}." unless trec.promote!
234
+ trec
235
+ end
236
+ else
237
+ trec
238
+ end
239
+ end
240
+
241
+ RDL.type String, 'self.replace_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", effect: [:+, :+]
242
+
243
+ RDL.type :String, :insert, '(Integer, String) -> String' ## TODO
244
+
245
+ def String.insert_output(trec, targs)
246
+ case trec
247
+ when RDL::Type::PreciseStringType
248
+ if targs[0].is_a?(RDL::Type::SingletonType) && targs[1].is_a?(RDL::Type::PreciseStringType) && targs[1].all? { |v| v.is_a?(String) } && trec.vals.all? { |v| v.is_a?(String) }
249
+ rec_str = trec.vals.join
250
+ arg_int = targs[0].val
251
+ arg_str = targs[1].vals.join
252
+ trec.vals = [rec_str.insert(arg_int, arg_str)]
253
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
254
+ trec
255
+ else
256
+ raise RDL::Typecheck::StaticTypeError, "Failed to promote string #{trec}." unless trec.promote!
257
+ trec
258
+ end
259
+ else
260
+ trec
261
+ end
262
+ end
263
+
264
+ RDL.type String, 'self.insert_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", effect: [:+, :+]
265
+
266
+ RDL.type :String, :inspect, '() -> ``output_type(trec, targs, :inspect, "String")``'
267
+ RDL.type :String, :intern, '() -> ``output_type(trec, targs, :intern, "Symbol")``'
268
+ RDL.type :String, :length, '() -> ``output_type(trec, targs, :length, "Integer")``'
269
+ RDL.type :String, :lines, '(?String) -> ``output_type(trec, targs, :lines, "Array<String>")``'
270
+ RDL.type :String, :ljust, '(Integer, ?String) -> ``output_type(trec, targs, :ljust, "String")``'
271
+ RDL.type :String, :lstrip, '() -> ``output_type(trec, targs, :getbyte, "String")``'
272
+ RDL.type :String, :lstrip!, '() -> ``lrstrip_output(trec, :lstrip!)``' ## TODO
273
+
274
+ def String.lrstrip_output(trec, meth)
275
+ check = (if meth == :lstrip! then :start_with? elsif meth == :rstrip! then :end_with? else raise "unexpected val #{meth}" end)
276
+ case trec
277
+ when RDL::Type::PreciseStringType
278
+ if trec.vals[0].is_a?(String)
279
+ if trec.vals[0].send(check, " ")
280
+ trec.vals[0].send(meth)
281
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
282
+ trec
283
+ else
284
+ trec
285
+ end
286
+ else
287
+ raise RDL::Typecheck::StaticTypeError, "Failed to promote string #{trec}." unless trec.promote!
288
+ trec
289
+ end
290
+ else
291
+ trec
292
+ end
293
+ end
294
+
295
+ RDL.type String, 'self.lrstrip_output', "(RDL::Type::Type, Symbol) -> RDL::Type::Type", effect: [:+, :+]
296
+
297
+ RDL.type :String, :match, '(Regexp or String) -> MatchData'
298
+ RDL.type :String, :match, '(Regexp or String, Integer) -> MatchData'
299
+ RDL.type :String, :next, '() -> ``output_type(trec, targs, :next, "String")``'
300
+ RDL.type :String, :next!, '() -> ``mutate_output(trec, :next!)``' ## TODO
301
+
302
+ def String.mutate_output(trec, meth)
303
+ case trec
304
+ when RDL::Type::PreciseStringType
305
+ if trec.vals.all? { |v| v.is_a?(String) }
306
+ trec.vals = [trec.vals.join.send(meth)]
307
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate string: new string #{trec} does not match prior constraints." unless trec.check_bounds
308
+ trec
309
+ else
310
+ raise RDL::Typecheck::StaticTypeError, "Failed to promote string #{trec}." unless trec.promote!
311
+ trec
312
+ end
313
+ else
314
+ trec
315
+ end
316
+ end
317
+
318
+ RDL.type String, 'self.mutate_output', "(RDL::Type::Type, Symbol) -> RDL::Type::Type", effect: [:+, :+]
319
+
320
+
321
+ RDL.type :String, :oct, '() -> ``output_type(trec, targs, :oct, "Integer")``'
322
+ RDL.type :String, :ord, '() -> ``output_type(trec, targs, :ord, "Integer")``'
323
+ RDL.type :String, :partition, '(Regexp or String) -> ``output_type(trec, targs, :partition, "Array<String>")``'
324
+ RDL.type :String, :prepend, '(String) -> ``output_type(trec, targs, :prepend, "String")``'
325
+ RDL.type :String, :reverse, '() -> ``output_type(trec, targs, :reverse, "String")``'
326
+ RDL.type :String, :rindex, '(String or Regexp, ?Integer) -> ``output_type(trec, targs, :rindex, "Integer")``'
327
+ RDL.type :String, :rjust, '(Integer, ?String) -> ``output_type(trec, targs, :rjust, "String")``'
328
+ RDL.type :String, :rpartition, '(String or Regexp) -> ``output_type(trec, targs, :rpartition, "Array<String>")``'
329
+ RDL.type :String, :rstrip, '() -> ``output_type(trec, targs, :rstrip, "String")``'
330
+ RDL.type :String, :rstrip!, '() -> ``lrstrip_output(trec, :rstrip!)``'
331
+ RDL.type :String, :scan, '(Regexp or String) -> ``output_type(trec, targs, :scan, "Array<String or Array<String>>")``', wrap: false # :String, Can't wrap or screws up last_match
332
+ RDL.type :String, :scan, '(Regexp or String) {(*%any) -> %any} -> ``output_type(trec, targs, :scan, "Array<String or Array<String>>")``', wrap: false
333
+ RDL.type :String, :scrub, '(?String) -> ``output_type(trec, targs, :scrub, "String")``'
334
+ RDL.type :String, :scrub, '(?String) {(%any) -> %any} -> String'
335
+ RDL.type :String, :scrub!, '(?String) -> ``string_promote!(trec)``'
336
+ RDL.type :String, :scrub!, '(?String) {(%any) -> %any} -> ``string_promote!(trec)``'
337
+ RDL.type :String, :size, '() -> ``output_type(trec, targs, :size, "Integer")``'
338
+ RDL.rdl_alias :String, :slice, :[]
339
+ RDL.type :String, :slice!, '(Integer, ?Integer) -> ``string_promote!(trec)``'
340
+ RDL.type :String, :slice!, '(Range<Integer> or Regexp) -> ``string_promote!(trec)``'
341
+ RDL.type :String, :slice!, '(Regexp, Integer) -> ``string_promote!(trec)``'
342
+ RDL.type :String, :slice!, '(Regexp, String) -> ``string_promote!(trec)``'
343
+ RDL.type :String, :slice!, '(String) -> ``string_promote!(trec)``'
344
+ RDL.type :String, :split, '(?(Regexp or String), ?Integer) -> ``output_type(trec, targs, :split, "Array<String>")``', effect: [:+, :+]
345
+ RDL.type :String, :split, '(?Integer) -> ``output_type(trec, targs, :split, "Array<String>")``', effect: [:+, :+]
346
+ RDL.type :String, :squeeze, '() -> ``output_type(trec, targs, :squeeze, "String")``'
347
+ RDL.type :String, :squeeze!, '() -> ``mutate_output(trec, :squeeze!)``'
348
+ RDL.type :String, :start_with?, '(* String) -> ``output_type(trec, targs, :start_with?, "%bool")``', effect: [:+, :+]
349
+ RDL.type :String, :strip, '() -> ``output_type(trec, targs, :strip, "String")``'
350
+ RDL.type :String, :strip!, '() -> ``mutate_output(trec, :strip!)``'
351
+ RDL.type :String, :sub, '(Regexp or String, String or Hash) -> ``output_type(trec, targs, :sub, "String")``', wrap: false # Can't wrap these, since they mess with $1 etc
352
+ RDL.type :String, :sub, '(Regexp or String) {(String) -> %any} -> ``output_type(trec, targs, :sub, "String")``', wrap: false
353
+ RDL.type :String, :sub!, '(Regexp or String, String) -> ``string_promote!(trec)``', wrap: false
354
+ RDL.type :String, :sub!, '(Regexp or String) {(String) -> %any} -> ``string_promote!(trec)``', wrap: false
355
+ RDL.type :String, :succ, '() -> ``output_type(trec, targs, :succ, "String")``'
356
+ RDL.type :String, :sum, '(?Integer) -> ``output_type(trec, targs, :sum, "Integer")``'
357
+ RDL.type :String, :swapcase, '() -> ``output_type(trec, targs, :swapcase, "String")``'
358
+ RDL.type :String, :swapcase!, '() -> ``mutate_output(trec, :swapcase!)``'
359
+ RDL.type :String, :to_c, '() -> Complex'
360
+ RDL.type :String, :to_f, '() -> ``output_type(trec, targs, :to_f, "Float")``'
361
+ RDL.type :String, :to_i, '(?Integer) -> ``output_type(trec, targs, :to_i, "Integer")``'
362
+ RDL.type :String, :to_r, '() -> Rational'
363
+ RDL.type :String, :to_s, '() -> self', effect: [:+, :+]
364
+ RDL.type :String, :to_str, '() -> self'
365
+ RDL.type :String, :to_sym, '() -> ``output_type(trec, targs, :to_sym, "Symbol")``', effect: [:+, :+]
366
+ RDL.type :String, :tr, '(String, String) -> ``output_type(trec, targs, :tr, "String")``'
367
+ RDL.type :String, :tr!, '(String, String) -> ``string_promote!(trec)``'
368
+ RDL.type :String, :tr_s, '(String, String) -> ``output_type(trec, targs, :tr_s, "String")``'
369
+ RDL.type :String, :tr_s!, '(String, String) -> ``string_promote!(trec)``'
370
+ RDL.type :String, :unpack, '(String) -> ``output_type(trec, targs, :unpack, "Array<String>")``'
371
+ RDL.type :String, :upcase, '() -> ``output_type(trec, targs, :upcase, "String")``'
372
+ RDL.type :String, :upcase!, '() -> ``mutate_output(trec, :upcase!)``'
373
+ RDL.type :String, :upto, '(String, ?bool) -> Enumerator'
374
+ RDL.type :String, :upto, '(String, ?bool) {(String) -> %any } -> String'
375
+ RDL.type :String, :valid_encoding?, '() -> ``output_type(trec, targs, :valid_encoding?, "%bool")``'
376
+
377
+
378
+
379
+
380
+
381
+
382
+
383
+
384
+
385
+
386
+
387
+ ### non-dependent types
388
+
389
+
390
+
391
+
392
+
393
+
394
+ RDL.type :String, :initialize, '(?String str) -> self new_str'
395
+ RDL.type :String, :'self.try_convert', '(Object obj) -> String or nil new_string'
4
396
  RDL.type :String, :%, '(Object) -> String'
5
397
  RDL.type :String, :*, '(Integer) -> String'
6
398
  RDL.type :String, :+, '(String) -> String'
7
399
  RDL.type :String, :<<, '(Object) -> String'
8
400
  RDL.type :String, :<=>, '(String other) -> Integer or nil ret'
9
- RDL.type :String, :==, '(%any) -> %bool'
401
+ RDL.type :String, :==, '(%any) -> %bool', effect: [:+, :+]
10
402
  RDL.type :String, :===, '(%any) -> %bool'
11
403
  RDL.type :String, :=~, '(Object) -> Integer or nil', wrap: false # Wrapping this messes up $1 etc
12
- RDL.type :String, :[], '(Integer, ?Integer) -> String or nil'
13
- RDL.type :String, :[], '(Range<Integer> or Regexp) -> String or nil'
14
- RDL.type :String, :[], '(Regexp, Integer) -> String or nil'
15
- RDL.type :String, :[], '(Regexp, String) -> String or nil'
16
- RDL.type :String, :[], '(String) -> String or nil'
404
+ RDL.type :String, :[], '(Integer, ?Integer) -> String or nil', effect: [:+, :+]
405
+ RDL.type :String, :[], '(Range<Integer> or Regexp) -> String or nil', effect: [:+, :+]
406
+ RDL.type :String, :[], '(Regexp, Integer) -> String or nil', effect: [:+, :+]
407
+ RDL.type :String, :[], '(Regexp, String) -> String or nil', effect: [:+, :+]
408
+ RDL.type :String, :[], '(String) -> String or nil', effect: [:+, :+]
17
409
  RDL.type :String, :ascii_only?, '() -> %bool'
18
410
  RDL.type :String, :b, '() -> String'
19
411
  RDL.type :String, :bytes, '() -> Array' # TODO: bindings to parameterized (vars)
@@ -67,7 +459,7 @@ RDL.type :String, :gsub!, '(Regexp or String) {(String) -> %any } -> String or n
67
459
  RDL.type :String, :gsub!, '(Regexp or String) -> Enumerator', wrap: false
68
460
  RDL.type :String, :hash, '() -> Integer'
69
461
  RDL.type :String, :hex, '() -> Integer'
70
- RDL.type :String, :include?, '(String) -> %bool'
462
+ RDL.type :String, :include?, '(String) -> %bool', effect: [:+, :+]
71
463
  RDL.type :String, :index, '(Regexp or String, ?Integer) -> Integer or nil'
72
464
  RDL.type :String, :replace, '(String) -> String'
73
465
  RDL.type :String, :insert, '(Integer, String) -> String'
@@ -98,19 +490,18 @@ RDL.type :String, :scrub, '(?String) -> String'
98
490
  RDL.type :String, :scrub, '(?String) {(%any) -> %any} -> String'
99
491
  RDL.type :String, :scrub!, '(?String) -> String'
100
492
  RDL.type :String, :scrub!, '(?String) {(%any) -> %any} -> String'
101
- RDL.type :String, :set_byte, '(Integer, Integer) -> Integer'
493
+ RDL.type :String, :setbyte, '(Integer, Integer) -> Integer'
102
494
  RDL.type :String, :size, '() -> Integer'
103
- RDL.rdl_alias :String, :slice, :[]
104
495
  RDL.type :String, :slice!, '(Integer, ?Integer) -> String or nil'
105
496
  RDL.type :String, :slice!, '(Range<Integer> or Regexp) -> String or nil'
106
497
  RDL.type :String, :slice!, '(Regexp, Integer) -> String or nil'
107
498
  RDL.type :String, :slice!, '(Regexp, String) -> String or nil'
108
499
  RDL.type :String, :slice!, '(String) -> String or nil'
109
- RDL.type :String, :split, '(?(Regexp or String), ?Integer) -> Array<String>'
110
- RDL.type :String, :split, '(?Integer) -> Array<String>'
500
+ RDL.type :String, :split, '(?(Regexp or String), ?Integer) -> Array<String>', effect: [:+, :+]
501
+ RDL.type :String, :split, '(?Integer) -> Array<String>', effect: [:+, :+]
111
502
  RDL.type :String, :squeeze, '(?String) -> String'
112
503
  RDL.type :String, :squeeze!, '(?String) -> String'
113
- RDL.type :String, :start_with?, '(* String) -> %bool'
504
+ RDL.type :String, :start_with?, '(* String) -> %bool', effect: [:+, :+]
114
505
  RDL.type :String, :strip, '() -> String'
115
506
  RDL.type :String, :strip!, '() -> String'
116
507
  RDL.type :String, :sub, '(Regexp or String, String or Hash) -> String', wrap: false # Can't wrap these, since they mess with $1 etc
@@ -125,9 +516,9 @@ RDL.type :String, :to_c, '() -> Complex'
125
516
  RDL.type :String, :to_f, '() -> Float'
126
517
  RDL.type :String, :to_i, '(?Integer) -> Integer'
127
518
  RDL.type :String, :to_r, '() -> Rational'
128
- RDL.type :String, :to_s, '() -> String'
129
- RDL.type :String, :to_str, '() -> String'
130
- RDL.type :String, :to_sym, '() -> Symbol'
519
+ RDL.type :String, :to_s, '() -> String', effect: [:+, :+]
520
+ RDL.type :String, :to_str, '() -> self'
521
+ RDL.type :String, :to_sym, '() -> Symbol', effect: [:+, :+]
131
522
  RDL.type :String, :tr, '(String, String) -> String'
132
523
  RDL.type :String, :tr!, '(String, String) -> String or nil'
133
524
  RDL.type :String, :tr_s, '(String, String) -> String'
@@ -138,3 +529,4 @@ RDL.type :String, :upcase!, '() -> String or nil'
138
529
  RDL.type :String, :upto, '(String, ?bool) -> Enumerator'
139
530
  RDL.type :String, :upto, '(String, ?bool) {(String) -> %any } -> String'
140
531
  RDL.type :String, :valid_encoding?, '() -> %bool'
532
+