steep 0.1.0.pre → 0.1.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91398a985c422d844373a28dadd59f8e55b73e8f
4
- data.tar.gz: bdf3272c32938f7b5e762cfffce099b26630115b
3
+ metadata.gz: 74822cb390656501c900a6a8c1cb9fbe60c4dc4c
4
+ data.tar.gz: 1bd94c67e5339288af5052ecdbfaa553ae151aee
5
5
  SHA512:
6
- metadata.gz: 1345b14455a625814b4beafcab5ad3327f47b2dd0be200a5ecbc73157c83ab8074b6069a80acffb8fe563987c042f133820c33c07d1a7baa4039d29e35438735
7
- data.tar.gz: 455b3c6502ef94579bb859f12cbaca314285f426cf1a0b3cf5a9cad0c1533664738f8674b20ebde46ef8b8fcaa443ace1ece38f57922e5427465771afbf98f77
6
+ metadata.gz: 8102354b9e6ca837f22439b9b721e6e7ec67bc4b2e49de5db26a59d7167d5399ba04183b2e88d49afa3bf20cb88e5ed94ce6363a22caa0e7b5ec88ffd9963dfd
7
+ data.tar.gz: ea2304c8ee9850fc540c0b656daf4b100c97de914a4a124e332ef53117b0aa137c6f05a62402227a4601d51a74b1b5298c64980a6e3be9af300f480e41045e0a
data/README.md CHANGED
@@ -2,86 +2,107 @@
2
2
 
3
3
  ## Installation
4
4
 
5
- Add this line to your application's Gemfile:
5
+ Install via RubyGems.
6
6
 
7
- ```ruby
8
- gem 'steep'
9
- ```
10
-
11
- And then execute:
7
+ $ gem install steep --pre
12
8
 
13
- $ bundle
9
+ Note that Steep is not released yet (pre-released). Add `--pre` for `gem install`.
14
10
 
15
- Or install it yourself as:
11
+ ### Requirements
16
12
 
17
- $ gem install steep
13
+ Steep requires Ruby 2.4.
18
14
 
19
15
  ## Usage
20
16
 
21
- Run `steep check` command in project dir.
17
+ Steep does not infer types from Ruby programs, but requires declaring types and writing annotations.
18
+ You have to go on the following three steps.
22
19
 
23
- ```
24
- $ steep check
25
- $ steep check lib
26
- ```
20
+ ### 1. Declare Signatures
27
21
 
28
- It loads signatures from the global registry and `sig` dir in current dir.
29
- If you want to load signuatres from dir different from `sig`, pass `-I` parameter.
22
+ Declare signatures in `.rbi` files.
30
23
 
31
24
  ```
32
- $ steep check -I signauture -I sig .
33
- ```
25
+ interface _Foo {
26
+ def do_something: (String) -> any
27
+ }
34
28
 
35
- Note that when `-I` option is given, `steep` does not load signatures from `sig` dir.
29
+ module Fooable : _Foo {
30
+ def foo: (Array<String>) { (String) -> String } -> any
31
+ }
36
32
 
37
- ## Type Annotations
33
+ class SuperFoo {
34
+ include Fooable
38
35
 
39
- You have to write type annotations in your Ruby program.
36
+ def name: -> String
37
+ def do_something: (String) -> any
38
+ def bar: (?Symbol, size: Integer) -> Symbol
39
+ }
40
+ ```
40
41
 
41
- ```rb
42
- # @import ActiveRecord.Try
42
+ ### 2. Annotate Ruby Code
43
43
 
44
+ Write annotations to your Ruby code.
45
+
46
+ ```rb
44
47
  class Foo
45
- # @class Foo<A> extends Object
46
-
47
- # @attribute results: (readonly) Array<A>
48
- attr_reader :results
49
-
50
- # @type initialize: () -> _
51
- def initialize()
52
- @results = []
48
+ # @implements SuperFoo
49
+ # @type const Helper: FooHelper
50
+
51
+ # @dynamic name
52
+ attr_reader :name
53
+
54
+ def do_something(string)
55
+ # ...
53
56
  end
54
-
55
- # @type plus: (Addable<X, A>, X) -> A
56
- def plus(x, y)
57
- (x + y).try do |a|
58
- results << a
59
- a
60
- end
57
+
58
+ def bar(symbol = :default, size:)
59
+ Helper.run_bar(symbol, size: size)
61
60
  end
62
61
  end
63
62
  ```
