steep 0.27.0 → 0.31.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/bin/smoke_runner.rb +3 -4
  4. data/bin/steep-prof +1 -2
  5. data/lib/steep.rb +6 -4
  6. data/lib/steep/annotation_parser.rb +2 -4
  7. data/lib/steep/ast/builtin.rb +11 -21
  8. data/lib/steep/ast/types/factory.rb +234 -101
  9. data/lib/steep/ast/types/intersection.rb +12 -9
  10. data/lib/steep/ast/types/logic.rb +63 -0
  11. data/lib/steep/ast/types/name.rb +2 -58
  12. data/lib/steep/ast/types/union.rb +5 -6
  13. data/lib/steep/errors.rb +14 -0
  14. data/lib/steep/interface/interface.rb +5 -62
  15. data/lib/steep/interface/method_type.rb +346 -75
  16. data/lib/steep/interface/substitution.rb +16 -4
  17. data/lib/steep/module_helper.rb +25 -0
  18. data/lib/steep/project.rb +25 -0
  19. data/lib/steep/project/completion_provider.rb +57 -58
  20. data/lib/steep/project/file_loader.rb +7 -2
  21. data/lib/steep/project/hover_content.rb +92 -83
  22. data/lib/steep/project/signature_file.rb +33 -0
  23. data/lib/steep/project/{file.rb → source_file.rb} +24 -54
  24. data/lib/steep/project/target.rb +31 -12
  25. data/lib/steep/server/base_worker.rb +1 -0
  26. data/lib/steep/server/code_worker.rb +31 -45
  27. data/lib/steep/server/interaction_worker.rb +42 -38
  28. data/lib/steep/server/master.rb +23 -33
  29. data/lib/steep/server/utils.rb +46 -13
  30. data/lib/steep/server/worker_process.rb +4 -2
  31. data/lib/steep/signature/validator.rb +3 -3
  32. data/lib/steep/source.rb +60 -3
  33. data/lib/steep/subtyping/check.rb +34 -47
  34. data/lib/steep/subtyping/constraints.rb +8 -0
  35. data/lib/steep/type_construction.rb +366 -365
  36. data/lib/steep/type_inference/block_params.rb +5 -0
  37. data/lib/steep/type_inference/constant_env.rb +2 -5
  38. data/lib/steep/type_inference/logic_type_interpreter.rb +219 -0
  39. data/lib/steep/type_inference/type_env.rb +2 -2
  40. data/lib/steep/version.rb +1 -1
  41. data/smoke/alias/a.rb +1 -1
  42. data/smoke/case/a.rb +1 -1
  43. data/smoke/if/a.rb +1 -1
  44. data/smoke/module/a.rb +1 -1
  45. data/smoke/rescue/a.rb +4 -13
  46. data/smoke/toplevel/Steepfile +5 -0
  47. data/smoke/toplevel/a.rb +4 -0
  48. data/smoke/toplevel/a.rbs +3 -0
  49. data/smoke/type_case/a.rb +0 -7
  50. data/steep.gemspec +3 -3
  51. metadata +20 -16
  52. data/lib/steep/ast/method_type.rb +0 -126
  53. data/lib/steep/ast/namespace.rb +0 -80
  54. data/lib/steep/names.rb +0 -86
@@ -56,6 +56,11 @@ module Steep
56
56
 
57
57
  node.children.each do |arg|
58
58
  var = arg.children.first
59
+
60
+ if var.is_a?(::AST::Node)
61
+ return
62
+ end
63
+
59
64
  type = annotations.var_type(lvar: var.name)
60
65
 
61
66
  case arg.type
@@ -6,7 +6,7 @@ module Steep
6
6
  attr_reader :factory
7
7
  attr_reader :table
8
8
 
9
- # ConstantEnv receives an Names::Module as a context, not a Namespace, because this is a simulation of Ruby.
9
+ # ConstantEnv receives an TypeName as a context, not a Namespace, because this is a simulation of Ruby.
10
10
  # Any namespace is a module or class.
11
11
  def initialize(factory:, context:)
12
12
  @cache = {}
@@ -17,10 +17,7 @@ module Steep
17
17
 
