sorbet-runtime 0.0.1.pre.prealpha → 0.4.4253

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 (69) hide show
  1. checksums.yaml +5 -5
  2. data/lib/sorbet-runtime.rb +100 -0
  3. data/lib/types/_types.rb +245 -0
  4. data/lib/types/abstract_utils.rb +50 -0
  5. data/lib/types/boolean.rb +8 -0
  6. data/lib/types/compatibility_patches.rb +37 -0
  7. data/lib/types/configuration.rb +368 -0
  8. data/lib/types/generic.rb +23 -0
  9. data/lib/types/helpers.rb +31 -0
  10. data/lib/types/interface_wrapper.rb +158 -0
  11. data/lib/types/private/abstract/data.rb +36 -0
  12. data/lib/types/private/abstract/declare.rb +39 -0
  13. data/lib/types/private/abstract/hooks.rb +43 -0
  14. data/lib/types/private/abstract/validate.rb +128 -0
  15. data/lib/types/private/casts.rb +22 -0
  16. data/lib/types/private/class_utils.rb +102 -0
  17. data/lib/types/private/decl_state.rb +18 -0
  18. data/lib/types/private/error_handler.rb +37 -0
  19. data/lib/types/private/methods/_methods.rb +344 -0
  20. data/lib/types/private/methods/call_validation.rb +1177 -0
  21. data/lib/types/private/methods/decl_builder.rb +275 -0
  22. data/lib/types/private/methods/modes.rb +18 -0
  23. data/lib/types/private/methods/signature.rb +196 -0
  24. data/lib/types/private/methods/signature_validation.rb +232 -0
  25. data/lib/types/private/mixins/mixins.rb +27 -0
  26. data/lib/types/private/runtime_levels.rb +41 -0
  27. data/lib/types/private/types/not_typed.rb +23 -0
  28. data/lib/types/private/types/string_holder.rb +26 -0
  29. data/lib/types/private/types/void.rb +33 -0
  30. data/lib/types/profile.rb +27 -0
  31. data/lib/types/props/_props.rb +165 -0
  32. data/lib/types/props/constructor.rb +20 -0
  33. data/lib/types/props/custom_type.rb +84 -0
  34. data/lib/types/props/decorator.rb +826 -0
  35. data/lib/types/props/errors.rb +8 -0
  36. data/lib/types/props/optional.rb +73 -0
  37. data/lib/types/props/plugin.rb +15 -0
  38. data/lib/types/props/pretty_printable.rb +106 -0
  39. data/lib/types/props/serializable.rb +376 -0
  40. data/lib/types/props/type_validation.rb +98 -0
  41. data/lib/types/props/utils.rb +49 -0
  42. data/lib/types/props/weak_constructor.rb +30 -0
  43. data/lib/types/runtime_profiled.rb +36 -0
  44. data/lib/types/sig.rb +28 -0
  45. data/lib/types/struct.rb +8 -0
  46. data/lib/types/types/base.rb +141 -0
  47. data/lib/types/types/class_of.rb +38 -0
  48. data/lib/types/types/enum.rb +42 -0
  49. data/lib/types/types/fixed_array.rb +60 -0
  50. data/lib/types/types/fixed_hash.rb +59 -0
  51. data/lib/types/types/intersection.rb +36 -0
  52. data/lib/types/types/noreturn.rb +25 -0
  53. data/lib/types/types/proc.rb +51 -0
  54. data/lib/types/types/self_type.rb +31 -0
  55. data/lib/types/types/simple.rb +33 -0
  56. data/lib/types/types/type_member.rb +7 -0
  57. data/lib/types/types/type_parameter.rb +23 -0
  58. data/lib/types/types/type_template.rb +7 -0
  59. data/lib/types/types/type_variable.rb +31 -0
  60. data/lib/types/types/typed_array.rb +20 -0
  61. data/lib/types/types/typed_enumerable.rb +141 -0
  62. data/lib/types/types/typed_enumerator.rb +22 -0
  63. data/lib/types/types/typed_hash.rb +29 -0
  64. data/lib/types/types/typed_range.rb +22 -0
  65. data/lib/types/types/typed_set.rb +22 -0
  66. data/lib/types/types/union.rb +59 -0
  67. data/lib/types/types/untyped.rb +25 -0
  68. data/lib/types/utils.rb +223 -0
  69. metadata +122 -15
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ # https://jira.corp.stripe.com/browse/RUBYPLAT-1107
3
+ # typed: false
4
+
5
+ module T::Types
6
+ # Takes a list of types. Validates each item in an array using the type in the same position
7
+ # in the list.
8
+ class FixedArray < Base
9
+ attr_reader :types
10
+
11
+ def initialize(types)
12
+ @types = types.map {|type| T::Utils.coerce(type)}
13
+ end
14
+
15
+ # @override Base
16
+ def name
17
+ "[#{@types.join(', ')}]"
18
+ end
19
+
20
+ # @override Base
21
+ def valid?(obj)
22
+ obj.is_a?(Array) && obj.length == @types.length &&
23
+ obj.zip(@types).all? {|item, type| type.valid?(item)}
24
+ end
25
+
26
+ # @override Base
27
+ private def subtype_of_single?(other)
28
+ case other
29
+ when FixedArray
30
+ # Properly speaking, covariance here is unsound since arrays
31
+ # can be mutated, but sorbet implements covariant tuples for
32
+ # ease of adoption.
33
+ @types.size == other.types.size && @types.zip(other.types).all? do |t1, t2|
34
+ t1.subtype_of?(t2)
35
+ end
36
+ else
37
+ false
38
+ end
39
+ end
40
+
41
+ # This gives us better errors, e.g.:
42
+ # "Expected [String, Symbol], got [String, String]"
43
+ # instead of
44
+ # "Expected [String, Symbol], got Array".
45
+ #
46
+ # @override Base
47
+ def describe_obj(obj)
48
+ if obj.is_a?(Array)
49
+ if obj.length == @types.length
50
+ item_classes = obj.map(&:class).join(', ')
51
+ "type [#{item_classes}]"
52
+ else
53
+ "array of size #{obj.length}"
54
+ end
55
+ else
56
+ super
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Takes a hash of types. Validates each item in an hash using the type in the same position
6
+ # in the list.
7
+ class FixedHash < Base
8
+ attr_reader :types
9
+
10
+ def initialize(types)
11
+ @types = types.each_with_object({}) {|(k, v), h| h[k] = T::Utils.coerce(v)}
12
+ end
13
+
14
+ # @override Base
15
+ def name
16
+ "{#{@types.map {|(k, v)| "#{k}: #{v}"}.join(', ')}}"
17
+ end
18
+
19
+ # @override Base
20
+ def valid?(obj)
21
+ return false unless obj.is_a?(Hash)
22
+
23
+ @types.each do |key, type|
24
+ return false unless type.valid?(obj[key])
25
+ end
26
+
27
+ obj.each_key do |key|
28
+ return false unless @types[key]
29
+ end
30
+
31
+ true
32
+ end
33
+
34
+ # @override Base
35
+ private def subtype_of_single?(other)
36
+ case other
37
+ when FixedHash
38
+ # Using `subtype_of?` here instead of == would be unsound
39
+ @types == other.types
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ # This gives us better errors, e.g.:
46
+ # "Expected {a: String}, got {a: TrueClass}"
47
+ # instead of
48
+ # "Expected {a: String}, got Hash".
49
+ #
50
+ # @override Base
51
+ def describe_obj(obj)
52
+ if obj.is_a?(Hash)
53
+ "type {#{obj.map {|(k, v)| "#{k}: #{v.class}"}.join(', ')}}"
54
+ else
55
+ super
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Takes a list of types. Validates that an object matches all of the types.
6
+ class Intersection < Base
7
+ attr_reader :types
8
+
9
+ def initialize(types)
10
+ @types = types.flat_map do |type|
11
+ if type.is_a?(Intersection)
12
+ # Simplify nested intersections (mostly so `name` returns a nicer value)
13
+ type.types
14
+ else
15
+ T::Utils.coerce(type)
16
+ end
17
+ end.uniq
18
+ end
19
+
20
+ # @override Base
21
+ def name
22
+ "T.all(#{@types.map(&:name).sort.join(', ')})"
23
+ end
24
+
25
+ # @override Base
26
+ def valid?(obj)
27
+ @types.all? {|type| type.valid?(obj)}
28
+ end
29
+
30
+ # @override Base
31
+ private def subtype_of_single?(other)
32
+ raise "This should never be reached if you're going through `subtype_of?` (and you should be)"
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # The bottom type
6
+ class NoReturn < Base
7
+
8
+ def initialize; end
9
+
10
+ # @override Base
11
+ def name
12
+ "T.noreturn"
13
+ end
14
+
15
+ # @override Base
16
+ def valid?(obj)
17
+ false
18
+ end
19
+
20
+ # @override Base
21
+ private def subtype_of_single?(other)
22
+ true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Defines the type of a proc (a ruby callable). At runtime, only
6
+ # validates that the value is a `::Proc`.
7
+ #
8
+ # At present, we only support fixed-arity procs with no optional or
9
+ # keyword arguments.
10
+ class Proc < Base
11
+ attr_reader :arg_types
12
+ attr_reader :returns
13
+
14
+ def initialize(arg_types, returns)
15
+ @arg_types = {}
16
+ arg_types.each do |key, raw_type|
17
+ @arg_types[key] = T::Utils.coerce(raw_type)
18
+ end
19
+ @returns = T::Utils.coerce(returns)
20
+ end
21
+
22
+ # @override Base
23
+ def name
24
+ args = []
25
+ @arg_types.each do |k, v|
26
+ args << "#{k}: #{v.name}"
27
+ end
28
+ "T.proc.params(#{args.join(', ')}).returns(#{returns})"
29
+ end
30
+
31
+ # @override Base
32
+ def valid?(obj)
33
+ obj.is_a?(::Proc)
34
+ end
35
+
36
+ # @override Base
37
+ private def subtype_of_single?(other)
38
+ case other
39
+ when self.class
40
+ if arg_types.size != other.arg_types.size
41
+ return false
42
+ end
43
+ arg_types.values.zip(other.arg_types.values).all? do |a, b|
44
+ b.subtype_of?(a)
45
+ end && returns.subtype_of?(other.returns)
46
+ else
47
+ false
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Modeling self-types properly at runtime would require additional tracking,
6
+ # so at runtime we permit all values and rely on the static checker.
7
+ class SelfType < Base
8
+
9
+ def initialize(); end
10
+
11
+ # @override Base
12
+ def name
13
+ "T.self_type"
14
+ end
15
+
16
+ # @override Base
17
+ def valid?(obj)
18
+ true
19
+ end
20
+
21
+ # @override Base
22
+ private def subtype_of_single?(other)
23
+ case other
24
+ when SelfType
25
+ true
26
+ else
27
+ false
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Validates that an object belongs to the specified class.
6
+ class Simple < Base
7
+ attr_reader :raw_type
8
+
9
+ def initialize(raw_type)
10
+ @raw_type = raw_type
11
+ end
12
+
13
+ # @override Base
14
+ def name
15
+ @raw_type.name
16
+ end
17
+
18
+ # @override Base
19
+ def valid?(obj)
20
+ obj.is_a?(@raw_type)
21
+ end
22
+
23
+ # @override Base
24
+ private def subtype_of_single?(other)
25
+ case other
26
+ when Simple
27
+ @raw_type <= other.raw_type
28
+ else
29
+ false
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ class TypeMember < TypeVariable
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ class TypeParameter < Base
6
+ def initialize(name)
7
+ raise ArgumentError.new("not a symbol: #{name}") unless name.is_a?(Symbol)
8
+ @name = name
9
+ end
10
+
11
+ def valid?(obj)
12
+ true
13
+ end
14
+
15
+ def subtype_of_single?(type)
16
+ true
17
+ end
18
+
19
+ def name
20
+ "T.type_parameter(#{@name})"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ class TypeTemplate < TypeVariable
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Since we do type erasure at runtime, this just validates the variance and
6
+ # provides some syntax for the static type checker
7
+ class TypeVariable < Base
8
+ attr_reader :variance
9
+
10
+ VALID_VARIANCES = [:in, :out, :invariant]
11
+
12
+ def initialize(variance)
13
+ if !VALID_VARIANCES.include?(variance)
14
+ raise TypeError.new("invalid variance #{variance}")
15
+ end
16
+ @variance = variance
17
+ end
18
+
19
+ def valid?(obj)
20
+ true
21
+ end
22
+
23
+ def subtype_of_single?(type)
24
+ true
25
+ end
26
+
27
+ def name
28
+ Untyped.new.name
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ class TypedArray < TypedEnumerable
6
+ # @override Base
7
+ def name
8
+ "T::Array[#{@type.name}]"
9
+ end
10
+
11
+ # @override Base
12
+ def valid?(obj)
13
+ obj.is_a?(Array) && super
14
+ end
15
+
16
+ def new(*args) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
17
+ Array.new(*T.unsafe(args))
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Types
5
+ # Note: All subclasses of Enumerable should add themselves to the
6
+ # `case` statement below in `describe_obj` in order to get better
7
+ # error messages.
8
+ class TypedEnumerable < Base
9
+ attr_reader :type
10
+
11
+ def initialize(type)
12
+ @type = T::Utils.coerce(type)
13
+ end
14
+
15
+ # @override Base
16
+ def name
17
+ "T::Enumerable[#{@type.name}]"
18
+ end
19
+
20
+ # @override Base
21
+ def valid?(obj)
22
+ return false unless obj.is_a?(Enumerable)
23
+ case obj
24
+ when Array
25
+ begin
26
+ it = 0
27
+ while it < obj.count
28
+ return false unless @type.valid?(obj[it])
29
+ it += 1
30
+ end
31
+ return true
32
+ end
33
+ when Hash
34
+ return false unless @type.is_a?(FixedArray)
35
+ types = @type.types
36
+ return false if types.count != 2
37
+ key_type = types[0]
38
+ value_type = types[1]
39
+ obj.each_pair do |key, val|
40
+ # Some objects (I'm looking at you Rack::Utils::HeaderHash) don't
41
+ # iterate over a [key, value] array, so we can't juse use the @type.valid?(v)
42
+ return false if !key_type.valid?(key) || !value_type.valid?(val)
43
+ end
44
+ return true
45
+ when Enumerator::Lazy
46
+ # Users don't want these walked
47
+ return true
48
+ when Enumerator
49
+ obj.each do |elem|
50
+ return false unless @type.valid?(elem)
51
+ end
52
+ return true
53
+ when Range
54
+ @type.valid?(obj.first) && @type.valid?(obj.last)
55
+ when Set
56
+ obj.each do |item|
57
+ return false unless @type.valid?(item)
58
+ end
59
+
60
+ return true
61
+ else
62
+ # We don't check the enumerable since it isn't guaranteed to be
63
+ # rewindable (e.g. STDIN) and it may be expensive to enumerate
64
+ # (e.g. an enumerator that makes an HTTP request)"
65
+ true
66
+ end
67
+ end
68
+
69
+ # @override Base
70
+ private def subtype_of_single?(other)
71
+ if self.class <= other.class
72
+ # Enumerables are covariant because they are read only
73
+ #
74
+ # Properly speaking, many Enumerable subtypes (e.g. Set)
75
+ # should be invariant because they are mutable and support
76
+ # both reading and writing. However, Sorbet treats *all*
77
+ # Enumerable subclasses as covariant for ease of adoption.
78
+ @type.subtype_of?(other.type)
79
+ else
80
+ false
81
+ end
82
+ end
83
+
84
+ # @override Base
85
+ def describe_obj(obj)
86
+ return super unless obj.is_a?(Enumerable)
87
+ type_from_instance(obj).name
88
+ end
89
+
90
+ private def type_from_instances(objs)
91
+ return objs.class unless objs.is_a?(Enumerable)
92
+ obtained_types = []
93
+ begin
94
+ objs.each do |x|
95
+ obtained_types << type_from_instance(x)
96
+ end
97
+ rescue
98
+ return T.untyped # all we can do is go with the types we have so far
99
+ end
100
+ if obtained_types.count > 1
101
+ # Multiple kinds of bad types showed up, we'll suggest a union
102
+ # type you might want.
103
+ Union.new(obtained_types)
104
+ elsif obtained_types.empty?
105
+ T.noreturn
106
+ else
107
+ # Everything was the same bad type, lets just show that
108
+ obtained_types.first
109
+ end
110
+ end
111
+
112
+ private def type_from_instance(obj)
113
+ if [true, false].include?(obj)
114
+ return T::Boolean
115
+ elsif !obj.is_a?(Enumerable)
116
+ return obj.class
117
+ end
118
+
119
+ case obj
120
+ when Array
121
+ T::Array[type_from_instances(obj)]
122
+ when Hash
123
+ inferred_key = type_from_instances(obj.keys)
124
+ inferred_val = type_from_instances(obj.values)
125
+ T::Hash[inferred_key, inferred_val]
126
+ when Range
127
+ T::Range[type_from_instances([obj.first, obj.last])]
128
+ when Enumerator
129
+ T::Enumerator[type_from_instances(obj)]
130
+ when Set
131
+ T::Set[type_from_instances(obj)]
132
+ when IO
133
+ # Short circuit for anything IO-like (File, etc.). In these cases,
134
+ # enumerating the object is a destructive operation and might hang.
135
+ obj.class
136
+ else
137
+ self.class.new(type_from_instances(obj))
138
+ end
139
+ end
140
+ end
141
+ end