64
63
 
65
- ## Signature
66
-
67
- Steep does not allow types to be constructed from Ruby programs.
68
- You have to write down signatures by yourself.
64
+ ### 3. Type Check
69
65
 
70
- ### Signature Scaffolding
71
-
72
- Steep allows generate a *scaffold* from Ruby programs.
66
+ Run `steep check` command to type check.
73
67
 
74
68
  ```
75
- $ steep scaffold lib/**/*.rb
69
+ $ steep check lib/foo.rb
70
+ foo.rb:41:18: NoMethodError: type=FooHelper, method=run_bar
71
+ foo.rb:42:24: NoMethodError: type=String, method==~
76
72
  ```
77
73
 
78
- The generated scaffold includes:
74
+ ## Commandline
75
+
76
+ `steep check` is the command to run type checking.
77
+
78
+ ### Signature Directory
79
+
80
+ Use `-I` option to specify signature file or signature directory.
81
+
82
+ $ steep check -I my-types.rbi test.rb
83
+
84
+ If you don't specify `-I` option, it assumes `sig` directory.
85
+
86
+ ### Detecting Fallback
87
+
88
+ When Steep finds a node which cannot be typed, it assumes the type of the node is *any*.
89
+ *any* type does not raise any type error so that fallback to *any* may hide some type errors.
90
+
91
+ Using `--fallback-any-is-error` option prints the fallbacks.
92
+
93
+ $ steep check --fallback-any-is-error test.rb
94
+
95
+ ### Dump All Types
96
+
97
+ When you are debugging, printing all types of all node in the source code may help.
98
+
99
+ Use `--dump-all-types` for that.
79
100
 
80
- * Signature definition for each class/module defined in the given program
81
- * Method definition stub for each method
101
+ $ steep check --dump-all-types test.rb
82
102
 
83
- The scaffold may be a good starting point for writing signatures.
103
+ ## Examples
84
104
 
105
+ You can find examples in `smoke` directory.
85
106
 
86
107
  ## Development
87
108
 
@@ -91,5 +112,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
91
112
 
92
113
  ## Contributing
93
114
 
94
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/steep.
115
+ Bug reports and pull requests are welcome on GitHub at https://github.com/soutaro/steep.
95
116
 
@@ -93,9 +93,13 @@ ARGV.each do |arg|
93
93
 
94
94
  unless lines.empty?
95
95
  lines.each do |line|
96
- puts Rainbow(" 🤦‍♀️ Unexpected error found: #{line}").red
96
+ if line =~ /:\d+:\d+:/
97
+ puts Rainbow(" 🤦‍♀️ Unexpected error found: #{line}").red
98
+ failed = true
99
+ else
100
+ puts Rainbow(" 🤦 Unexpected error found, but ignored: #{line}").yellow
101
+ end
97
102
  end
98
- failed = true
99
103
  end
100
104
  end
101
105
 
@@ -56,14 +56,14 @@ module Steep
56
56
  opts.on("--fallback-any-is-error") { fallback_any_is_error = true }
57
57
  end.parse!(argv)
58
58
 
59
- unless no_builtin
60
- signature_dirs.unshift Pathname(__dir__).join("../../stdlib").realpath
61
- end
62
-
63
59
  if signature_dirs.empty?
64
60
  signature_dirs << Pathname("sig")
65
61
  end
66
62
 
63
+ unless no_builtin
64
+ signature_dirs.unshift Pathname(__dir__).join("../../stdlib").realpath
65
+ end
66
+
67
67
  source_paths = argv.map {|path| Pathname(path) }
68
68
  if source_paths.empty?
