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
@@ -1,9 +1,9 @@
1
1
  RDL.nowrap :BasicObject
2
2
 
3
- RDL.type :BasicObject, :==, '(%any other) -> %bool'
3
+ RDL.type :BasicObject, :==, '(%any other) -> %bool', effect: [:+, :+]
4
4
  RDL.type :BasicObject, :equal?, '(%any other) -> %bool'
5
- RDL.type :BasicObject, :!, '() -> %bool'
6
- RDL.type :BasicObject, :!=, '(%any other) -> %bool'
5
+ RDL.type :BasicObject, :!, '() -> %bool', effect: [:+, :+]
6
+ RDL.type :BasicObject, :!=, '(%any other) -> %bool', effect: [:+, :+]
7
7
  RDL.type :BasicObject, :instance_eval, '(String, ?String filename, ?Integer lineno) -> %any'
8
8
  RDL.type :BasicObject, :instance_eval, '() { () -> %any } -> %any'
9
9
  RDL.type :BasicObject, :instance_exec, '(*%any args) { (*%any) -> %any } -> %any'
@@ -1,5 +1,10 @@
1
1
  RDL.nowrap :BigDecimal
2
2
 
3
+ class BigDecimal < Numeric; end ## Hacky way around existing issue.
4
+ ## The issue is any types that even reference BigDecimal, e.g., Integer#+ etc., will
5
+ ## call const_get on it, but without the above, the class is undefined.
6
+ ## May want to come up with more elegant solution in the future.
7
+
3
8
  RDL.type :BigDecimal, :%, '(%numeric) -> BigDecimal'
4
9
  RDL.pre(:BigDecimal, :%) { |x| x!=0&&(if x.is_a?(Float) then x!=Float::INFINITY && !x.nan? else true end)}
5
10
 
@@ -13,3 +13,5 @@ RDL.type :Class, :instance_methods, '(?%bool) -> Array<Symbol>'
13
13
  RDL.type :Class, :class, '() -> Class'
14
14
  RDL.type :Class, :superclass, '() -> Class'
15
15
  RDL.type :Class, :name, '() -> String'
16
+ RDL.type :Class, :==, '(%any) -> %bool', effect: [:+, :+]
17
+ RDL.type :Class, :===, '(%any) -> %bool', effect: [:+, :+]
@@ -1,6 +1,6 @@
1
1
  RDL.nowrap :Dir
2
2
 
3
- RDL.rdl_alias :Dir, :[], :glob
3
+ RDL.rdl_alias :Dir, :'self.[]', :'self.glob'
4
4
 
5
5
  RDL.type :Dir, 'self.chdir', '(?(String or Pathname)) -> 0'
6
6
  RDL.type :Dir, 'self.chdir', '(?(String or Pathname)) { (String) -> u } -> u'
@@ -12,8 +12,8 @@ RDL.type :Dir, 'self.exist?', '(String file) -> %bool'
12
12
  RDL.type :Dir, 'self.foreach', '(String dir, ?Encoding) { (String) -> %any } -> nil'
13
13
  RDL.type :Dir, 'self.foreach', '(String dir, ?Encoding) -> Enumerator<String>'
14
14
  RDL.type :Dir, 'self.getwd', '() -> String'
15
- RDL.type :Dir, 'self.glob', '(String or Array<String> pattern, ?Fixum flags) -> Array<String>'
16
- RDL.type :Dir, 'self.glob', '(String or Array<String> pattern, ?Fixum flags) { (String) -> %any} -> nil'
15
+ RDL.type :Dir, 'self.glob', '(String or Array<String> pattern, ?Fixnum flags) -> Array<String>'
16
+ RDL.type :Dir, 'self.glob', '(String or Array<String> pattern, ?Fixnum flags) { (String) -> %any} -> nil'
17
17
  RDL.type :Dir, 'self.home', '(?String) -> String'
18
18
  RDL.type :Dir, 'self.mkdir', '(String, ?Integer) -> 0'
19
19
  RDL.type :Dir, 'self.open', '(String, ?Encoding) -> Dir'
@@ -2,8 +2,8 @@ RDL.nowrap :Enumerable
2
2
 
3
3
  RDL.type_params :Enumerable, [:t], :all?
4
4
 
5
- RDL.type :Enumerable, :all?, '() -> %bool'
6
- RDL.type :Enumerable, :all?, '() { (t) -> %bool } -> %bool'
5
+ RDL.type :Enumerable, :all?, '() -> %bool', effect: [:blockdep, :blockdep]
6
+ RDL.type :Enumerable, :all?, '() { (t) -> %bool } -> %bool', effect: [:blockdep, :blockdep]
7
7
  RDL.type :Enumerable, :any?, '() -> %bool'
8
8
  RDL.type :Enumerable, :any?, '() { (t) -> %bool } -> %bool'
9
9
  # RDL.type :Enumerable, :chunk, '(XXXX : *XXXX)' # TODO
@@ -24,8 +24,8 @@ RDL.type :Enumerable, :each_cons, '(Integer n) { (Array<t>) -> %any } -> nil'
24
24
  RDL.type :Enumerable, :each_cons, '(Integer n) -> Enumerator<t>'
25
25
  # RDL.type :Enumerable, :each_entry, '(XXXX : *XXXX)' # TODO
26
26
  RDL.rdl_alias :Enumerable, :each_slice, :each_cons
27
- RDL.type :Enumerable, :each_with_index, '() { (t, Integer) -> %any } -> Enumerable<t>' # args! note may not return self
28
- RDL.type :Enumerable, :each_with_index, '() -> Enumerable<t>' # args! note may not return self
27
+ RDL.type :Enumerable, :each_with_index, '() { (t, Integer) -> %any } -> Enumerable<t>', effect: [:blockdep, :blockdep] # args! note may not return self
28
+ RDL.type :Enumerable, :each_with_index, '() -> Enumerable<t>', effect: [:blockdep, :blockdep] # args! note may not return self
29
29
  # RDL.type :Enumerable, :each_with_object, '(XXXX : XXXX)' #TODO
30
30
  RDL.type :Enumerable, :entries, '() -> Array<t>' # TODO args?
31
31
  RDL.rdl_alias :Enumerable, :find, :detect
@@ -18,7 +18,7 @@ RDL.type :Enumerator, :next, '() -> t'
18
18
  RDL.type :Enumerator, :next_values, '() -> Array<t>'
19
19
  RDL.type :Enumerator, :peek, '() -> t'
20
20
  RDL.type :Enumerator, :peek_values, '() -> Array<t>'
21
- RDL.type :Enumerator, :rewrind, '() -> self'
21
+ RDL.type :Enumerator, :rewind, '() -> self'
22
22
  RDL.type :Enumerator, :size, '() -> Integer or Float or nil'
23
23
  RDL.rdl_alias :Enumerator, :with_index, :each_with_index
24
24
  RDL.rdl_alias :Enumerator, :with_object, :each_with_object
@@ -23,7 +23,7 @@ RDL.type :File, 'self.expand_path', '(%path file, ?%path dir) -> String abs_file
23
23
  RDL.type :File, 'self.extname', '(String path) -> String'
24
24
  RDL.type :File, 'self.file?', '(String or IO file) -> %bool'
25
25
  RDL.type :File, 'self.fnmatch', '(String pattern, String path, ?Integer flags) -> %bool'
26
- RDL.rdl_alias :File, :fnmatch?, :fnmatch
26
+ RDL.rdl_alias :File, :'self.fnmatch?', :'self.fnmatch'
27
27
  RDL.type :File, 'self.ftype', '(String file) -> String' # TODO: return in set of strings