18
18
  def lookup(name)
19
19
  cache[name] ||= begin
20
- constant = table.resolve_constant_reference(
21
- factory.type_name_1(name),
22
- context: context.map {|namespace| factory.namespace_1(namespace) }
23
- )
20
+ constant = table.resolve_constant_reference(name, context: context)
24
21
 
25
22
  if constant
26
23
  factory.type(constant.type)
@@ -0,0 +1,219 @@
1
+ module Steep
2
+ module TypeInference
3
+ class LogicTypeInterpreter
4
+ attr_reader :subtyping
5
+ attr_reader :typing
6
+
7
+ def initialize(subtyping:, typing:)
8
+ @subtyping = subtyping
9
+ @typing = typing
10
+ end
11
+
12
+ def factory
13
+ subtyping.factory
14
+ end
15
+
16
+ def guess_type_from_method(node)
17
+ if node.type == :send
18
+ method = node.children[1]
19
+ case method
20
+ when :is_a?, :kind_of?, :instance_of?
21
+ AST::Types::Logic::ReceiverIsArg.new
22
+ when :nil?
23
+ AST::Types::Logic::ReceiverIsNil.new
24
+ when :!
25
+ AST::Types::Logic::Not.new
26
+ when :===
27
+ AST::Types::Logic::ArgIsReceiver.new
28
+ end
29
+ end
30
+ end
31
+
32
+ def eval(env:, type:, node:)
33
+ value_node, vars = decompose_value(node)
34
+
35
+ truthy_env = env
36
+ falsy_env = env
37
+
38
+ if type.is_a?(AST::Types::Any)
39
+ type = guess_type_from_method(node) || type
40
+ end
41
+
42
+ if type.is_a?(AST::Types::Logic::Base)
43
+ vars.each do |var_name|
44
+ truthy_env = truthy_env.assign!(var_name, node: node, type: AST::Builtin.true_type)
45
+ falsy_env = truthy_env.assign!(var_name, node: node, type: AST::Builtin.false_type)
46
+ end
47
+
48
+ case type
49
+ when AST::Types::Logic::ReceiverIsNil
50
+ case value_node.type
51
+ when :send
52
+ receiver = value_node.children[0]
53
+
54
+ if receiver
55
+ _, receiver_vars = decompose_value(receiver)
56
+
57
+ receiver_vars.each do |receiver_var|
58
+ var_type = env[receiver_var]
59
+ truthy_type, falsy_type = factory.unwrap_optional(var_type)
60
+
61
+ truthy_env = truthy_env.assign!(receiver_var, node: node, type: falsy_type || AST::Builtin.nil_type)
62
+ falsy_env = falsy_env.assign!(receiver_var, node: node, type: truthy_type)
63
+ end
64
+ end
65
+ end
66
+ when AST::Types::Logic::ReceiverIsArg
67
+ case value_node.type
68
+ when :send
69
+ receiver, _, arg = value_node.children
70
+
71
+ if receiver
72
+ _, receiver_vars = decompose_value(receiver)
73
+ arg_type = typing.type_of(node: arg)
74
+
75
+ if arg_type.is_a?(AST::Types::Name::Singleton)
76
+ receiver_vars.each do |var_name|
77
+ var_type = env[var_name]
78
+ truthy_type, falsy_type = type_case_select(var_type, arg_type.name)
79
+
80
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
81
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ when AST::Types::Logic::ArgIsReceiver
87
+ case value_node.type
88
+ when :send
89
+ receiver, _, arg = value_node.children
90
+
91
+ if receiver
92
+ _, arg_vars = decompose_value(arg)
93
+ receiver_type = typing.type_of(node: receiver)
94
+
95
+ if receiver_type.is_a?(AST::Types::Name::Singleton)
96
+ arg_vars.each do |var_name|
97
+ var_type = env[var_name]
98
+ truthy_type, falsy_type = type_case_select(var_type, receiver_type.name)
99
+
100
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
101
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ when AST::Types::Logic::Not
107
+ receiver, * = value_node.children
108
+ receiver_type = typing.type_of(node: receiver)
109
+ falsy_env, truthy_env = eval(env: env, type: receiver_type, node: receiver)
110
+ end
111
+ else
112
+ _, vars = decompose_value(node)
113
+
114
+ vars.each do |var_name|
115
+ var_type = env[var_name]
116
+ truthy_type, falsy_type = factory.unwrap_optional(var_type)
117
+
118
+ if falsy_type
119
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
120
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
121
+ else
122
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
123
+ falsy_env = falsy_env.assign!(var_name, node: node, type: truthy_type)
124
+ end
125
+ end
126
+ end
127
+
128
+ [truthy_env, falsy_env]
129
+ end
130
+
131
+ def decompose_value(node)
132
+ case node.type
133
+ when :lvar
134
+ [node, Set[node.children[0].name]]
135
+ when :masgn
136
+ lhs, rhs = node.children
137
+ lhs_vars = lhs.children.select {|m| m.type == :lvasgn }.map {|m| m.children[0].name }
138
+ val, vars = decompose_value(rhs)
139
+ [val, vars + lhs_vars]
140
+ when :lvasgn
141
+ var, rhs = node.children
142
+ val, vars = decompose_value(rhs)
143
+ [val, vars + [var.name]]
144
+ when :begin
145
+ decompose_value(node.children.last)
146
+ when :and
147
+ left, right = node.children
148
+ _, left_vars = decompose_value(left)
149
+ val, right_vars = decompose_value(right)
150
+ [val, left_vars + right_vars]
151
+ else
152
+ [node, Set[]]
153
+ end
154
+ end
155
+
156
+ def type_case_select(type, klass)
157
+ truth_types, false_types = type_case_select0(type, klass)
158
+
159
+ [
160
+ AST::Types::Union.build(types: truth_types),
161
+ AST::Types::Union.build(types: false_types)
162
+ ]
163
+ end
164
+
165
+ def type_case_select0(type, klass)
166
+ instance_type = factory.instance_type(klass)
167
+
168
+ case type
169
+ when AST::Types::Union
170
+ truthy_types = []
171
+ falsy_types = []
172
+
173
+ type.types.each do |ty|
174
+ truths, falses = type_case_select0(ty, klass)
175
+
176
+ if truths.empty?
177
+ falsy_types.push(ty)
178
+ else
179
+ truthy_types.push(*truths)
180
+ falsy_types.push(*falses)
181
+ end
182
+ end
183
+
184
+ [truthy_types, falsy_types]
185
+
186
+ when AST::Types::Name::Instance
187
+ relation = Subtyping::Relation.new(sub_type: type, super_type: instance_type)
188
+ if subtyping.check(relation, constraints: Subtyping::Constraints.empty, self_type: AST::Types::Self.new).success?
189
+ [
190
+ [type],
191
+ []
192
+ ]
193
+ else
194
+ [
195
+ [],
196
+ [type]
197
+ ]
198
+ end
199
+
200
+ when AST::Types::Name::Alias
201
+ ty = factory.expand_alias(type)
202
+ type_case_select0(ty, klass)
203
+
204
+ when AST::Types::Any, AST::Types::Top
205
+ [
206
+ [instance_type],
207
+ [type]
208
+ ]
209
+
210
+ else
211
+ [
212
+ [],
213
+ [type]
214
+ ]
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -57,7 +57,7 @@ module Steep
57
57
  end