69
69
  source_paths << Pathname(".")
@@ -34,6 +34,10 @@ module Steep
34
34
  end
35
35
  end
36
36
 
37
+ assignability.errors.each do |error|
38
+ error.puts(stdout)
39
+ end
40
+
37
41
  sources = []
38
42
  each_ruby_source do |source|
39
43
  sources << source
@@ -232,14 +232,19 @@ module Steep
232
232
  class Method
233
233
  attr_reader :super_method
234
234
  attr_reader :types
235
+ attr_reader :attributes
235
236
 
236
- def initialize(types:, super_method:)
237
+ def initialize(types:, super_method:, attributes:)
237
238
  @types = types
238
239
  @super_method = super_method
240
+ @attributes = attributes
239
241
  end
240
242
 
241
243
  def ==(other)
242
- other.is_a?(Method) && other.types == types && other.super_method == super_method
244
+ other.is_a?(Method) &&
245
+ other.types == types &&
246
+ other.super_method == super_method &&
247
+ other.attributes == attributes
243
248
  end
244
249
 
245
250
  def closed?
@@ -262,10 +267,12 @@ module Steep
262
267
  end
263
268
 
264
269
  attr_reader :name
270
+ attr_reader :params
265
271
  attr_reader :methods
266
272
 
267
- def initialize(name:, methods:)
273
+ def initialize(name:, params:, methods:)
268
274
  @name = name
275
+ @params = params
269
276
  @methods = methods
270
277
  end
271
278
 
@@ -274,7 +281,7 @@ module Steep
274
281
  end
275
282
 
276
283
  def ==(other)
277
- other.is_a?(self.class) && other.name == name && other.methods == methods
284
+ other.is_a?(self.class) && other.name == name && other.params == params && other.methods == methods
278
285
  end
279
286
  end
280
287
  end
@@ -66,13 +66,17 @@ simple_type: INTERFACE_NAME { result = Types::Name.interface(name: val[0]) }
66
66
  | INTERFACE_NAME LT type_seq GT { result = Types::Name.interface(name: val[0], params: val[2]) }
67
67
  | MODULE_NAME { result = Types::Name.instance(name: val[0])}
68
68
  | MODULE_NAME LT type_seq GT { result = Types::Name.instance(name: val[0], params: val[2]) }
69
- | CLASS_IDENT { result = Types::Name.module(name: val[0]) }
69
+ | CLASS_IDENT constructor { result = Types::Name.module(name: val[0], constructor: val[1]) }
70
70
  | ANY { result = Types::Any.new }
71
71
  | TVAR { result = Types::Var.new(name: val[0]) }
72
72
  | CLASS { result = Types::Class.new }
73
73
  | MODULE { result = Types::Class.new }
74
74
  | INSTANCE { result = Types::Instance.new }
75
75
 
76
+ constructor: { result = nil }
77
+ | CONSTRUCTOR
78
+ | NOCONSTRUCTOR
79
+
76
80
  type: simple_type
77
81
  | union_seq { result = Types::Union.new(types: val[0]) }
78
82
 
@@ -89,6 +93,8 @@ keyword: IDENT
89
93
  | CLASS { result = :class }
90
94
  | MODULE { result = :module }
91
95
  | INSTANCE { result = :instance }
96
+ | BLOCK { result = :block }
97
+ | INCLUDE { result = :include }
92
98
 
93
99
  signatures: { result = [] }
94
100
  | interface signatures { result = [val[0]] + val[1] }
@@ -117,12 +123,15 @@ class_member: instance_method_member { result = val[0] }
117
123
  | include_member { result = val[0] }
118
124
  | extend_member { result = val[0] }
119
125
 