28
28
  RDL.type :File, 'self.grpowned?', '(String or IO file) -> %bool'
29
29
  RDL.type :File, 'self.identical?', '(String or IO file_1, String or IO file_2) -> %bool'
@@ -41,7 +41,7 @@ RDL.type :File, 'self.pipe?', '(String file) -> %bool'
41
41
  RDL.type :File, 'self.readable?', '(String file) -> %bool'
42
42
  RDL.type :File, 'self.readable_real?', '(String file) -> %bool'
43
43
  RDL.type :File, 'self.readlink', '(String link) -> String file'
44
- RDL.type :File, 'self.readldirpath', '(String pathname, ?String dir) -> String real_pathname'
44
+ RDL.type :File, 'self.realdirpath', '(String pathname, ?String dir) -> String real_pathname'
45
45
  RDL.type :File, 'self.realpath', '(String pathname, ?String dir) -> String real_pathname'
46
46
  RDL.type :File, 'self.rename', '(String old, String new) -> 0'
47
47
  RDL.type :File, 'self.setgid?', '(String file) -> %bool'
@@ -56,7 +56,7 @@ RDL.type :File, 'self.symlink', '(String old, String new) -> 0'
56
56
  RDL.type :File, 'self.symlink?', '(String file) -> %bool'
57
57
  RDL.type :File, 'self.truncate', '(String file, Integer) -> 0'
58
58
  RDL.type :File, 'self.umask', '(?Integer) -> Integer'
59
- RDL.rdl_alias :File, :unlink, :delete
59
+ RDL.rdl_alias :File, :'self.unlink', :'self.delete'
60
60
  RDL.type :File, 'self.utime', '(Time atime, Time mtime, *String files) -> Integer'
61
61
  RDL.type :File, 'self.world_readable?', '(String or IO file) -> Integer or nil'
62
62
  RDL.type :File, 'self.world_writable?', '(String or IO file) -> Integer or nil'
@@ -105,7 +105,7 @@ RDL.type :'File::Stat', :mode, '() -> Integer'
105
105
  RDL.type :'File::Stat', :mtime, '() -> Time'
106
106
  RDL.type :'File::Stat', :nlink, '() -> Integer'
107
107
  RDL.type :'File::Stat', :owned?, '() -> %bool'
108
- RDL.type :'File::Stat', :pip?, '() -> %bool'
108
+ RDL.type :'File::Stat', :pipe?, '() -> %bool'
109
109
  RDL.type :'File::Stat', :rdev, '() -> Integer or nil'
110
110
  RDL.type :'File::Stat', :rdev_major, '() -> Integer'
111
111
  RDL.type :'File::Stat', :rdev_minor, '() -> Integer'
@@ -1,5 +1,208 @@
1
1
  RDL.nowrap :Float
2
2
 
