rdl 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+