120
- instance_method_member: DEF method_name COLON method_type_union { result = Signature::Members::InstanceMethod.new(name: val[1], types: val[3]) }
121
- class_method_member: DEF SELF DOT method_name COLON method_type_union { result = Signature::Members::ModuleMethod.new(name: val[3], types: val[5]) }
122
- class_instance_method_member: DEF SELFQ DOT method_name COLON method_type_union { result = Signature::Members::ModuleInstanceMethod.new(name: val[3], types: val[5]) }
126
+ instance_method_member: DEF constructor_method method_name COLON method_type_union { result = Signature::Members::InstanceMethod.new(name: val[2], types: val[4], constructor: val[1]) }
127
+ class_method_member: DEF constructor_method SELF DOT method_name COLON method_type_union { result = Signature::Members::ModuleMethod.new(name: val[4], types: val[6], constructor: val[1]) }
128
+ class_instance_method_member: DEF constructor_method SELFQ DOT method_name COLON method_type_union { result = Signature::Members::ModuleInstanceMethod.new(name: val[4], types: val[6], constructor: val[1]) }
123
129
  include_member: INCLUDE type { result = Signature::Members::Include.new(name: val[1]) }
124
130
  extend_member: EXTEND type { result = Signature::Members::Extend.new(name: val[1]) }
125
131
 
132
+ constructor_method: { result = false }
133
+ | LPAREN CONSTRUCTOR RPAREN { result = true }
134
+
126
135
  super_opt: { result = nil }
127
136
  | LTCOLON type { result = val[1] }
128
137
 
@@ -152,6 +161,11 @@ method_name: IDENT
152
161
  | INSTANCE { result = :instance }
153
162
  | OPERATOR
154
163
  | METHOD_NAME
164
+ | BLOCK { result = :block }
165
+ | INCLUDE { result = :include }
166
+ | CONSTRUCTOR { result = :constructor }
167
+ | NOCONSTRUCTOR { result = :noconstructor }
168
+ | GT GT { result = :>> }
155
169
 
156
170
  annotation: AT_TYPE VAR subject COLON type { result = Annotation::VarType.new(var: val[2], type: val[4]) }
157
171
  | AT_TYPE METHOD subject COLON method_type { result = Annotation::MethodType.new(method: val[2], type: val[4]) }
@@ -241,7 +255,7 @@ def next_token
241
255
  [:DOT, nil]
242
256
  when input.scan(/<:/)
243
257
  [:LTCOLON, nil]
244
- when input.scan(/(\[\]=)|(\[\])|===|==|\^|!=|<<|>>/)
258
+ when input.scan(/(\[\]=)|(\[\])|===|==|\^|!=|<</)
245
259
  [:OPERATOR, input.matched.to_sym]
246
260
  when input.scan(/</)
247
261
  [:LT, nil]
@@ -295,6 +309,10 @@ def next_token
295
309
  [:IVAR, nil]
296
310
  when input.scan(/extension\b/)
297
311
  [:EXTENSION, nil]
312
+ when input.scan(/constructor\b/)
313
+ [:CONSTRUCTOR, true]
314
+ when input.scan(/noconstructor\b/)
315
+ [:NOCONSTRUCTOR, false]
298
316
  when input.scan(/[A-Z]\w*\.(class|module)\b/)
299
317
  [:CLASS_IDENT, input.matched.gsub(/\.(class|module)$/, '').to_sym]
300
318
  when input.scan(/\w+(\!|\?)/)
@@ -2,48 +2,70 @@ module Steep
2
2
  module Signature
3
3
  module Members
4
4
  class InstanceMethod
5
+ # @implements Steep__SignatureMember__Method
6
+
7
+ # @dynamic name
5
8
  attr_reader :name
9
+ # @dynamic types
6
10
  attr_reader :types
7
11
 
8
- def initialize(name:, types:)
12
+ attr_reader :constructor
13
+
14
+ def initialize(name:, types:, constructor:)
9
15
  @name = name
10
16
  @types = types
17
+ @constructor = constructor
11
18
  end
12
19
 
13
20
  def ==(other)
14
- other.is_a?(InstanceMethod) && other.name == name && other.types == types
21
+ other.is_a?(self.class) && other.name == name && other.types == types && other.constructor == constructor
15
22
  end
16
23
  end
17
24
 
18
25
  class ModuleMethod