3
+ RDL.type :Float, :%, '(Integer x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :%, "Float")``'
4
+ RDL.type :Float, :%, '(Float x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :%, "Float")``'
5
+ RDL.type :Float, :%, '(Rational x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :%, "Float")``'
6
+ RDL.type :Float, :%, '(BigDecimal x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :%, "BigDecimal")``'
7
+
8
+ RDL.type :Float, :*, '(Integer) -> ``sing_or_type(trec, targs, :*, "Float")``'
9
+ RDL.type :Float, :*, '(Float) -> ``sing_or_type(trec, targs, :*, "Float")``'
10
+ RDL.type :Float, :*, '(Rational) -> ``sing_or_type(trec, targs, :*, "Float")``'
11
+ RDL.type :Float, :*, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :*, "BigDecimal")``'
12
+ RDL.type :Float, :*, '(Complex) -> ``sing_or_type(trec, targs, :*, "Complex")``'
13
+ RDL.pre(:Float, :*) { |x| if (x.real.is_a?(BigDecimal)||x.imaginary.is_a?(BigDecimal)) then (if x.real.is_a?(Float) then (x.real!=Float::INFINITY && !(x.real.nan?)) elsif(x.imaginary.is_a?(Float)) then x.imaginary!=Float::INFINITY && !(x.imaginary.nan?) else true end) && self!=Float::INFINITY && !(self.nan?) else true end} #can't have a complex with part BigDecimal, other part infinity/NAN
14
+
15
+ RDL.type :Float, :**, '(Integer) -> ``sing_or_type(trec, targs, :**, "Float")``'
16
+ RDL.type :Float, :**, '(Float) -> ``sing_or_type(trec, targs, :**, "%numeric")``'
17
+ RDL.type :Float, :**, '(Rational) -> ``sing_or_type(trec, targs, :**, "%numeric")``'
18
+ RDL.type :Float, :**, '(BigDecimal) -> ``sing_or_type(trec, targs, :**, "BigDecimal")``'
19
+ RDL.pre(:Float, :**) { |x| x!=BigDecimal::INFINITY && if self<0 then x<=-1||x>=0 else true end}
20
+ RDL.post(:Float, :**) { |x| x.real?}
21
+ RDL.type :Float, :**, '(Complex) -> ``sing_or_type(trec, targs, :**, "Complex")``'
22
+ RDL.pre(:Float, :**) { |x| x != 0 && if (x.real.is_a?(BigDecimal)||x.imaginary.is_a?(BigDecimal)) then (if x.real.is_a?(Float) then (x.real!=Float::INFINITY && !(x.real.nan?)) elsif(x.imaginary.is_a?(Float)) then x.imaginary!=Float::INFINITY && !(x.imaginary.nan?) else true end) && self!=Float::INFINITY && !(self.nan?) else true end}
23
+
24
+ RDL.type :Float, :+, '(Integer) -> ``sing_or_type(trec, targs, :+, "Float")``'
25
+ RDL.type :Float, :+, '(Float) -> ``sing_or_type(trec, targs, :+, "Float")``'
26
+ RDL.type :Float, :+, '(Rational) -> ``sing_or_type(trec, targs, :+, "Float")``'
27
+ RDL.type :Float, :+, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :+, "BigDecimal")``'
28
+ RDL.type :Float, :+, '(Complex) -> ``sing_or_type(trec, targs, :+, "Complex")``'
29
+ RDL.pre(:Float, :+) { |x| if x.real.is_a?(BigDecimal) then self!=Float::INFINITY && !(self.nan?) else true end}
30
+
31
+ RDL.type :Float, :-, '(Integer) -> ``sing_or_type(trec, targs, :-, "Float")``'
32
+ RDL.type :Float, :-, '(Float) -> ``sing_or_type(trec, targs, :-, "Float")``'
33
+ RDL.type :Float, :-, '(Rational) -> ``sing_or_type(trec, targs, :-, "Float")``'
34
+ RDL.type :Float, :-, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :-, "BigDecimal")``'
35
+ RDL.type :Float, :-, '(Complex) -> ``sing_or_type(trec, targs, :-, "Complex")``'
36
+ RDL.pre(:Float, :-) { |x| if x.real.is_a?(BigDecimal) then self!=Float::INFINITY && !(self.nan?) else true end}
37
+
38
+ RDL.type :Float, :-@, '() -> ``sing_or_type(trec, targs, :-@, "Float")``'
39
+
40
+ RDL.type :Float, :+@, '() -> ``sing_or_type(trec, targs, :+@, "Float")``'
41
+
42
+ RDL.type :Float, :/, '(Integer x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :/, "Float")``'
43
+ RDL.type :Float, :/, '(Float x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :/, "Float")``'
44
+ RDL.type :Float, :/, '(Rational x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :/, "Float")``'
45
+ RDL.type :Float, :/, '(BigDecimal x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :/, "BigDecimal")``'
46
+ RDL.type :Float, :/, '(Complex x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :/, "Complex")``'
47
+ RDL.pre(:Float, :/) { |x| if (x.real.is_a?(BigDecimal)||x.imaginary.is_a?(BigDecimal)) then (if x.real.is_a?(Float) then (x.real!=Float::INFINITY && !(x.real.nan?)) elsif(x.imaginary.is_a?(Float)) then x.imaginary!=Float::INFINITY && !(x.imaginary.nan?) else true end) && self!=Float::INFINITY && !(self.nan?) else true end && if (x.real.is_a?(Rational) && x.imaginary.is_a?(Float)) then !x.imaginary.nan? else true end}
48
+
49
+ RDL.type :Float, :<, '(Integer) -> ``sing_or_type(trec, targs, :<, "%bool")``'
50
+ RDL.type :Float, :<, '(Float) -> ``sing_or_type(trec, targs, :<, "%bool")``'
51
+ RDL.type :Float, :<, '(Rational) -> ``sing_or_type(trec, targs, :<, "%bool")``'
52
+ RDL.type :Float, :<, '(BigDecimal x {{ !self.nan? && !self.infinite? }}) -> ``sing_or_type(trec, targs, :<, "%bool")``'
53
+
54
+ RDL.type :Float, :<=, '(Integer) -> ``sing_or_type(trec, targs, :<=, "%bool")``'
55
+ RDL.type :Float, :<=, '(Float) -> ``sing_or_type(trec, targs, :<=, "%bool")``'
56
+ RDL.type :Float, :<=, '(Rational) -> ``sing_or_type(trec, targs, :<=, "%bool")``'
57
+ RDL.type :Float, :<=, '(BigDecimal x {{ !self.nan? && !self.infinite? }}) -> ``sing_or_type(trec, targs, :<=, "%bool")``'
58
+
59
+ RDL.type :Float, :<=>, '(Integer) -> ``sing_or_type(trec, targs, :<=>, "Integer")``'
60
+ RDL.post(:Float, :<=>) { |x| x == -1 || x==0 || x==1}
61
+ RDL.type :Float, :<=>, '(Float) -> ``sing_or_type(trec, targs, :<=>, "Integer")``'
62
+ RDL.post(:Float, :<=>) { |x| x == -1 || x==0 || x==1}
63
+ RDL.type :Float, :<=>, '(Rational) -> ``sing_or_type(trec, targs, :<=>, "Integer")``'
64
+ RDL.post(:Float, :<=>) { |x| x == -1 || x==0 || x==1}
65
+ RDL.type :Float, :<=>, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :<=>, "Integer")``'
66
+ RDL.post(:Float, :<=>) { |x| x == -1 || x==0 || x==1}
67
+
68
+ RDL.type :Float, :==, '(Object) -> ``sing_or_type(trec, targs, :==, "%bool")``'
69
+ RDL.pre(:Float, :==) { |x| if (x.is_a?(BigDecimal)) then (!self.nan? && self!=Float::INFINITY) else true end}
70
+
71
+ RDL.type :Float, :===, '(Object) -> ``sing_or_type(trec, targs, :===, "%bool")``'
72
+ RDL.pre(:Float, :===) { |x| if (x.is_a?(BigDecimal)) then (!self.nan? && self!=Float::INFINITY) else true end}
73
+
74
+ RDL.type :Float, :>, '(Integer) -> ``sing_or_type(trec, targs, :>, "%bool")``'
75
+ RDL.type :Float, :>, '(Float) -> ``sing_or_type(trec, targs, :>, "%bool")``'
76
+ RDL.type :Float, :>, '(Rational) -> ``sing_or_type(trec, targs, :>, "%bool")``'
77
+ RDL.type :Float, :>, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :>, "%bool")``'
78
+
79
+ RDL.type :Float, :>=, '(Integer) -> ``sing_or_type(trec, targs, :>=, "%bool")``'
80
+ RDL.type :Float, :>=, '(Float) -> ``sing_or_type(trec, targs, :>=, "%bool")``'
81
+ RDL.type :Float, :>=, '(Rational) -> ``sing_or_type(trec, targs, :>=, "%bool")``'
82
+ RDL.type :Float, :>=, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :>=, "%bool")``'
83
+
84
+ RDL.type :Float, :abs, '() -> Float r {{ r>=0 || (if self.nan? then r.nan? end) }}' ## TODO
85
+
86
+ RDL.type :Float, :abs2, '() -> Float r {{ r>=0 || (if self.nan? then r.nan? end) }}' ## TODO
87
+
88
+ RDL.type :Float, :div, '(Integer x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :div, "Integer")``'
89
+ RDL.type :Float, :div, '(Float x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :div, "Integer")``'
90
+ RDL.type :Float, :div, '(Rational x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :div, "Integer")``'
91
+ RDL.type :Float, :div, '(BigDecimal x {{ x != 0 && !x.nan? && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :div, "Integer")``'
92
+
93
+ RDL.type :Float, :divmod, '(%real) -> [%real, %real]'
94
+ RDL.pre(:Float, :divmod) { |x| x != 0 && if x.is_a?(Float) then !x.nan? else true end && self!=Float::INFINITY && !self.nan?}
95
+
96
+ RDL.type :Float, :angle, '() -> ``sing_or_type(trec, targs, :angle, "%numeric")``'
97
+ RDL.post(:Float, :angle) { |r,x| r == 0 || r == Math::PI || r == Float::NAN}
98
+
99
+ RDL.type :Float, :arg, '() -> ``sing_or_type(trec, targs, :rg, "%numeric")``'
100
+ RDL.post(:Float, :arg) { |r,x| r == 0 || r == Math::PI || r == Float::NAN}
101
+
102
+ RDL.type :Float, :ceil, '() -> ``sing_or_type(trec, targs, :ceil, "Integer")``'
103
+ RDL.pre(:Float, :ceil) { !self.infinite? && !self.nan?}
104
+
105
+ RDL.type :Float, :coerce, '(%real) -> [Float, Float]'
106
+
107
+ RDL.type :Float, :denominator, '() -> Integer r {{ r>0 }}' ## TODO
108
+
109
+ RDL.type :Float, :equal?, '(Object) -> ``sing_or_type(trec, targs, :equal?, "%bool")``'
110
+
111
+ RDL.type :Float, :eql?, '(Object) -> ``sing_or_type(trec, targs, :eql?, "%bool")``'
112
+
113
+ RDL.type :Float, :fdiv, '(Integer) -> ``sing_or_type(trec, targs, :fdiv, "Float")``'
114
+ RDL.type :Float, :fdiv, '(Float) -> ``sing_or_type(trec, targs, :fdiv, "Float")``'
115
+ RDL.type :Float, :fdiv, '(Rational) -> ``sing_or_type(trec, targs, :fdiv, "Float")``'
116
+ RDL.type :Float, :fdiv, '(BigDecimal x {{ !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :fdiv, "BigDecimal")``'
117
+ RDL.type :Float, :fdiv, '(Complex) -> ``sing_or_type(trec, targs, :fdiv, "Complex")``'
118
+ RDL.pre(:Float, :fdiv) { |x| x != 0 && if (x.real.is_a?(BigDecimal)||x.imaginary.is_a?(BigDecimal)) then (if x.real.is_a?(Float) then (x.real!=Float::INFINITY && !(x.real.nan?)) elsif(x.imaginary.is_a?(Float)) then x.imaginary!=Float::INFINITY && !(x.imaginary.nan?) else true end) && self!=Float::INFINITY && !(self.nan?) else true end && if (x.real.is_a?(Rational) && x.imaginary.is_a?(Float)) then !x.imaginary.nan? else true end}
119
+
120
+ RDL.type :Float, :finite?, '() -> ``sing_or_type(trec, targs, :finite?, "%bool")``'
121
+
122
+ RDL.type :Float, :floor, '() -> ``sing_or_type(trec, targs, :floor, "Integer")``'
123
+ RDL.pre(:Float, :ceil) { !self.infinite? && !self.nan?}
124
+
125
+ RDL.type :Float, :hash, '() -> Integer'
126
+
127
+ RDL.type :Float, :infinite?, '() -> ``sing_or_type(trec, targs, :infinite?, "Integer")``'
128
+ RDL.post(:Float, :infinite?) { |r,x| r == -1 || r == 1 || r == nil }
129
+
130
+ RDL.type :Float, :to_s, '() -> String'
131
+ RDL.type :Float, :inspect, '() -> String'
132
+
133
+ RDL.type :Float, :magnitude, '() -> ``sing_or_type(trec, targs, :magnitude, "Float")``'
134
+ RDL.post(:Float, :magnitude) { |r,x| r>=0 }
135
+
136
+ RDL.type :Float, :modulo, '(Integer x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :modulo, "Float")``'
137
+ RDL.type :Float, :modulo, '(Float x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :modulo, "Float")``'
138
+ RDL.type :Float, :modulo, '(Rational x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :modulo, "Float")``'
139
+ RDL.type :Float, :modulo, '(BigDecimal x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :modulo, "BigDecimal")``'
140
+
141
+ RDL.type :Float, :nan?, '() -> ``sing_or_type(trec, targs, :nan?, "%bool")``'
142
+
143
+ RDL.type :Float, :next_float, '() -> ``sing_or_type(trec, targs, :next_float, "Float")``'
144
+
145
+ RDL.type :Float, :numerator, '() -> ``sing_or_type(trec, targs, :numerator, "Integer")``'
146
+
147
+ RDL.type :Float, :phase, '() -> ``sing_or_type(trec, targs, :phase, "%numeric")``'
148
+ RDL.post(:Float, :phase) { |r,x| r == 0 || r == Math::PI || r == Float::NAN}
149
+
150
+ RDL.type :Float, :prev_float, '() -> ``sing_or_type(trec, targs, :prev_float, "Float")``'
151
+
152
+ RDL.type :Float, :quo, '(Integer x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :quo, "Float")``'
153
+ RDL.type :Float, :quo, '(Float x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :quo, "Float")``'
154
+ RDL.type :Float, :quo, '(Rational x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :quo, "Float")``'
155
+ RDL.type :Float, :quo, '(BigDecimal x {{ x != 0 && !self.infinite? && !self.nan? }}) -> ``sing_or_type(trec, targs, :quo, "BigDecimal")``'
156
+ RDL.type :Float, :quo, '(Complex x {{ x != 0 }}) -> ``sing_or_type(trec, targs, :quo, "Complex")``'
157
+ RDL.pre(:Float, :quo) { |x| if (x.real.is_a?(BigDecimal)||x.imaginary.is_a?(BigDecimal)) then (if x.real.is_a?(Float) then (x.real!=Float::INFINITY && !(x.real.nan?)) elsif(x.imaginary.is_a?(Float)) then x.imaginary!=Float::INFINITY && !(x.imaginary.nan?) else true end) && self!=Float::INFINITY && !(self.nan?) else true end && if (x.real.is_a?(Rational) && x.imaginary.is_a?(Float)) then !x.imaginary.nan? else true end}
158
+
159
+ RDL.type :Float, :rationalize, '() -> ``sing_or_type(trec, targs, :rationalize, "Rational")``'
160
+ RDL.pre(:Float, :rationalize) { !self.infinite? && !self.nan?}
161
+
162
+ RDL.type :Float, :rationalize, '(%numeric) -> ``sing_or_type(trec, targs, :rationalize, "Rational")``'
163
+ RDL.pre(:Float, :rationalize) { |x| if x.is_a?(Float) then x!=Float::INFINITY && !x.nan? else true end}
164
+
165
+ RDL.type :Float, :round, '() -> ``sing_or_type(trec, targs, :round, "Integer")``'
166
+ RDL.pre(:Float, :round) { !self.infinite? && !self.nan?}
167
+
168
+ RDL.type :Float, :round, '(%numeric) -> ``sing_or_type(trec, targs, :round, "%numeric")``'
169
+ RDL.pre(:Float, :round) { |x| x != 0 && if x.is_a?(Complex) then x.imaginary==0 && (if x.real.is_a?(Float)||x.real.is_a?(BigDecimal) then !x.real.infinite? && !x.real.nan? else true end) elsif x.is_a?(Float) then x!=Float::INFINITY && !x.nan? elsif x.is_a?(BigDecimal) then x!=BigDecimal::INFINITY && !x.nan? else true end} #Also, x must be in range [-2**31, 2**31].
170
+
171
+ RDL.type :Float, :to_f, '() -> self'
172
+
173
+ RDL.type :Float, :to_i, '() -> ``sing_or_type(trec, targs, :to_i, "Integer")``'
174
+ RDL.pre(:Float, :to_i) { !self.infinite? && !self.nan?}
175
+
176
+ RDL.type :Float, :to_int, '() -> ``sing_or_type(trec, targs, :to_int, "Integer")``'
177
+ RDL.pre(:Float, :to_int) { !self.infinite? && !self.nan?}
178
+
179
+ RDL.type :Float, :to_r, '() -> ``sing_or_type(trec, targs, :to_r, "Rational")``'
180
+ RDL.pre(:Float, :to_r) { !self.infinite? && !self.nan?}
181
+
182
+ RDL.type :Float, :truncate, '() -> ``sing_or_type(trec, targs, :truncate, "Integer")``'
183
+
184
+ RDL.type :Float, :zero?, '() -> ``sing_or_type(trec, targs, :zero, "%bool")``'
185
+
186
+ RDL.type :Float, :conj, '() -> ``sing_or_type(trec, targs, :conj, "Float")``'
187
+ RDL.type :Float, :conjugate, '() -> ``sing_or_type(trec, targs, :conjugate, "Float")``'
188
+
189
+ RDL.type :Float, :imag, '() -> Integer r {{ r==0 }}' ## TODO
190
+ RDL.type :Float, :imaginary, '() -> Integer r {{ r==0 }}' ## TODO
191
+
192
+ RDL.type :Float, :real, '() -> ``sing_or_type(trec, targs, :real, "Float")``'
193
+
194
+ RDL.type :Float, :real?, '() -> ``sing_or_type(trec, targs, :real?, "%bool")``'
195
+
196
+ RDL.type :Float, :to_c, '() -> Complex r {{ r.imaginary == 0 }}' ## TODO
197
+
198
+ RDL.type :Float, :coerce, '(%numeric) -> [Float, Float]'
199
+ RDL.pre(:Float, :coerce) { |x| if x.is_a?(Complex) then x.imaginary==0 else true end}
200
+
201
+
202
+
203
+ ######### Non-dependent types below #########
204
+
205
+
3
206
  RDL.type :Float, :%, '(Integer x {{ x != 0 }}) -> Float'
