steep 0.5.1 → 0.6.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/bin/smoke_runner.rb +1 -1
  4. data/lib/steep.rb +6 -4
  5. data/lib/steep/ast/builtin.rb +96 -0
  6. data/lib/steep/ast/location.rb +9 -5
  7. data/lib/steep/ast/namespace.rb +80 -0
  8. data/lib/steep/ast/signature/env.rb +37 -31
  9. data/lib/steep/ast/types/boolean.rb +2 -2
  10. data/lib/steep/ast/types/hash.rb +50 -0
  11. data/lib/steep/ast/types/literal.rb +12 -10
  12. data/lib/steep/ast/types/name.rb +135 -94
  13. data/lib/steep/ast/types/nil.rb +3 -1
  14. data/lib/steep/ast/types/proc.rb +3 -1
  15. data/lib/steep/drivers/check.rb +4 -4
  16. data/lib/steep/drivers/utils/validator.rb +11 -16
  17. data/lib/steep/interface/builder.rb +201 -146
  18. data/lib/steep/interface/instantiated.rb +8 -0
  19. data/lib/steep/names.rb +86 -0
  20. data/lib/steep/parser.y +1093 -668
  21. data/lib/steep/source.rb +2 -2
  22. data/lib/steep/subtyping/check.rb +199 -63
  23. data/lib/steep/subtyping/constraints.rb +2 -5
  24. data/lib/steep/subtyping/variable_variance.rb +2 -2
  25. data/lib/steep/type_construction.rb +194 -175
  26. data/lib/steep/type_inference/block_params.rb +9 -21
  27. data/lib/steep/type_inference/constant_env.rb +26 -30
  28. data/lib/steep/type_inference/send_args.rb +4 -7
  29. data/lib/steep/type_inference/type_env.rb +3 -3
  30. data/lib/steep/version.rb +1 -1
  31. data/smoke/alias/a.rb +1 -1
  32. data/smoke/alias/b.rb +1 -1
  33. data/smoke/class/i.rbi +1 -1
  34. data/smoke/hash/a.rbi +8 -0
  35. data/smoke/hash/c.rb +18 -0
  36. data/smoke/hash/d.rb +6 -0
  37. data/smoke/hello/hello.rb +2 -2
  38. data/smoke/interface/a.rb +14 -0
  39. data/smoke/interface/a.rbi +12 -0
  40. data/smoke/module/a.rb +1 -1
  41. data/smoke/module/a.rbi +3 -3
  42. data/smoke/module/b.rb +1 -1
  43. data/smoke/stdout/a.rb +2 -2
  44. data/stdlib/builtin.rbi +6 -7
  45. data/steep.gemspec +1 -1
  46. metadata +14 -7
  47. data/lib/steep/module_name.rb +0 -116
  48. data/lib/steep/type_name.rb +0 -93
@@ -149,13 +149,13 @@ module Steep
149
149
  type = params_type.required[0]
150
150
 
151
151
  case
152
- when array?(type)
152
+ when AST::Builtin::Array.instance_type?(type)
153
153
  type_arg = type.args[0]
154
154
  params.each do |param|
155
155
  unless param == rest_param
156
- zip << [param, AST::Types::Union.build(types: [type_arg, AST::Types::Nil.new])]
156
+ zip << [param, AST::Types::Union.build(types: [type_arg, AST::Builtin.nil_type])]
157
157
  else
158
- zip << [param, AST::Types::Name.new_instance(name: "::Array", args: [type_arg])]
158
+ zip << [param, AST::Builtin::Array.instance_type(type_arg)]
159
159
  end
160
160
  end
161
161
  when type.is_a?(AST::Types::Tuple)
@@ -172,7 +172,7 @@ module Steep
172
172
  if rest_param
173
173
  if types.any?
174
174
  union = AST::Types::Union.build(types: types)
175
- zip << [rest_param, AST::Types::Name.new_instance(name: "::Array", args: [union])]
175
+ zip << [rest_param, AST::Builtin::Array.instance_type(union)]
176
176
  else
177
177
  zip << [rest_param, AST::Types::Nil.new]
178
178
  end
@@ -187,23 +187,17 @@ module Steep
187
187
  if type
188
188
  zip << [param, type]
189
189
  else
190
- zip << [param, AST::Types::Nil.new]
190
+ zip << [param, AST::Builtin.nil_type]
191
191
  end
192
192
  end
193
193
 
194
194
  if rest_param
