steep 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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