4
207
  RDL.type :Float, :%, '(Float x {{ x != 0 }}) -> Float'
5
208
  RDL.type :Float, :%, '(Rational x {{ x != 0 }}) -> Float'
@@ -2,14 +2,386 @@ RDL.nowrap :Hash
2
2
 
3
3
  RDL.type_params :Hash, [:k, :v], :all?
4
4
 
5
- RDL.type :Hash, 'self.[]', '(*u) -> Hash<u, u>' # example: Hash[1,2,3,4]
6
- RDL.type :Hash, 'self.[]', '(Array<[a,b]>) -> Hash<a, b>'
7
- RDL.type :Hash, 'self.[]', '([to_hash: () -> Hash<a, b>]) -> Hash<a, b>'
5
+ def Hash.output_type(trec, targs, meth_name, default1, default2=default1, nil_default: false, use_sing_val: true)
6
+ case trec
7
+ when RDL::Type::FiniteHashType
8
+ if targs.empty? || targs.all? { |t| t.is_a?(RDL::Type::SingletonType) }
9
+ vals = RDL.type_cast((if use_sing_val then targs.map { |t| RDL.type_cast(t, "RDL::Type::SingletonType").val } else targs end), "Array<%any>", force: true)
10
+ res = RDL.type_cast(trec.elts.send(meth_name, *vals), "Object", force: true)
11
+ if nil_default && res.nil?
12
+ if default1 == :promoted_val
13
+ return trec.promote.params[1]
14
+ elsif default1 == :promoted_key
15
+ return trec.promote.params[0]
16
+ else
17
+ return RDL::Globals.parser.scan_str "#T #{default1}"
18
+ end
19
+ end
20
+ to_type(res)
21
+ else
22
+ if default1 == :promoted_val
23
+ x = trec.promote.params[1]
24
+ return x
25
+ elsif default1 == :promoted_key
26
+ return trec.promote.params[0]
27
+ else
28
+ RDL::Globals.parser.scan_str "#T #{default1}"
29
+ end
30
+ end
31
+ else
32
+ RDL::Globals.parser.scan_str "#T #{default2}"
33
+ end
34
+ end
35
+ RDL.type Hash, 'self.output_type', "(RDL::Type::Type, Array<RDL::Type::Type>, Symbol, Symbol or String, ?(Symbol or String), { nil_default: ?%bool, use_sing_val: ?%bool } ) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
36
+
37
+
38
+ def Hash.to_type(t)
39
+ case t
40
+ when RDL::Type::Type
41
+ t
42
+ when Array
43
+ RDL::Type::TupleType.new(*(t.map { |i| to_type(i) }))
44
+ else
45
+ ## symbols, ints, nil, ...
46
+ RDL::Type::SingletonType.new(t)
47
+ end
48
+ end
49
+ RDL.type Hash, 'self.to_type', "(%any) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
50
+
51
+ def Hash.any_or_k(trec)
52
+ case trec
53
+ when RDL::Type::FiniteHashType
54
+ RDL::Globals.types[:top]
55
+ else
56
+ RDL::Globals.parser.scan_str "#T k"
57
+ end
58
+ end
59
+ RDL.type Hash, 'self.any_or_k', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
60
+
61
+ def Hash.any_or_v(trec)
62
+ case trec
63
+ when RDL::Type::FiniteHashType
64
+ RDL::Globals.types[:top]
65
+ else
66
+ RDL::Globals.parser.scan_str "#T v"
67
+ end
68
+ end
69
+ RDL.type Hash, 'self.any_or_v', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
70
+
71
+ def Hash.promoted_or_v(trec)
72
+ case trec
73
+ when RDL::Type::FiniteHashType
74
+ trec.promote.params[1]
75
+ else
76
+ RDL::Globals.parser.scan_str "#T v"
77
+ end
78
+ end
79
+ RDL.type Hash, 'self.promoted_or_v', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
80
+
81
+
82
+ def Hash.weak_promote(val)
83
+ case val
84
+ when RDL::Type::UnionType
85
+ if val.types.all? { |t| t.is_a?(RDL::Type::SingletonType) }
86
+ klass = RDL.type_cast(val.types[0], "RDL::Type::SingletonType", force: true).nominal.klass
87
+ if val.types.all? { |t| RDL.type_cast(t, "RDL::Type::SingletonType", force: true).nominal.klass == klass }
88
+ return RDL::Type::NominalType.new(klass)
89
+ else
90
+ return val
91
+ end
92
+ else
93
+ return val
94
+ end
95
+ else
96
+ val
97
+ end
98
+ end
99
+ RDL.type Hash, 'self.weak_promote', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
100
+
101
+ #RDL.type :Hash, 'self.[]', '(*%any) -> ``hash_create_output_from_list(targs)``'
102
+ RDL.type :Hash, 'self.[]', '(*%any) -> ``hash_create_output(targs)``'
103
+
104
+ def Hash.hash_create_output_from_list(targs)
105
+ raise RDL::Typecheck::StaticTypeError, "Hash[...] expect only 1 argument. Have #{targs}." if targs.size > 1
106
+ raise RDL::Typecheck::StaticTypeError, "The argument has to be an array or tuple" unless (targs[0].is_a?(RDL::Type::GenericType) && targs[0].base.klass == Array)
107
+
108
+ case targs[0].params[0]
109
+ when RDL::Type::GenericType
110
+ return RDL::Globals.parser.scan_str "#T Hash<#{targs[0].params[0].params[0]}, #{targs[0].params[0].params[0]}>"
111
+ when RDL::Type::TupleType
112
+ return RDL::Type::GenericType.new(RDL::Type::NominalType.new(Hash), targs[0].params[0].params[0], targs[0].params[0].params[1])
113
+ end
114
+ end
115
+
116
+ def Hash.hash_create_output(targs)
117
+ return hash_create_output_from_list(targs) if targs.size == 1
118
+
119
+ raise RDL::Typecheck::StaticTypeError, "Hash.[] expects an even number of arguments. Have #{targs}." if targs.size.odd?
120
+ args = RDL.type_cast([], "Array<%any>", force: true)
121
+ i = -1
122
+ args = targs.map { |a| i = i+1 ; if i.even? && a.is_a?(RDL::Type::SingletonType) then RDL.type_cast(a, "RDL::Type::SingletonType", force: true).val else a end }
123
+ RDL::Type::FiniteHashType.new(RDL.type_cast(Hash[*args], "Hash<%any, RDL::Type::Type>", force: true), nil)
124
+ end
125
+ RDL.type Hash, 'self.hash_create_output', "(Array<RDL::Type::Type>) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
126
+
127
+ RDL.type :Hash, :[], '(``any_or_k(trec)``) -> ``output_type(trec, targs, :[], :promoted_val, "v", nil_default: true)``', effect: [:+, :+]
128
+
129
+ RDL.type :Hash, :[]=, '(``any_or_k(trec)``, ``any_or_v(trec)``) -> ``assign_output(trec, targs)``'
130
+
131
+
132
+ def Hash.assign_output(trec, targs)
133
+ case trec
134
+ when RDL::Type::FiniteHashType
135
+ case targs[0]
136
+ when RDL::Type::SingletonType ### TODO: adjust for strings
137
+ argval = RDL.type_cast(targs[0], "RDL::Type::SingletonType", force: true).val
138
+ trec.elts[argval] = RDL::Type::UnionType.new(trec.elts[argval], targs[1]).canonical
139
+ trec.elts[argval] = weak_promote(trec.elts[argval]) if RDL::Config.instance.weak_update_promote
140
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate hash: new hash does not match prior type constraints." unless trec.check_bounds(true)
141
+ return targs[1]
142
+ else
143
+ raise "Unable to promote tuple #{trec} to Hash." unless trec.promote!(targs[0], targs[1])
144
+ return targs[1]
145
+ end
146
+ else
147
+ RDL::Globals.parser.scan_str "#T v"
148
+ end
149
+ end
150
+ RDL.type Hash, 'self.assign_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:~, :+]
151
+
152
+ RDL.type :Hash, :store, '(``any_or_k(trec)``, ``any_or_v(trec)``) -> ``assign_output(trec, targs)``'
153
+ RDL.type :Hash, :assoc, '(``any_or_k(trec)``) -> ``RDL::Type::TupleType.new(targs[0], output_type(trec, targs, :[], :promoted_val, "v", nil_default: true))``'
154
+ RDL.type :Hash, :clear, '() -> self'
155
+ RDL.type :Hash, :compare_by_identity, '() -> self'
156
+ RDL.type :Hash, :compare_by_identity?, '() -> %bool'
157
+ RDL.type :Hash, :default, '() -> ``promoted_or_v(trec)``'
158
+ RDL.type :Hash, :default, '(``any_or_k(trec)``) -> ``promoted_or_v(trec)``'
159
+ RDL.type :Hash, :default=, '(``promoted_or_v(trec)``) -> ``promoted_or_v(trec)``'
160
+
161
+ RDL.type :Hash, :delete, '(``any_or_k(trec)``) -> ``delete_output(trec, targs, false)``'
162
+ RDL.type :Hash, :delete, '(``any_or_k(trec)``) { (``any_or_k(trec)``) -> u } -> ``delete_output(trec, targs, true)``'
163
+
164
+ def Hash.delete_output(trec, targs, block)
165
+ case trec
166
+ when RDL::Type::FiniteHashType
167
+ case targs[0]
168
+ when RDL::Type::SingletonType
169
+ argval = RDL.type_cast(targs[0], "RDL::Type::SingletonType", force: true).val
170
+ if trec.elts.include?(argval)
171
+ trec.elts[argval]
172
+ else
173
+ trec.promote.params[1]
174
+ end
175
+ else
176
+ if block
177
+ RDL::Type::UnionType.new(trec.promote.params[1], RDL::Globals.parser.scan_str("#T u"))
178
+ else
179
+ trec.promote.params[1]
180
+ end
181
+ end
182
+ else
183
+ t = (if block then "u or v" else "v" end)
184
+ RDL::Globals.parser.scan_str "#T #{t}"
185
+ end
186
+ end
187
+ RDL.type Hash, 'self.delete_output', "(RDL::Type::Type, Array<RDL::Type::Type>, %bool) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
188
+
189
+ RDL.type :Hash, :delete_if, '() { (``any_or_k(trec)``, ``any_or_v(trec)``) -> %any } -> self'
190
+ RDL.type :Hash, :delete_if, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), RDL::Type::TupleType.new(any_or_k(trec), any_or_v(trec)))``' ## I had made a mistake here, type checker caught it.
191
+ RDL.type :Hash, :each, '() { (``any_or_k(trec)``, ``any_or_v(trec)``) -> %any } -> self'
192
+ RDL.type :Hash, :each, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), RDL::Type::TupleType.new(any_or_k(trec), any_or_v(trec)))``' ## I had made a mistake here, type checker caught it.
193
+ RDL.type :Hash, :each_pair, '() { (``any_or_k(trec)``, ``any_or_v(trec)``) -> %any } -> self'
194
+ RDL.type :Hash, :each_pair, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), RDL::Type::TupleType.new(any_or_k(trec), any_or_v(trec)))``' ## I had made a mistake here, type checker caught it.
195
+ RDL.type :Hash, :each_key, '() { (``any_or_k(trec)``) -> %any } -> self'
196
+ RDL.type :Hash, :each_key, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), any_or_k(trec))``'
197
+ RDL.type :Hash, :each_value, '() { (``any_or_v(trec)``) -> %any } -> self'
198
+ RDL.type :Hash, :each_value, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), any_or_v(trec))``'
199
+ RDL.type :Hash, :empty?, '() -> ``output_type(trec, targs, :empty?, "%bool")``'
200
+ RDL.type :Hash, :fetch, '(``any_or_k(trec)``) -> ``output_type(trec, targs, :fetch, :promoted_val, "v", nil_default: true)``'
201
+ RDL.type :Hash, :fetch, '(``any_or_k(trec)``, u) -> ``RDL::Type::UnionType.new(RDL::Globals.parser.scan_str("u"), output_type(trec, targs, :fetch, :promoted_val, "v", nil_default: true))``'
202
+ RDL.type :Hash, :fetch, '(``any_or_k(trec)``) { (``any_or_k(trec)``) -> u } -> ``RDL::Type::UnionType.new(RDL::Globals.parser.scan_str("u"), output_type(trec, targs, :fetch, :promoted_val, "v", nil_default: true))``'
203
+ RDL.type :Hash, :member?, '(%any) -> ``output_type(trec, targs, :member?, "%bool")``'
204
+ RDL.type :Hash, :has_key?, '(%any) -> ``output_type(trec, targs, :has_key?, "%bool")``', effect: [:+, :+]
205
+ RDL.type :Hash, :key?, '(%any) -> ``output_type(trec, targs, :key?, "%bool")``'
206
+ RDL.type :Hash, :has_value?, '(%any) -> ``output_type(trec, targs, :has_value?, "%bool")``'
207
+ RDL.type :Hash, :value?, '(%any) -> ``output_type(trec, targs, :value?, "%bool")``'
208
+ RDL.type :Hash, :to_s, '() -> String'
209
+ RDL.type :Hash, :inspect, '() -> String'
210
+ RDL.type :Hash, :invert, '() -> ``invert_output(trec)``'
211
+
212
+
213
+ def Hash.invert_output(trec)
214
+ case trec
215
+ when RDL::Type::FiniteHashType
216
+ hash = trec.elts.invert
217
+ hash = Hash[hash.map { |k, v| if !RDL.type_cast(v, "Object", force: true).is_a?(RDL::Type::Type) then [k, RDL::Type::SingletonType.new(v)] else [k, v] end }]
218
+ RDL::Type::FiniteHashType.new(RDL.type_cast(hash, "Hash<%any, RDL::Type::Type>", force: true), nil)
219
+ else
220
+ RDL::Globals.parser.scan_str "#T Hash<v, k>"
221
+ end
222
+ end
223
+ RDL.type Hash, 'self.invert_output', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
224
+
225
+ RDL.type :Hash, :keep_if, '() { (``any_or_k(trec)``,``any_or_v(trec)``) -> %bool } -> self'
226
+ RDL.type :Hash, :keep_if, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), RDL::Type::TupleType.new(any_or_k(trec), any_or_v(trec)))``' ## I had made a mistake here, type checker caught it.
227
+ RDL.type :Hash, :key, '(%any) -> ``output_type(trec, targs, :key, :promoted_key, "k", nil_default: true, use_sing_val: false)``'
228
+ RDL.type :Hash, :keys, '() -> ``output_type(trec, targs, :keys, "Array<k>")``'
229
+ RDL.type :Hash, :length, '() -> ``output_type(trec, targs, :length, "Integer")``'
230
+ RDL.type :Hash, :size, '() -> ``output_type(trec, targs, :size, "Integer")``'
231
+ RDL.type :Hash, :merge, '(``merge_input(targs)``) -> ``merge_output(trec, targs)``'
232
+ RDL.type :Hash, :merge!, '(``merge_input(targs, true)``) -> ``merge_output(trec, targs, true)``'
233
+
234
+
235
+ def Hash.merge_input(targs, mutate=false)
236
+ case targs[0]
237
+ when RDL::Type::FiniteHashType
238
+ return targs[0]
239
+ when RDL::Type::GenericType
240
+ if mutate
241
+ return RDL::Globals.parser.scan_str "#T Hash<k, v>"
242
+ else
243
+ return RDL::Globals.parser.scan_str "#T Hash<a, b>"
244
+ end
245
+ else
246
+ RDL::Globals.types[:hash]
247
+ end
248
+ end
249
+ RDL.type Hash, 'self.merge_input', "(Array<RDL::Type::Type>, ?%bool) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
250
+
251
+
252
+ def Hash.merge_output(trec, targs, mutate=false)
253
+ case trec
254
+ when RDL::Type::NominalType
255
+ return RDL::Globals.types[:hash]
256
+ when RDL::Type::GenericType
257
+ case targs[0]
258
+ when RDL::Type::FiniteHashType
259
+ promoted = RDL.type_cast(targs[0], "RDL::Type::FiniteHashType", force: true).promote
260
+ key_union = RDL::Type::UnionType.new(promoted.params[0], trec.params[0]).canonical
261
+ value_union = RDL::Type::UnionType.new(promoted.params[1], trec.params[1]).canonical
262
+ if mutate
263
+ raise "Call to `merge!` would change type of Hash." unless (key_union == trec.params[0]) && (value_union == trec.params[1])
264
+ return trec
265
+ else
266
+ return RDL::Type::GenericType.new(trec.base, key_union, value_union)
267
+ end
268
+ when RDL::Type::GenericType
269
+ ret = (if mutate then "Hash<k, v>" else "Hash<a or k, b or v>" end)
270
+ return RDL::Globals.parser.scan_str "#T #{ret}"
271
+ else
272
+ ## targs[0] should just be hash here
273
+ return RDL::Globals.types[:hash]
274
+ end
275
+ when RDL::Type::FiniteHashType
276
+ case targs[0]
277
+ when RDL::Type::FiniteHashType
278
+ arg = RDL.type_cast(targs[0], "RDL::Type::FiniteHashType", force: true)
279
+ if mutate
280
+ if arg.elts.any? { |k, v| !RDL.type_cast(k, "Object", force: true).is_a?(Symbol) }
281
+ arg_key = arg.promote.params[0]
282
+ arg_val = arg.promote.params[1]
283
+ raise "Unable to promote tuple #{trec} to Hash." unless trec.promote!(arg_key, arg_val)
284
+ return trec
285
+ end
286
+ trec.elts = RDL.type_cast(Hash[trec.elts.map { |k, v| if arg.elts.has_key?(k) then [k, RDL::Type::UnionType.new(arg.elts[k], v).canonical] else [k, v] end } ].merge(arg.elts), "Hash<%any, RDL::Type::Type>", force: true)
287
+ raise RDL::Typecheck::StaticTypeError, "Failed to mutate hash: new hash does not match prior type constraints." unless trec.check_bounds(true)
288
+ return trec
289
+ else
290
+ return RDL::Type::FiniteHashType.new(trec.elts.merge(arg.elts), nil)
291
+ end
292
+ when RDL::Type::GenericType
293
+ arg0 = RDL.type_cast(targs[0], "RDL::Type::GenericType", force: true)
294
+ promoted = trec.promote
295
+ key_union = RDL::Type::UnionType.new(promoted.params[0], arg0.params[0]).canonical
296
+ value_union = RDL::Type::UnionType.new(promoted.params[1], arg0.params[1]).canonical
297
+ if mutate
298
+ raise "Unable to promote tuple #{trec} to Hash." unless trec.promote!(arg0.params[0], arg0.params[1])
299
+ return trec
300
+ else
301
+ return RDL::Type::GenericType.new(arg0.base, key_union, value_union)
302
+ end
303
+ else
304
+ ## targs[0] should just be Hash here
305
+ return RDL::Globals.types[:hash]
306
+ end
307
+ end
308
+
309
+ end
310
+ RDL.type Hash, 'self.merge_output', "(RDL::Type::Type, Array<RDL::Type::Type>, ?%bool) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:~, :+]
311
+
312
+ RDL.type :Hash, :merge, '(Hash<a,b>) { (k,v,b) -> v or b } -> Hash<a or k, b or v>'
313
+ RDL.type :Hash, :rassoc, '(``any_or_v(trec)``) -> ``RDL::Type::TupleType.new(output_type(trec, targs, :key, :promoted_key, "k", nil_default: true, use_sing_val: false),targs[0])``'
314
+ RDL.type :Hash, :rehash, '() -> self'
315
+ RDL.type :Hash, :reject, '() -> ``RDL::Type::GenericType.new(RDL::Type::NominalType.new(Enumerator), any_or_k(trec), any_or_v(trec))``'
316
+ RDL.type :Hash, :reject, '() {(``any_or_k(trec)``,``any_or_v(trec)``) -> %bool} -> self'
317
+ RDL.type :Hash, :reject!, '() {(``any_or_k(trec)``,``any_or_v(trec)``) -> %bool} -> self'
318
+ RDL.type :Hash, :select, '() {(``any_or_k(trec)``,``any_or_v(trec)``) -> %bool} -> self'
319
+ RDL.type :Hash, :select!, '() {(``any_or_k(trec)``,``any_or_v(trec)``) -> %bool} -> self'
320
+ RDL.type :Hash, :shift, '() -> ``shift_output(trec)``'
321
+
322
+
323
+ def Hash.shift_output(trec)
324
+ case trec
325
+ when RDL::Type::FiniteHashType
326
+ promoted = trec.promote
327
+ RDL::Type::TupleType.new(*promoted.params) ## Type error found by type checker here.
328
+ else
329
+ RDL::Globals.parser.scan_str "#T [k, v]"
330
+ end
331
+ end
332
+ RDL.type Hash, 'self.shift_output', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:+, :+]
333
+
334
+ RDL.type :Hash, :to_a, '() -> ``output_type(trec, targs, :to_a, "Array<[k, v]>")``'
335
+ RDL.type :Hash, :to_hash, '() -> self'
336
+ RDL.type :Hash, :values, '() -> ``output_type(trec, targs, :values, "Array<v>")``'
337
+ RDL.type :Hash, :values_at, '(``values_at_input(trec)``) -> ``values_at_output(trec, targs)``'
338
+
339
+
340
+ def Hash.values_at_input(trec)
341
+ case trec
342
+ when RDL::Type::FiniteHashType
343
+ RDL::Type::VarargType.new(RDL::Globals.types[:top])
344
+ else
345
+ RDL::Type::VarargType.new(RDL::Type::VarType.new("k"))
346
+ end
347
+ end
348
+ RDL.type Hash, 'self.values_at_input', "(RDL::Type::Type) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:~, :+]
349
+
350
+
351
+ def Hash.values_at_output(trec, targs)
352
+ case trec
353
+ when RDL::Type::FiniteHashType
354
+ if targs.all? { |t| t.is_a? RDL::Type::SingletonType }
355
+ res = trec.elts.values_at(*targs.map { |t| RDL.type_cast(t, "RDL::Type::SingletonType<%any>", force: true).val })
356
+ if res.all? { |t| !t.nil? }
357
+ to_type(res)
358
+ else
359
+ RDL::Type::GenericType.new(RDL::Type::NominalType.new(Array), trec.promote.params[1])
360
+ end
361
+ else
362
+ RDL::Type::GenericType.new(RDL::Type::NominalType.new(Array), trec.promote.params[1])
363
+ end
364
+ else
365
+ RDL::Globals.parser.scan_str "#T Array<v>"
366
+ end
367
+ end
368
+ RDL.type Hash, 'self.values_at_output', "(RDL::Type::Type, Array<RDL::Type::Type>) -> RDL::Type::Type", typecheck: :type_code, wrap: false, effect: [:~, :+]
369
+
370
+
371
+
372
+
373
+
374
+ ######### Non-dependent types below #########
375
+
376
+ RDL.type :Hash, 'self.[]', '(*u) -> Hash<u, u>', effect: [:+, :+] # example: Hash[1,2,3,4]
377
+ RDL.type :Hash, 'self.[]', '(Array<[a,b]>) -> Hash<a, b>', effect: [:+, :+]
378
+ RDL.type :Hash, 'self.[]', '([to_hash: () -> Hash<a, b>]) -> Hash<a, b>', effect: [:+, :+]
8
379
 