26
+ # @implements Steep__SignatureMember__Method
27
+
28
+ # @dynamic name
19
29
  attr_reader :name
30
+ # @dynamic types
20
31
  attr_reader :types
32
+ attr_reader :constructor
21
33
 
22
- def initialize(name:, types:)
34
+ def initialize(name:, types:, constructor:)
23
35
  @name = name
24
36
  @types = types
37
+ @constructor = constructor
25
38
  end
26
39
 
27
40
  def ==(other)
28
- other.is_a?(ModuleMethod) && other.name == name && other.types == types
41
+ other.is_a?(self.class) && other.name == name && other.types == types && other.constructor == constructor
29
42
  end
30
43
  end
31
44
 
32
45
  class ModuleInstanceMethod
46
+ # @implements Steep__SignatureMember__Method
47
+
48
+ # @dynamic name
33
49
  attr_reader :name
50
+ # @dynamic types
34
51
  attr_reader :types
52
+ attr_reader :constructor
35
53
 
36
- def initialize(name:, types:)
54
+ def initialize(name:, types:, constructor:)
37
55
  @name = name
38
56
  @types = types
57
+ @constructor = constructor
39
58
  end
40
59
 
41
60
  def ==(other)
42
- other.is_a?(ModuleInstanceMethod) && other.name == name && other.types == types
61
+ other.is_a?(self.class) && other.name == name && other.types == types && other.constructor == constructor
43
62
  end
44
63
  end
45
64
 
46
65
  class Include
66
+ # @implements Steep__SignatureMember__Include
67
+
68
+ # @dynamic name
47
69
  attr_reader :name
48
70
 
49
71
  def initialize(name:)
@@ -56,6 +78,9 @@ module Steep
56
78
  end
57
79
 
58
80
  class Extend
81
+ # @implements Steep__SignatureMember__Extend
82
+
83
+ # @dynamic name
59
84
  attr_reader :name
60
85
 
61
86
  def initialize(name:)
@@ -69,6 +94,8 @@ module Steep
69
94
  end
70
95
 
71
96
  module WithMethods
97
+ # @implements Steep__Signature__WithMethods
98
+
72
99
  def instance_methods(assignability:, klass:, instance:, params:)
73
100
  methods = super
74
101
 
@@ -77,19 +104,32 @@ module Steep
77
104
  members.each do |member|
78
105
  case member
79
106
  when Members::Include
80
- module_signature = assignability.lookup_included_signature(member.name)
107
+ # @type var include_member: Steep__SignatureMember__Include
108
+ include_member = member
109
+ module_signature = assignability.lookup_included_signature(include_member.name)
81
110
  merge_methods(methods, module_signature.instance_methods(assignability: assignability,
82
111
  klass: klass,
83
112
  instance: instance,
84
- params: module_signature.type_application_hash(member.name.params)))
113
+ params: module_signature.type_application_hash(include_member.name.params)))
114
+
85
115
  end
86
116
  end
87
117
 
88
118
  members.each do |member|
89
119
  case member
90
120
  when Members::InstanceMethod, Members::ModuleInstanceMethod
91
- method_types = member.types.map {|type| type.substitute(klass: klass, instance: instance, params: hash) }
92
- merge_methods(methods, member.name => Steep::Interface::Method.new(types: method_types, super_method: nil))
121
+ # @type var method_member: Steep__SignatureMember__Method
122
+ method_member = member
123
+ method_types = method_member.types.map {|type| type.substitute(klass: klass, instance: instance, params: hash) }
124
+
125
+ attributes = [].tap do |attrs|
126
+ attrs.push(:constructor) if method_member.constructor
127
+ end
128
+
129
+ merge_methods(methods,
130
+ method_member.name => Steep::Interface::Method.new(types: method_types,
131
+ super_method: nil,
132
+ attributes: attributes))
93
133
  end
94
134
  end
95
135
 
@@ -102,7 +142,7 @@ module Steep
102
142
  methods
103
143
  end
104
144
 