195
195
  if types.empty?
196
- array = AST::Types::Name.new_instance(
197
- name: "::Array",
198
- args: [params_type.rest || AST::Types::Any.new]
199
- )
196
+ array = AST::Builtin::Array.instance_type(params_type.rest || AST::Builtin.any_type)
200
197
  zip << [rest_param, array]
201
198
  else
202
199
  union = AST::Types::Union.build(types: types.map(&:last) + [params_type.rest])
203
- array = AST::Types::Name.new_instance(
204
- name: "::Array",
205
- args: [union]
206
- )
200
+ array = AST::Builtin::Array.instance_type(union)
207
201
  zip << [rest_param, array]
208
202
  end
209
203
  end
@@ -211,19 +205,13 @@ module Steep
211
205
  end
212
206
  end
213
207
 
214
- def array?(type)
215
- type.is_a?(AST::Types::Name) &&
216
- type.name.is_a?(TypeName::Instance) &&
217
- type.name.name.name == "Array" && type.name.name.absolute?
218
- end
219
-
220
208
  def expandable_params?(params_type)
221
209
  if params_type.flat_unnamed_params.size == 1
222
210
  case (type = params_type.required.first)
223
211
  when AST::Types::Tuple
224
212
  true
225
- when AST::Types::Name
226
- array?(type)
213
+ when AST::Types::Name::Base
214
+ AST::Builtin::Array.instance_type?(type)
227
215
  end
228
216
  end
229
217
  end
@@ -2,51 +2,47 @@ module Steep
2
2
  module TypeInference
3
3
  class ConstantEnv
4
4
  attr_reader :builder
5
- attr_reader :current_namespace
5
+ attr_reader :context
6
6
  attr_reader :cache
7
7
 
8
- def initialize(builder:, current_namespace:)
8
+ # ConstantEnv receives an optional Names::Module, not a Namespace, because this is a simulation of Ruby.
9
+ # Any namespace is a module or class.
10
+ def initialize(builder:, context:)
9
11
  @cache = {}
10
12
  @builder = builder
11
- @current_namespace = current_namespace
13
+ @context = context
12
14
  end
13
15
 
14
16
  def signatures
15
17
  builder.signatures
16
18
  end
17
19
 
18
- def lookup(name)
19
- unless cache.key?(name)
20
- cache[name] = lookup0(name, namespace: current_namespace)
21
- end
20
+ def namespace
21
+ @namespace ||= if context
22
+ context.namespace.append(context.name)
23
+ else
24
+ AST::Namespace.root
25
+ end
26
+ end
22
27
 
23
- cache[name]
28
+ def lookup(name)
29
+ cache[name] ||= lookup0(name, namespace: namespace)
24
30
  end
25
31
 
32
+ # @type method lookup0: (Names::Module, namespace: AST::Namespace) -> Type
26
33
  def lookup0(name, namespace:)
27
- if name.absolute?
28
- case
29
- when signatures.module_name?(name)
30
- AST::Types::Name.new_module(name: name)
31
- when signatures.class_name?(name)
32
- AST::Types::Name.new_class(name: name, constructor: true)
33
- when signatures.const_name?(name)
34
- builder.absolute_type(signatures.find_const(name).type, current: nil)
35
- end
34
+ full_name = name.in_namespace(namespace)
35
+ case
36
+ when signatures.module_name?(full_name)
37
+ AST::Types::Name::Module.new(name: full_name)
38
+ when signatures.class_name?(full_name)
39
+ AST::Types::Name::Class.new(name: full_name, constructor: true)
40
+ when signatures.const_name?(full_name)
41
+ builder.absolute_type(signatures.find_const(name, current_module: namespace).type,
42
+ current: namespace)
36
43
  else
37
- if namespace
38
- case
39
- when signatures.module_name?(name, current_module: namespace)
40
- AST::Types::Name.new_module(name: namespace + name)
41
- when signatures.class_name?(name, current_module: namespace)
42
- AST::Types::Name.new_class(name: namespace + name, constructor: true)
43
- when signatures.const_name?(name, current_module: namespace)
44
- builder.absolute_type(signatures.find_const(name, current_module: namespace).type, current: nil)
45
- else
46
- lookup0(name, namespace: namespace.parent)
47
- end
48
- else
49
- lookup0(name.absolute!, namespace: nil)
44
+ unless namespace.empty?
45
+ lookup0(name, namespace: namespace.parent)
50
46
  end