9
380
  RDL.type :Hash, :[], '(k) -> v'
10
- RDL.type :Hash, :[]=, '(k, v) -> v'
381
+ RDL.type :Hash, :[]=, '(k, v) -> v', effect: [:-, :+]
11
382
  RDL.type :Hash, :store, '(k,v) -> v'
12
383
 
384
+ RDL.type :Hash, :any?, "() { (k, v) -> %any } -> %bool", effect: [:blockdep, :blockdep]
13
385
  # RDL.type :Hash, :assoc, '(k) -> [k, v]' # TODO
14
386
  RDL.type :Hash, :assoc, '(k) -> Array<k or v>'
15
387
  RDL.type :Hash, :clear, '() -> Hash<k,v>'
@@ -27,41 +399,44 @@ RDL.type :Hash, :delete, '(k) -> v'
27
399
  RDL.type :Hash, :delete, '(k) { (k) -> u } -> u or v'
28
400
  RDL.type :Hash, :delete_if, '() { (k,v) -> %bool } -> Hash<k,v>'
29
401
  RDL.type :Hash, :delete_if, '() -> Enumerator<[k, v]>'
30
- RDL.type :Hash, :each, '() { (k,v) -> %any } -> Hash<k,v>'
31
- RDL.type :Hash, :each, '() -> Enumerator<[k, v]>'
402
+ RDL.type :Hash, :each, '() { (k,v) -> %any } -> Hash<k,v>', effect: [:blockdep, :blockdep]
403
+ RDL.type :Hash, :each, '() -> Enumerator<[k, v]>', effect: [:blockdep, :blockdep]
32
404
  RDL.type :Hash, :each_pair, '() { (k,v) -> %any } -> Hash<k,v>'