105
- def module_methods(assignability:, klass:, instance:, params:)
145
+ def module_methods(assignability:, klass:, instance:, params:, constructor:)
106
146
  methods = super
107
147
 
108
148
  members.each do |member|
@@ -112,7 +152,8 @@ module Steep
112
152
  merge_methods(methods, module_signature.module_methods(assignability: assignability,
113
153
  klass: klass,
114
154
  instance: instance,
115
- params: module_signature.type_application_hash(member.name.params)))
155
+ params: module_signature.type_application_hash(member.name.params),
156
+ constructor: constructor))
116
157
  when Members::Extend
117
158
  module_signature = assignability.lookup_included_signature(member.name)
118
159
  merge_methods(methods, module_signature.instance_methods(assignability: assignability,
@@ -125,24 +166,30 @@ module Steep
125
166
  members.each do |member|
126
167
  case member
127
168
  when Members::ModuleInstanceMethod, Members::ModuleMethod
128
- method_types = member.types.map {|type| type.substitute(klass: klass, instance: instance, params: {}) }
129
- merge_methods(methods, member.name => Steep::Interface::Method.new(types: method_types, super_method: nil))
169
+ # @type var method_member: Steep__SignatureMember__Method
170
+ method_member = member
171
+ method_types = method_member.types.map {|type| type.substitute(klass: klass, instance: instance, params: {}) }
172
+ merge_methods(methods,
173
+ method_member.name => Steep::Interface::Method.new(types: method_types,
174
+ super_method: nil,
175
+ attributes: []))
130
176
  end
131
177
  end
132
178
 
133
- if self.is_a?(Class)
179
+ if is_class? && constructor
134
180
  instance_methods = instance_methods(assignability: assignability, klass: klass, instance: instance, params: params)
135
181
  new_method = if instance_methods[:initialize]
136
182
  types = instance_methods[:initialize].types.map do |method_type|
137
183
  method_type.updated(return_type: instance)
138
184
  end
139
- Steep::Interface::Method.new(types: types, super_method: nil)
185
+ Steep::Interface::Method.new(types: types, super_method: nil, attributes: [])
140
186
  else
141
187
  Steep::Interface::Method.new(types: [Steep::Interface::MethodType.new(type_params: [],
142
188
  params: Steep::Interface::Params.empty,
143
189
  block: nil,
144
190
  return_type: instance)],
145
- super_method: nil)
191
+ super_method: nil,
192
+ attributes: [])
146
193
  end
147
194
  methods[:new] = new_method
148
195
  end
@@ -152,21 +199,27 @@ module Steep
152
199
 
153
200
  def merge_methods(methods, hash)
154
201
  hash.each_key do |name|
155
- method = hash[name]
202
+ new_method = hash[name]
203
+ old_method = methods[name]
204
+ attributes = (new_method.attributes + (old_method&.attributes || [])).sort.uniq
156
205
 
157
- methods[name] = Steep::Interface::Method.new(types: method.types,
158
- super_method: methods[name])
206
+ methods[name] = Steep::Interface::Method.new(types: new_method.types,
207
+ super_method: old_method,
208
+ attributes: attributes)
159
209
  end
160
210
  end
161
211
  end
162
212
 
163
213
  module WithMembers
214
+ # @implements Steep__Signature__WithMembers
164
215
  def each_type
165
216
  if block_given?
166
217
  members.each do |member|
167
218
  case member
168
219
  when Members::InstanceMethod, Members::ModuleMethod, Members::ModuleInstanceMethod
169
- member.types.each do |method_type|
220
+ # @type var method_member: Steep__SignatureMember__Method
221
+ method_member = member
222
+ method_member.types.each do |method_type|
170
223
  method_type.params.each_type do |type|
171
224
  yield type
172
225
  end
@@ -179,7 +232,9 @@ module Steep
179
232
  end
180
233
  end
181
234
  when Members::Include, Members::Extend
182
- yield member.name
235
+ # @type var mixin_member: _Steep__SignatureMember__Mixin
236
+ mixin_member = member
237
+ yield mixin_member.name
183
238
  else
184
239
  raise "Unknown member: #{member.class.inspect}"
185
240
  end
@@ -210,15 +265,23 @@ module Steep
210
265
  end
211
266
 
212
267
  module WithParams
268
+ # @implements Steep__Signature__WithParams
269
+
213
270
  def type_application_hash(args)
214
271
  Hash[params.zip(args)]
215
272
  end
216
273
  end
217
274
 
218
275
  class Module
276
+ # @implements Steep__Signature__Module
277
+
278
+ # @dynamic name
219
279
  attr_reader :name
280
+ # @dynamic params
220
281
  attr_reader :params
282
+ # @dynamic members
221
283
  attr_reader :members
284
+ # @dynamic self_type
222
285
  attr_reader :self_type
223
286
 
224
287
  prepend WithMethods
@@ -240,7 +303,7 @@ module Steep
240
303
  {}
241
304
  end
242
305
 
243
- def module_methods(assignability:, klass:, instance:, params:)
306
+ def module_methods(assignability:, klass:, instance:, params:, constructor:)
244
307
  {}
245
308
  end
246
309
 
@@ -264,13 +327,28 @@ module Steep
264
327
  params.map {|x| Types::Var.new(name: x) })