51
47
  end
52
48
  end
@@ -123,12 +123,9 @@ module Steep
123
123
 
124
124
  if kwsplat_nodes.any?
125
125
  pairs << [kw_args,
126
- AST::Types::Name.new_instance(
127
- name: "::Hash",
128
- args: [
129
- AST::Types::Name.new_instance(name: "::Symbol"),
130
- AST::Types::Union.build(types: rest_types + [params.rest_keywords])
131
- ]
126
+ AST::Builtin::Hash.instance_type(
127
+ AST::Builtin::Symbol.instance_type,
128
+ AST::Types::Union.build(types: rest_types + [params.rest_keywords])
132
129
  )]
133
130
  end
134
131
  end
@@ -185,7 +182,7 @@ module Steep
185
182
 
186
183
  if types
187
184
  if arg.type == :splat
188
- type = AST::Types::Name.new_instance(name: "::Array", args: [AST::Types::Union.build(types: types)])
185
+ type = AST::Builtin::Array.instance_type(AST::Types::Union.build(types: types))
189
186
  else
190
187
  type = AST::Types::Union.build(types: types)
191
188
  end
@@ -38,7 +38,7 @@ module Steep
38
38
  env.set(const: name, type: type)
39
39
  end
40
40
  signatures.globals.each do |name, annot|
41
- type = subtyping.builder.absolute_type(annot.type, current: nil)
41
+ type = subtyping.builder.absolute_type(annot.type, current: AST::Namespace.root)
42
42
  env.set(gvar: name, type: type)
43
43
  end
44
44
  end
@@ -83,7 +83,7 @@ module Steep
83
83
  end
84
84
  end
85
85
 
86
- # @type method assert: (const: ModuleName) { () -> void } -> AST::Type
86
+ # @type method assert: (const: Names::Module) { () -> void } -> AST::Type
87
87
  # | (gvar: Symbol) { () -> void } -> AST::Type
88
88
  # | (ivar: Symbol) { () -> void } -> AST::Type
89
89
  # | (lvar: Symbol) { () -> AST::Type | nil } -> AST::Type
@@ -138,7 +138,7 @@ module Steep
138
138
  end
139
139
  end
140
140
 
141
- # @type method assign: (const: ModuleName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
141
+ # @type method assign: (const: Names::Module, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
142
142
  # | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
143
143
  # | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
144
144
  # | (lvar: Symbol | LabeledName, type: AST::Type) { (Subtyping::Result::Failure) -> void } -> AST::Type
data/lib/steep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
data/smoke/alias/a.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # @type var x: foo
2
2
  x = ""
3
3
 
4
- # !expects NoMethodError: type=foo, method=+
4
+ # !expects NoMethodError: type=::foo, method=+
5
5
  x + 123
6
6
 
7
7
  # @type var y: bar<Integer>
data/smoke/alias/b.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  a = ["", :foo]
4
4
 
5
5
  # @type var x: Integer
6
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=String
6
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=::String
7
7
  x = a[0]
data/smoke/class/i.rbi CHANGED
@@ -3,7 +3,7 @@ class IncompatibleSuper
3
3
  def initialize: (name: String) -> any
4
4
  end
5
5
 
6
- class IncompatibleChild <: IncompatibleSuper
6
+ class IncompatibleChild < IncompatibleSuper
7
7
  def initialize: () -> any
8
8
  def (incompatible) foo: (Object) -> String
9
9
  end
data/smoke/hash/a.rbi ADDED
@@ -0,0 +1,8 @@
1
+ type t = {
2
+ id: Integer,
3
+ name: String
4
+ }
5
+
6
+ class Controller
7
+ def params: -> { id: Integer, name: String }
8
+ end
data/smoke/hash/c.rb ADDED
@@ -0,0 +1,18 @@
1
+ # @type var params: t
2
+ params = _ = nil
3
+
4
+ id = params[:id]
5
+ # !expects NoMethodError: type=::Integer, method=abcdefg
6
+ id.abcdefg
7
+
8
+ name = params[:name]
9
+ # !expects NoMethodError: type=::String, method=abcdefg
10
+ name.abcdefg
11
+
12
+ # !expects NoMethodError: type=(::Integer | ::String | nil), method=abcdefg
13
+ params[(_=nil) ? :id : :name].abcdefg
14
+
15
+ # @type var controller: Controller
16
+ controller = _ = nil
17
+
18
+ controller.params[:id] + 3
data/smoke/hash/d.rb ADDED
@@ -0,0 +1,6 @@
1
+ # @type var params: { name: String, id: Integer }
2
+
3
+ params = { id: 30, name: "Matz" }
4
+
5
+ # !expects IncompatibleAssignment: lhs_type={ :name => ::String, :id => ::Integer }, rhs_type=::Hash<::Symbol, ::String>
6
+ params = { id: "30", name: "foo", email: "matsumoto@soutaro.com" }
data/smoke/hello/hello.rb CHANGED
@@ -6,8 +6,8 @@ y = (_ = nil)
6
6
 
7
7
  a = x.foo
8
8
 
9
- # !expects NoMethodError: type=_Bar, method=foo
9
+ # !expects NoMethodError: type=::_Bar, method=foo
10
10
  b = y.foo
11
11
 
12
- # !expects IncompatibleAssignment: lhs_type=_Foo, rhs_type=_Bar
12
+ # !expects IncompatibleAssignment: lhs_type=::_Foo, rhs_type=::_Bar
13
13
  x = y
@@ -0,0 +1,14 @@
1
+ class A
2
+ # @dynamic foo
3
+
4
+ def hello
5
+ # !expects NoMethodError: type=::A::Object, method=bar
6
+ foo.foo.bar
7
+
8
+ # @type var object: ::Object
9
+ object = _ = nil
10
+
11
+ # !expects NoMethodError: type=::Object, method=object?
12
+ object.object?
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ class A
2
+ def foo: -> _Foo
3
+ def hello: -> void
4
+ end
5
+
6
+ class A::Object
7
+ def object?: -> bool
8
+ end
9
+
10
+ interface A::_Foo
11
+ def foo: -> Object
12
+ end
data/smoke/module/a.rb CHANGED
@@ -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 & _Each<::Integer>), method=foo
16
+ # !expects NoMethodError: type=(::A & ::Object & ::_Each<::Integer, ::A>), method=foo
17
17
  foo()