58
58
  end
59
59
 
60
- # @type method assert: (const: Names::Module) { () -> void } -> AST::Type
60
+ # @type method assert: (const: TypeName) { () -> void } -> AST::Type
61
61
  # | (gvar: Symbol) { () -> void } -> AST::Type
62
62
  # | (ivar: Symbol) { () -> void } -> AST::Type
63
63
  def get(const: nil, gvar: nil, ivar: nil)
@@ -98,7 +98,7 @@ module Steep
98
98
  end
99
99
  end
100
100
 
101
- # @type method assign: (const: Names::Module, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
101
+ # @type method assign: (const: TypeName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
102
102
  # | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
103
103
  # | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
104
104
  def assign(const: nil, gvar: nil, ivar: nil, type:, self_type:, &block)
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.27.0"
2
+ VERSION = "0.31.1"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  # @type var x: foo
2
2
  x = ""
3
3
 
4
- # !expects ArgumentTypeMismatch: receiver=(::Integer | ::String), expected=::string, actual=::Integer
4
+ # !expects* UnresolvedOverloading: receiver=(::String | ::Integer), method_name=+,
5
5
  x + 123
6
6
 
7
7
  # @type var y: bar
@@ -1,6 +1,6 @@
1
1
  # @type var a: Integer
2
2
 