33
405
  RDL.type :Hash, :each_pair, '() -> Enumerator<[k, v]>'
34
- RDL.type :Hash, :each_key, '() { (k) -> %any } -> Hash<k,v>'
35
- RDL.type :Hash, :each_key, '() -> Enumerator<[k, v]>'
406
+ RDL.type :Hash, :each_key, '() { (k) -> %any } -> Hash<k,v>', effect: [:blockdep, :blockdep]
407
+ RDL.type :Hash, :each_key, '() -> Enumerator<[k, v]>', effect: [:blockdep, :blockdep]
36
408
  RDL.type :Hash, :each_value, '() { (v) -> %any } -> Hash<k,v>'
37
409
  RDL.type :Hash, :each_value, '() -> Enumerator<[k, v]>'
38
410
  RDL.type :Hash, :empty?, '() -> %bool'
411
+ RDL.type :Hash, :except, '(%any) -> self', effect: [:+, :+]
39
412
  RDL.type :Hash, :fetch, '(k) -> v'
40
413
  RDL.type :Hash, :fetch, '(k,u) -> u or v'
41
414
  RDL.type :Hash, :fetch, '(k) { (k) -> u } -> u or v'
415
+ RDL.type :Hash, :map, "() { (k, v) -> x } -> Array<x>", effect: [:+, :blockdep]
42
416
  RDL.type :Hash, :member?, '(t) -> %bool'
