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 +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
|