3
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::String] | ::Integer | ::String | nil)
3
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::Array[::String] | nil | ::String)
4
4
  a = case 1
5
5
  when 2
6
6
  1
@@ -13,7 +13,7 @@ else
13
13
  "baz"
14
14
  end
15
15
 
16
- # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=(::Integer | ::String)
16
+ # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=(::String | ::Integer)
17
17
  a = if z
18
18
  "foofoo"
19
19
  else
@@ -13,7 +13,7 @@ module A
13
13
  # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=::Integer
14
14
  s = n
15
15
 
16
- # !expects NoMethodError: type=(::A & ::Object & ::_Each2[::Integer, ::A]), method=foo
16
+ # !expects NoMethodError: type=(::Object & ::_Each2[::Integer, ::A] & ::A), method=foo
17
17
  foo()
18
18
 
19
19
  n
@@ -1,6 +1,6 @@
1
1
  # @type var a: Integer
2
2
 
3
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String)
3
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Integer)
4
4
  a = begin
5
5
  'foo'
6
6
  rescue
@@ -9,12 +9,12 @@ a = begin
9
9
 
10
10
  # @type var b: Integer
11
11
 
12
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String)
12
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Integer)
13
13
  b = 'foo' rescue 1
14
14
 
15
15
  # @type var c: Integer
16
16
 
17
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String | ::Symbol)
17
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Symbol | ::Integer)
18
18
  c = begin
19
19
  'foo'
20
20
  rescue RuntimeError
@@ -23,18 +23,9 @@ c = begin
23
23
  1
24
24
  end
25
25
 
26
- # @type var d: Integer
27
-
28
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=::String
29
- d = begin
30
- 1
31
- else
32
- 'foo'
33
- end
34
-
35
26
  # @type var e: Integer
36
27
 
37
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::Integer] | ::Integer | ::Symbol)
28
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::Integer] | ::Symbol | ::Integer)
38
29
  e = begin
39
30
  'foo'
40
31
  rescue RuntimeError
@@ -0,0 +1,5 @@
1
+ target :test do
2
+ typing_options :strict
3
+ check "*.rb"
4
+ signature "*.rbs"
5
+ end
@@ -0,0 +1,4 @@
1
+ # !expects MethodBodyTypeMismatch: method=fizz_buzz, expected=::String, actual=nil
2
+ def fizz_buzz(n)
3
+ nil
4
+ end
@@ -0,0 +1,3 @@
1
+ class Object
2
+ def fizz_buzz: (Integer) -> String
3
+ end
@@ -26,10 +26,3 @@ when String
26
26
  # @type var x: Integer
27
27
  x + 1
28
28
  end
29
-
30
- case x
31
- when Object
32
- # !expects@+2 IncompatibleTypeCase: var_name=x, ::Object <: (::Integer | ::String | ::Symbol)
33
- # !expects NoMethodError: type=::Object, method=foobar
34
- x.foobar
35
- end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency "ast_utils", "~> 0.3.0"
33
33
  spec.add_runtime_dependency "activesupport", ">= 5.1"
34
34
  spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
35
- spec.add_runtime_dependency "listen", "~> 3.1"
36
- spec.add_runtime_dependency "language_server-protocol", "~> 3.14.0.2"
37
- spec.add_runtime_dependency "rbs", "~> 0.11.0"
35
+ spec.add_runtime_dependency "listen", "~> 3.0"
36
+ spec.add_runtime_dependency "language_server-protocol", "~> 3.15.0.1"
37
+ spec.add_runtime_dependency "rbs", "~> 0.12.0"
38
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0
4
+ version: 0.31.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-31 00:00:00.000000000 Z
11
+ date: 2020-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -78,42 +78,42 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '3.1'
81
+ version: '3.0'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '3.1'
88
+ version: '3.0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: language_server-protocol
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: 3.14.0.2
95
+ version: 3.15.0.1
96
96
  type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: 3.14.0.2