43
417
  RDL.type :Hash, :has_key?, '(t) -> %bool'
44
418
  RDL.type :Hash, :key?, '(t) -> %bool'
45
419
  RDL.type :Hash, :has_value?, '(t) -> %bool'
46
420
  RDL.type :Hash, :value?, '(t) -> %bool'
47
421
  RDL.type :Hash, :to_s, '() -> String'
422
+ RDL.type :Hash, :include?, '(%any) -> %bool', effect: [:+, :+]
48
423
  RDL.type :Hash, :inspect, '() -> String'
49
- RDL.type :Hash, :invert, '() -> Hash<v,k>'
424
+ RDL.type :Hash, :invert, '() -> Hash<v,k>', effect: [:+, :+]
50
425
  RDL.type :Hash, :keep_if, '() { (k,v) -> %bool } -> Hash<k,v>'
51
426
  RDL.type :Hash, :keep_if, '() -> Enumerator<[k, v]>'
52
427
  RDL.type :Hash, :key, '(t) -> k'
53
- RDL.type :Hash, :keys, '() -> Array<k>'
428
+ RDL.type :Hash, :keys, '() -> Array<k>', effect: [:+, :+]
54
429
  RDL.type :Hash, :length, '() -> Integer'
55
- RDL.type :Hash, :size, '() -> Integer'
56
- RDL.type :Hash, :merge, '(Hash<a,b>) -> Hash<a or k, b or v>'
57
- RDL.type :Hash, :merge, '(Hash<a,b>) { (k,v,b) -> v or b } -> Hash<a or k, b or v>'
430
+ RDL.type :Hash, :size, '() -> Integer', effect: [:+, :+]
431
+ RDL.type :Hash, :merge, '(Hash<a,b>) -> Hash<a or k, b or v>', effect: [:+, :+]
432
+ RDL.type :Hash, :merge, '(Hash<a,b>) { (k,v,b) -> v or b } -> Hash<a or k, b or v>', effect: [:+, :+]
58
433
  # RDL.type :Hash, :rassoc, '(k) -> Tuple<k,v>'