18
18
 
19
19
  n
data/smoke/module/a.rbi CHANGED
@@ -1,8 +1,8 @@
1
- interface _Each<'a>
2
- def each: { ('a) -> any } -> instance
1
+ interface _Each<'a, 'b>
2
+ def each: { ('a) -> any } -> 'b
3
3
  end
4
4
 
5
- module A : _Each<Integer>
5
+ module A : _Each<Integer, A>
6
6
  def count: () -> Integer
7
7
  end
8
8
 
data/smoke/module/b.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # ALLOW FAILURE
2
2
 
3
- # @type var klass: Class<any>
3
+ # @type var klass: Class
4
4
  # @type var mod: Module
5
5
 
6
6
  3.is_a?(3.class)
data/smoke/stdout/a.rb CHANGED
@@ -4,5 +4,5 @@ class A
4
4
  end
5
5
  end
6
6
 
7
- A.new(STDOUT)
8
- A.new(StringIO.new)
7
+ A.new.write_to(io: STDOUT)
8
+ A.new.write_to(io: StringIO.new)
data/stdlib/builtin.rbi CHANGED
@@ -2,7 +2,7 @@ class BasicObject
2
2
  def __id__: -> Integer
3
3
  end
4
4
 
5
- class Object <: BasicObject
5
+ class Object < BasicObject
6
6
  include Kernel
7
7
  def tap: { (self) -> any } -> self
8
8
  def to_s: -> String
@@ -43,8 +43,7 @@ end
43
43
  class Method
44
44
  end
45
45
 
46
- class Class<'instance> <: Module
47
- def new: (*any, **any) -> 'instance
46
+ class Class < Module
48
47
  def class: -> Class.class
49
48
  def allocate: -> any
50
49
  end
@@ -268,7 +267,7 @@ class Numeric
268
267
  def -@: -> self
269
268
  end
270
269
 
271
- class Integer <: Numeric
270
+ class Integer < Numeric
272
271
  def to_int: -> Integer
273
272
  def +: (Integer) -> Integer
274
273
  | (Numeric) -> Numeric
@@ -296,7 +295,7 @@ class Integer <: Numeric
296
295
  def ~: () -> Integer
297
296
  end
298
297
 
299
- class Float <: Numeric
298
+ class Float < Numeric
300
299
  def *: (Float) -> Float
301
300
  | (Integer) -> Float
302
301
  | (Numeric) -> Numeric
@@ -313,7 +312,7 @@ end
313
312
 
314
313
  Math::PI: Float
315
314
 
316
- class Complex <: Numeric
315
+ class Complex < Numeric
317
316
  def self.polar: (Numeric, Numeric) -> instance
318
317
  def +: (Complex) -> Complex
319
318
  | (Numeric) -> Numeric
@@ -572,7 +571,7 @@ end
572
571
 
573
572
  File::FNM_DOTMATCH: Integer
574
573
 
575
- class File <: IO
574
+ class File < IO
576
575
  def self.binread: (String) -> String
577
576
  def self.extname: (String) -> String
578
577
  def self.basename: (String) -> String
data/steep.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "racc", "~> 1.4"
31
31
 
32
32
  spec.add_runtime_dependency "parser", "~> 2.4"
33
- spec.add_runtime_dependency "ast_utils", "~> 0.1.0"
33
+ spec.add_runtime_dependency "ast_utils", "~> 0.3.0"
34
34
  spec.add_runtime_dependency "activesupport", "~> 5.1"
35
35
  spec.add_runtime_dependency "rainbow", "~> 2.2.2", "< 4.0"
36
36
  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.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-13 00:00:00.000000000 Z
11
+ date: 2018-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.1.0
89
+ version: 0.3.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.1.0
96
+ version: 0.3.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: activesupport
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -151,8 +151,10 @@ files:
151
151
  - lib/steep/ast/annotation.rb
152
152
  - lib/steep/ast/annotation/collection.rb
153
153
  - lib/steep/ast/buffer.rb
154
+ - lib/steep/ast/builtin.rb
154
155
  - lib/steep/ast/location.rb
155
156
  - lib/steep/ast/method_type.rb
157
+ - lib/steep/ast/namespace.rb
156
158
  - lib/steep/ast/signature/alias.rb
157
159
  - lib/steep/ast/signature/class.rb
158
160
  - lib/steep/ast/signature/const.rb
@@ -167,6 +169,7 @@ files:
167
169
  - lib/steep/ast/types/boolean.rb
168
170
  - lib/steep/ast/types/bot.rb
169
171
  - lib/steep/ast/types/class.rb
172
+ - lib/steep/ast/types/hash.rb
170
173
  - lib/steep/ast/types/helper.rb
171
174
  - lib/steep/ast/types/instance.rb
172
175
  - lib/steep/ast/types/intersection.rb
@@ -196,7 +199,7 @@ files:
196
199
  - lib/steep/interface/method.rb
197
200
  - lib/steep/interface/method_type.rb
198
201
  - lib/steep/interface/substitution.rb
199
- - lib/steep/module_name.rb
202
+ - lib/steep/names.rb
200
203
  - lib/steep/parser.rb
201
204
  - lib/steep/parser.y
202
205
  - lib/steep/signature/errors.rb
@@ -214,7 +217,6 @@ files:
214
217
  - lib/steep/type_inference/constant_env.rb
215
218
  - lib/steep/type_inference/send_args.rb
216
219
  - lib/steep/type_inference/type_env.rb
217
- - lib/steep/type_name.rb
218
220
  - lib/steep/typing.rb
219
221
  - lib/steep/version.rb
220
222
  - manual/annotations.md
@@ -258,7 +260,10 @@ files:
258
260
  - smoke/extension/c.rb
259
261
  - smoke/extension/d.rb
260
262
  - smoke/hash/a.rb
263
+ - smoke/hash/a.rbi
261
264
  - smoke/hash/b.rb
265
+ - smoke/hash/c.rb
266
+ - smoke/hash/d.rb
262
267
  - smoke/hello/hello.rb
263
268
  - smoke/hello/hello.rbi
264
269
  - smoke/if/a.rb
@@ -266,6 +271,8 @@ files:
266
271
  - smoke/implements/a.rbi
267
272
  - smoke/initialize/a.rb
268
273
  - smoke/initialize/a.rbi
274
+ - smoke/interface/a.rb
275
+ - smoke/interface/a.rbi
269
276
  - smoke/kwbegin/a.rb
270
277
  - smoke/lambda/a.rb
271
278
  - smoke/literal/a.rb
@@ -317,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
324
  version: '0'
318
325
  requirements: []
319
326
  rubyforge_project:
320
- rubygems_version: 2.7.3
327
+ rubygems_version: 2.7.6
321
328
  signing_key:
322
329
  specification_version: 4
323
330
  summary: Gradual Typing for Ruby