102
+ version: 3.15.0.1
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: rbs
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: 0.11.0
109
+ version: 0.12.0
110
110
  type: :runtime
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: 0.11.0
116
+ version: 0.12.0
117
117
  description: Gradual Typing for Ruby
118
118
  email:
119
119
  - matsumoto@soutaro.com
@@ -143,8 +143,6 @@ files:
143
143
  - lib/steep/ast/buffer.rb
144
144
  - lib/steep/ast/builtin.rb
145
145
  - lib/steep/ast/location.rb
146
- - lib/steep/ast/method_type.rb
147
- - lib/steep/ast/namespace.rb
148
146
  - lib/steep/ast/type_params.rb
149
147
  - lib/steep/ast/types.rb
150
148
  - lib/steep/ast/types/any.rb
@@ -156,6 +154,7 @@ files:
156
154
  - lib/steep/ast/types/instance.rb
157
155
  - lib/steep/ast/types/intersection.rb
158
156
  - lib/steep/ast/types/literal.rb
157
+ - lib/steep/ast/types/logic.rb
159
158
  - lib/steep/ast/types/name.rb
160
159
  - lib/steep/ast/types/nil.rb
161
160
  - lib/steep/ast/types/proc.rb
@@ -184,14 +183,15 @@ files:
184
183
  - lib/steep/interface/method.rb
185
184
  - lib/steep/interface/method_type.rb
186
185
  - lib/steep/interface/substitution.rb
187
- - lib/steep/names.rb
186
+ - lib/steep/module_helper.rb
188
187
  - lib/steep/project.rb
189
188
  - lib/steep/project/completion_provider.rb
190
189
  - lib/steep/project/dsl.rb
191
- - lib/steep/project/file.rb
192
190
  - lib/steep/project/file_loader.rb
193
191
  - lib/steep/project/hover_content.rb
194
192
  - lib/steep/project/options.rb
193
+ - lib/steep/project/signature_file.rb
194
+ - lib/steep/project/source_file.rb
195
195
  - lib/steep/project/target.rb
196
196
  - lib/steep/server/base_worker.rb
197
197
  - lib/steep/server/code_worker.rb
@@ -218,6 +218,7 @@ files:
218
218
  - lib/steep/type_inference/context_array.rb
219
219
  - lib/steep/type_inference/local_variable_type_env.rb
220
220
  - lib/steep/type_inference/logic.rb
221
+ - lib/steep/type_inference/logic_type_interpreter.rb
221
222
  - lib/steep/type_inference/send_args.rb
222
223
  - lib/steep/type_inference/type_env.rb
223
224
  - lib/steep/typing.rb
@@ -347,6 +348,9 @@ files:
347
348
  - smoke/super/Steepfile
348
349
  - smoke/super/a.rb
349
350
  - smoke/super/a.rbs
351
+ - smoke/toplevel/Steepfile
352
+ - smoke/toplevel/a.rb
353
+ - smoke/toplevel/a.rbs
350
354
  - smoke/type_case/Steepfile
351
355
  - smoke/type_case/a.rb
352
356
  - smoke/yield/Steepfile
@@ -359,7 +363,7 @@ metadata:
359
363
  homepage_uri: https://github.com/soutaro/steep
360
364
  source_code_uri: https://github.com/soutaro/steep
361
365
  changelog_uri: https://github.com/soutaro/steep/blob/master/CHANGELOG.md
362
- post_install_message:
366
+ post_install_message:
363
367
  rdoc_options: []
364
368
  require_paths:
365
369
  - lib
@@ -374,8 +378,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
374
378
  - !ruby/object:Gem::Version
375
379
  version: '0'
376
380
  requirements: []
377
- rubygems_version: 3.0.3
378
- signing_key:
381
+ rubygems_version: 3.1.2
382
+ signing_key:
379
383
  specification_version: 4
380
384
  summary: Gradual Typing for Ruby
381
385
  test_files: []