steep 0.1.0.pre → 0.1.0.pre2
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.
- checksums.yaml +4 -4
- data/README.md +72 -51
- data/bin/smoke_runner.rb +6 -2
- data/lib/steep/cli.rb +4 -4
- data/lib/steep/drivers/check.rb +4 -0
- data/lib/steep/interface.rb +11 -4
- data/lib/steep/parser.y +23 -5
- data/lib/steep/signature/class.rb +118 -26
- data/lib/steep/signature/errors.rb +28 -0
- data/lib/steep/signature/interface.rb +2 -1
- data/lib/steep/type_assignability.rb +13 -8
- data/lib/steep/type_construction.rb +41 -6
- data/lib/steep/type_name.rb +31 -1
- data/lib/steep/types/name.rb +2 -2
- data/lib/steep/version.rb +1 -1
- data/sig/signature.rbi +92 -0
- data/smoke/array/b.rb +16 -0
- data/smoke/class/a.rbi +15 -0
- data/smoke/class/d.rb +9 -0
- data/smoke/class/e.rb +12 -0
- data/smoke/class/f.rb +8 -0
- data/smoke/enumerator/a.rb +19 -0
- data/smoke/initialize/a.rb +12 -0
- data/smoke/initialize/a.rbi +3 -0
- data/smoke/module/a.rb +1 -1
- data/smoke/module/c.rb +23 -0
- data/stdlib/builtin.rbi +19 -4
- data/steep.gemspec +2 -0
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74822cb390656501c900a6a8c1cb9fbe60c4dc4c
|
4
|
+
data.tar.gz: 1bd94c67e5339288af5052ecdbfaa553ae151aee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
5
|
+
Install via RubyGems.
|
6
6
|
|
7
|
-
|
8
|
-
gem 'steep'
|
9
|
-
```
|
10
|
-
|
11
|
-
And then execute:
|
7
|
+
$ gem install steep --pre
|
12
8
|
|
13
|
-
|
9
|
+
Note that Steep is not released yet (pre-released). Add `--pre` for `gem install`.
|
14
10
|
|
15
|
-
|
11
|
+
### Requirements
|
16
12
|
|
17
|
-
|
13
|
+
Steep requires Ruby 2.4.
|
18
14
|
|
19
15
|
## Usage
|
20
16
|
|
21
|
-
|
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
|
-
|
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
|
-
|
33
|
-
|
25
|
+
interface _Foo {
|
26
|
+
def do_something: (String) -> any
|
27
|
+
}
|
34
28
|
|
35
|
-
|
29
|
+
module Fooable : _Foo {
|
30
|
+
def foo: (Array<String>) { (String) -> String } -> any
|
31
|
+
}
|
36
32
|
|
37
|
-
|
33
|
+
class SuperFoo {
|
34
|
+
include Fooable
|
38
35
|
|
39
|
-
|
36
|
+
def name: -> String
|
37
|
+
def do_something: (String) -> any
|
38
|
+
def bar: (?Symbol, size: Integer) -> Symbol
|
39
|
+
}
|
40
|
+
```
|
40
41
|
|
41
|
-
|
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
|
-
# @
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def
|
52
|
-
|
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
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
71
|
-
|
72
|
-
Steep allows generate a *scaffold* from Ruby programs.
|
66
|
+
Run `steep check` command to type check.
|
73
67
|
|
74
68
|
```
|
75
|
-
$ steep
|
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
|
-
|
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
|
-
|
81
|
-
* Method definition stub for each method
|
101
|
+
$ steep check --dump-all-types test.rb
|
82
102
|
|
83
|
-
|
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/
|
115
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/soutaro/steep.
|
95
116
|
|
data/bin/smoke_runner.rb
CHANGED
@@ -93,9 +93,13 @@ ARGV.each do |arg|
|
|
93
93
|
|
94
94
|
unless lines.empty?
|
95
95
|
lines.each do |line|
|
96
|
-
|
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
|
|
data/lib/steep/cli.rb
CHANGED
@@ -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(".")
|
data/lib/steep/drivers/check.rb
CHANGED
data/lib/steep/interface.rb
CHANGED
@@ -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) &&
|
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
|
data/lib/steep/parser.y
CHANGED
@@ -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[
|
121
|
-
class_method_member: DEF SELF DOT method_name COLON method_type_union { result = Signature::Members::ModuleMethod.new(name: val[
|
122
|
-
class_instance_method_member: DEF SELFQ DOT method_name COLON method_type_union { result = Signature::Members::ModuleInstanceMethod.new(name: val[
|
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
|
-
|
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?(
|
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?(
|
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?(
|
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
|
-
|
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(
|
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
|
-
|
92
|
-
|
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
|
-
|
129
|
-
|
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
|
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
|
-
|
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:
|
158
|
-
super_method:
|
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
|
-
|
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
|
-
|
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,
|
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
|