59
434
  RDL.type :Hash, :rassoc, '(k) -> Array<k or v>'
60
435
  RDL.type :Hash, :rehash, '() -> Hash<k,v>'
61
436
  RDL.type :Hash, :reject, '() -> Enumerator<[k, v]>'
62
437
  RDL.type :Hash, :reject, '() {(k,v) -> %bool} -> Hash<k,v>'
63
438
  RDL.type :Hash, :reject!, '() {(k,v) -> %bool} -> Hash<k,v>'
64
- RDL.type :Hash, :select, '() {(k,v) -> %bool} -> Hash<k,v>'
439
+ RDL.type :Hash, :select, '() {(k,v) -> %bool} -> Hash<k,v>', effect: [:+, :blockdep]
65
440
  RDL.type :Hash, :select!, '() {(k,v) -> %bool} -> Hash<k,v>'
66
441
  # RDL.type :Hash, :shift, '() -> Tuple<k,v>'
67
442
  RDL.type :Hash, :shift, '() -> Array<k or v>'
@@ -69,4 +444,4 @@ RDL.type :Hash, :shift, '() -> Array<k or v>'
69
444
  RDL.type :Hash, :to_a, '() -> Array<Array<k or v>>'
70
445
  RDL.type :Hash, :to_hash, '() -> Hash<k,v>'
71
446
  RDL.type :Hash, :values, '() -> Array<v>'
72
- RDL.type :Hash, :values_at, '(*k) -> Array<v>'
447
+ RDL.type :Hash, :values_at, '(*k) -> Array<v>', effect: [:+, :+]