265
328
 
266
329
  validate_mixins(assignability, interface)
330
+
331
+ # FIXME: There is no check for initializer compatibility
332
+ if interface.methods.values.any? {|method| method.attributes.include?(:constructor) }
333
+ assignability.errors << Signature::Errors::ConstructorNoCheck.new(signature: self)
334
+ end
335
+ end
336
+
337
+ def is_class?
338
+ false
267
339
  end
268
340
  end
269
341
 
270
342
  class Class
343
+ # @implements Steep__Signature__Class
344
+
345
+ # @dynamic name
271
346
  attr_reader :name
347
+ # @dynamic params
272
348
  attr_reader :params
349
+ # @dynamic members
273
350
  attr_reader :members
351
+ # @dynamic super_class
274
352
  attr_reader :super_class
275
353
 
276
354
  prepend WithMethods
@@ -304,7 +382,7 @@ module Steep
304
382
  end
305
383
  end
306
384
 
307
- def module_methods(assignability:, klass:, instance:, params:)
385
+ def module_methods(assignability:, klass:, instance:, params:, constructor:)
308
386
  signature = assignability.lookup_class_signature(Types::Name.instance(name: :Class))
309
387
  class_methods = signature.instance_methods(assignability: assignability,
310
388
  klass: klass,
@@ -321,7 +399,11 @@ module Steep
321
399
  type.substitute(klass: klass, instance: instance, params: hash)
322
400
  end
323
401
 
324
- class_methods.merge!(signature.module_methods(assignability: assignability, klass: klass, instance: instance, params: super_class_params))
402
+ class_methods.merge!(signature.module_methods(assignability: assignability,
403
+ klass: klass,
404
+ instance: instance,
405
+ params: super_class_params,
406
+ constructor: constructor))
325
407
  end
326
408
  end
327
409
 
@@ -342,7 +424,8 @@ module Steep
342
424
  end
343
425
 
344
426
  interface = assignability.resolve_interface(TypeName::Instance.new(name: name),
345
- params.map {|x| Types::Var.new(name: x) })
427
+ params.map {|x| Types::Var.new(name: x) },
428
+ constructor: true)
346
429
 
347
430
  interface.methods.each_key do |method_name|
348
431
  method = interface.methods[method_name]
@@ -352,6 +435,15 @@ module Steep
352
435
  end
353
436
 
354
437
  validate_mixins(assignability, interface)
438
+
439
+ # FIXME: There is no check for initializer compatibility
440
+ if interface.methods.values.any? {|method| method.attributes.include?(:constructor) }
441
+ assignability.errors << Signature::Errors::ConstructorNoCheck.new(signature: self)
442
+ end
443
+ end
444
+
445
+ def is_class?
446
+ true
355
447
  end
356
448
  end
357
449
  end