steep 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/LICENSE +21 -0
- data/bin/smoke_runner.rb +3 -0
- data/lib/steep/ast/annotation/collection.rb +120 -43
- data/lib/steep/ast/annotation.rb +5 -10
- data/lib/steep/ast/location.rb +1 -1
- data/lib/steep/ast/method_type.rb +3 -1
- data/lib/steep/ast/signature/alias.rb +19 -0
- data/lib/steep/ast/signature/env.rb +9 -0
- data/lib/steep/ast/signature/members.rb +4 -0
- data/lib/steep/ast/types/proc.rb +79 -0
- data/lib/steep/ast/types/void.rb +4 -0
- data/lib/steep/cli.rb +2 -1
- data/lib/steep/drivers/check.rb +4 -1
- data/lib/steep/errors.rb +13 -0
- data/lib/steep/interface/builder.rb +90 -47
- data/lib/steep/interface/instantiated.rb +1 -1
- data/lib/steep/interface/method.rb +8 -0
- data/lib/steep/interface/method_type.rb +40 -13
- data/lib/steep/parser.rb +1098 -1043
- data/lib/steep/parser.y +94 -36
- data/lib/steep/source.rb +5 -6
- data/lib/steep/subtyping/check.rb +162 -47
- data/lib/steep/subtyping/variable_occurrence.rb +2 -2
- data/lib/steep/subtyping/variable_variance.rb +3 -3
- data/lib/steep/type_construction.rb +630 -300
- data/lib/steep/type_inference/block_params.rb +186 -35
- data/lib/steep/type_inference/send_args.rb +12 -3
- data/lib/steep/type_inference/type_env.rb +10 -4
- data/lib/steep/type_name.rb +6 -0
- data/lib/steep/typing.rb +21 -2
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +2 -0
- data/smoke/alias/a.rb +19 -0
- data/smoke/alias/a.rbi +10 -0
- data/smoke/alias/b.rb +7 -0
- data/smoke/alias/c.rb +10 -0
- data/smoke/array/c.rb +7 -0
- data/smoke/block/c.rb +10 -0
- data/smoke/block/c.rbi +3 -0
- data/smoke/block/d.rb +15 -0
- data/smoke/class/c.rb +1 -1
- data/smoke/class/e.rb +1 -1
- data/smoke/class/h.rb +15 -0
- data/smoke/class/h.rbi +7 -0
- data/smoke/class/i.rb +17 -0
- data/smoke/class/i.rbi +9 -0
- data/smoke/extension/a.rbi +4 -0
- data/smoke/extension/d.rb +2 -0
- data/smoke/hash/a.rb +17 -0
- data/smoke/hash/b.rb +7 -0
- data/smoke/implements/a.rb +2 -2
- data/smoke/initialize/a.rb +1 -1
- data/smoke/lambda/a.rb +11 -0
- data/smoke/literal/b.rb +9 -0
- data/smoke/literal/literal_methods.rbi +4 -0
- data/smoke/method/c.rb +5 -0
- data/smoke/regression/array.rb +7 -0
- data/smoke/regression/hash.rb +7 -0
- data/smoke/regression/set_divide.rb +16 -0
- data/smoke/self/a.rb +2 -2
- data/stdlib/builtin.rbi +151 -1
- data/steep.gemspec +1 -0
- metadata +30 -4
@@ -15,7 +15,7 @@ module Steep
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def ==(other)
|
18
|
-
other.is_a?(
|
18
|
+
other.is_a?(self.class) && other.var == var && other.type == type && other.value == value && other.node == node
|
19
19
|
end
|
20
20
|
|
21
21
|
alias eql? ==
|
@@ -25,72 +25,223 @@ module Steep
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
attr_reader :
|
29
|
-
attr_reader :
|
28
|
+
attr_reader :leading_params
|
29
|
+
attr_reader :optional_params
|
30
|
+
attr_reader :rest_param
|
31
|
+
attr_reader :trailing_params
|
30
32
|
|
31
|
-
def initialize(
|
32
|
-
@
|
33
|
-
@
|
33
|
+
def initialize(leading_params:, optional_params:, rest_param:, trailing_params:)
|
34
|
+
@leading_params = leading_params
|
35
|
+
@optional_params = optional_params
|
36
|
+
@rest_param = rest_param
|
37
|
+
@trailing_params = trailing_params
|
38
|
+
end
|
39
|
+
|
40
|
+
def params
|
41
|
+
[].tap do |params|
|
42
|
+
params.push *leading_params
|
43
|
+
params.push *optional_params
|
44
|
+
params.push rest_param if rest_param
|
45
|
+
params.push *trailing_params
|
46
|
+
end
|
34
47
|
end
|
35
48
|
|
36
49
|
def self.from_node(node, annotations:)
|
37
|
-
|
38
|
-
|
50
|
+
leading_params = []
|
51
|
+
optional_params = []
|
52
|
+
rest_param = nil
|
53
|
+
trailing_params = []
|
54
|
+
|
55
|
+
default_params = leading_params
|
39
56
|
|
40
57
|
node.children.each do |arg|
|
41
58
|
var = arg.children.first
|
42
|
-
type = annotations.
|
59
|
+
type = annotations.var_type(lvar: var.name)
|
43
60
|
|
44
61
|
case arg.type
|
45
62
|
when :arg, :procarg0
|
46
|
-
|
63
|
+
default_params << Param.new(var: var, type: type, value: nil, node: arg)
|
47
64
|
when :optarg
|
48
|
-
|
65
|
+
default_params = trailing_params
|
66
|
+
optional_params << Param.new(var: var, type: type, value: arg.children.last, node: arg)
|
49
67
|
when :restarg
|
50
|
-
|
68
|
+
default_params = trailing_params
|
69
|
+
rest_param = Param.new(var: var, type: type, value: nil, node: arg)
|
51
70
|
end
|
52
71
|
end
|
53
72
|
|
54
73
|
new(
|
55
|
-
|
56
|
-
|
74
|
+
leading_params: leading_params,
|
75
|
+
optional_params: optional_params,
|
76
|
+
rest_param: rest_param,
|
77
|
+
trailing_params: trailing_params
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def params_type(hint: nil)
|
82
|
+
params_type0(hint: hint) or params_type0(hint: nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
def params_type0(hint:)
|
86
|
+
if hint
|
87
|
+
case
|
88
|
+
when leading_params.size == hint.required.size
|
89
|
+
leadings = leading_params.map.with_index do |param, index|
|
90
|
+
param.type || hint.required[index]
|
91
|
+
end
|
92
|
+
when !hint.rest && hint.optional.empty? && leading_params.size > hint.required.size
|
93
|
+
leadings = leading_params.take(hint.required.size).map.with_index do |param, index|
|
94
|
+
param.type || hint.required[index]
|
95
|
+
end
|
96
|
+
when !hint.rest && hint.optional.empty? && leading_params.size < hint.required.size
|
97
|
+
leadings = leading_params.map.with_index do |param, index|
|
98
|
+
param.type || hint.required[index]
|
99
|
+
end + hint.required.drop(leading_params.size)
|
100
|
+
else
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
|
104
|
+
case
|
105
|
+
when optional_params.size == hint.optional.size
|
106
|
+
optionals = optional_params.map.with_index do |param, index|
|
107
|
+
param.type || hint.optional[index]
|
108
|
+
end
|
109
|
+
when !hint.rest && optional_params.size > hint.optional.size
|
110
|
+
optionals = optional_params.take(hint.optional.size).map.with_index do |param, index|
|
111
|
+
param.type || hint.optional[index]
|
112
|
+
end
|
113
|
+
when !hint.rest && optional_params.size < hint.optional.size
|
114
|
+
optionals = optional_params.map.with_index do |param, index|
|
115
|
+
param.type || hint.optional[index]
|
116
|
+
end + hint.optional.drop(optional_params.size)
|
117
|
+
else
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
|
121
|
+
if rest_param && hint.rest
|
122
|
+
rest = rest_param.type&.yield_self {|ty| ty.args&.first } || hint.rest
|
123
|
+
else
|
124
|
+
rest = hint.rest
|
125
|
+
end
|
126
|
+
else
|
127
|
+
leadings = leading_params.map {|param| param.type || AST::Types::Any.new }
|
128
|
+
optionals = optional_params.map {|param| param.type || AST::Types::Any.new }
|
129
|
+
rest = rest_param&.yield_self {|param| param.type.args[0] }
|
130
|
+
end
|
131
|
+
|
132
|
+
Interface::Params.new(
|
133
|
+
required: leadings,
|
134
|
+
optional: optionals,
|
135
|
+
rest: rest,
|
136
|
+
required_keywords: {},
|
137
|
+
optional_keywords: {},
|
138
|
+
rest_keywords: nil
|
57
139
|
)
|
58
140
|
end
|
59
141
|
|
60
142
|
def zip(params_type)
|
143
|
+
if trailing_params.any?
|
144
|
+
Steep.logger.error "Block definition with trailing required parameters are not supported yet"
|
145
|
+
end
|
146
|
+
|
61
147
|
[].tap do |zip|
|
62
|
-
|
63
|
-
|
64
|
-
|
148
|
+
if expandable_params?(params_type) && expandable?
|
149
|
+
type = params_type.required[0]
|
150
|
+
|
151
|
+
case
|
152
|
+
when array?(type)
|
153
|
+
type_arg = type.args[0]
|
154
|
+
params.each do |param|
|
155
|
+
unless param == rest_param
|
156
|
+
zip << [param, AST::Types::Union.build(types: [type_arg, AST::Types::Nil.new])]
|
157
|
+
else
|
158
|
+
zip << [param, AST::Types::Name.new_instance(name: "::Array", args: [type_arg])]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
when type.is_a?(AST::Types::Tuple)
|
162
|
+
types = type.types.dup
|
163
|
+
(leading_params + optional_params).each do |param|
|
164
|
+
ty = types.shift
|
165
|
+
if ty
|
166
|
+
zip << [param, ty]
|
167
|
+
else
|
168
|
+
zip << [param, AST::Types::Nil.new]
|
169
|
+
end
|
170
|
+
end
|
65
171
|
|
66
|
-
|
67
|
-
|
172
|
+
if rest_param
|
173
|
+
if types.any?
|
174
|
+
union = AST::Types::Union.build(types: types)
|
175
|
+
zip << [rest_param, AST::Types::Name.new_instance(name: "::Array", args: [union])]
|
176
|
+
else
|
177
|
+
zip << [rest_param, AST::Types::Nil.new]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
else
|
182
|
+
types = params_type.flat_unnamed_params
|
183
|
+
|
184
|
+
(leading_params + optional_params).each do |param|
|
185
|
+
type = types.shift&.last || params_type.rest
|
186
|
+
|
187
|
+
if type
|
188
|
+
zip << [param, type]
|
189
|
+
else
|
190
|
+
zip << [param, AST::Types::Nil.new]
|
191
|
+
end
|
68
192
|
end
|
69
|
-
end
|
70
193
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
194
|
+
if rest_param
|
195
|
+
if types.empty?
|
196
|
+
array = AST::Types::Name.new_instance(
|
197
|
+
name: "::Array",
|
198
|
+
args: [params_type.rest || AST::Types::Any.new]
|
199
|
+
)
|
200
|
+
zip << [rest_param, array]
|
201
|
+
else
|
202
|
+
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
|
+
)
|
207
|
+
zip << [rest_param, array]
|
208
|
+
end
|
85
209
|
end
|
86
210
|
end
|
87
211
|
end
|
88
212
|
end
|
89
213
|
|
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
|
+
def expandable_params?(params_type)
|
221
|
+
if params_type.flat_unnamed_params.size == 1
|
222
|
+
case (type = params_type.required.first)
|
223
|
+
when AST::Types::Tuple
|
224
|
+
true
|
225
|
+
when AST::Types::Name
|
226
|
+
array?(type)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def expandable?
|
232
|
+
case
|
233
|
+
when leading_params.size + trailing_params.size > 1
|
234
|
+
true
|
235
|
+
when (leading_params.any? || trailing_params.any?) && rest_param
|
236
|
+
true
|
237
|
+
when params.size == 1 && params[0].node.type == :arg
|
238
|
+
true
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
90
242
|
def each(&block)
|
91
243
|
if block_given?
|
92
244
|
params.each &block
|
93
|
-
yield rest if rest
|
94
245
|
else
|
95
246
|
enum_for :each
|
96
247
|
end
|
@@ -3,15 +3,24 @@ module Steep
|
|
3
3
|
class SendArgs
|
4
4
|
attr_reader :args
|
5
5
|
attr_reader :kw_args
|
6
|
+
attr_reader :block_pass_arg
|
6
7
|
|
7
|
-
def initialize(args:, kw_args:)
|
8
|
+
def initialize(args:, kw_args:, block_pass_arg:)
|
8
9
|
@args = args
|
9
10
|
@kw_args = kw_args
|
11
|
+
@block_pass_arg = block_pass_arg
|
10
12
|
end
|
11
13
|
|
12
14
|
def self.from_nodes(nodes)
|
15
|
+
nodes = nodes.dup
|
16
|
+
|
13
17
|
args = []
|
14
18
|
last_hash = nil
|
19
|
+
block_pass_arg = nil
|
20
|
+
|
21
|
+
if nodes.last&.type == :block_pass
|
22
|
+
block_pass_arg = nodes.pop
|
23
|
+
end
|
15
24
|
|
16
25
|
nodes.each do |node|
|
17
26
|
if last_hash
|
@@ -34,7 +43,7 @@ module Steep
|
|
34
43
|
end
|
35
44
|
end
|
36
45
|
|
37
|
-
new(args: args, kw_args: last_hash)
|
46
|
+
new(args: args, kw_args: last_hash, block_pass_arg: block_pass_arg)
|
38
47
|
end
|
39
48
|
|
40
49
|
def self.kw_args?(node)
|
@@ -72,7 +81,7 @@ module Steep
|
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
75
|
-
def zip(params)
|
84
|
+
def zip(params, block)
|
76
85
|
Set.new(
|
77
86
|
[].tap do |pairs|
|
78
87
|
consumed_keywords = Set.new
|
@@ -28,14 +28,14 @@ module Steep
|
|
28
28
|
|
29
29
|
def self.build(annotations:, signatures:, subtyping:, const_env:)
|
30
30
|
new(subtyping: subtyping, const_env: const_env).tap do |env|
|
31
|
-
annotations.
|
32
|
-
env.set(lvar: name, type:
|
31
|
+
annotations.lvar_types.each do |name, type|
|
32
|
+
env.set(lvar: name, type: type)
|
33
33
|
end
|
34
34
|
annotations.ivar_types.each do |name, type|
|
35
|
-
env.set(ivar: name, type:
|
35
|
+
env.set(ivar: name, type: type)
|
36
36
|
end
|
37
37
|
annotations.const_types.each do |name, type|
|
38
|
-
env.set(const: name, type:
|
38
|
+
env.set(const: name, type: type)
|
39
39
|
end
|
40
40
|
signatures.globals.each do |name, annot|
|
41
41
|
type = subtyping.builder.absolute_type(annot.type, current: nil)
|
@@ -195,6 +195,9 @@ module Steep
|
|
195
195
|
end
|
196
196
|
|
197
197
|
def assert_assign(var_type:, lhs_type:)
|
198
|
+
var_type = subtyping.expand_alias(var_type)
|
199
|
+
lhs_type = subtyping.expand_alias(lhs_type)
|
200
|
+
|
198
201
|
relation = Subtyping::Relation.new(sub_type: lhs_type, super_type: var_type)
|
199
202
|
constraints = Subtyping::Constraints.new(unknowns: Set.new)
|
200
203
|
|
@@ -212,6 +215,9 @@ module Steep
|
|
212
215
|
end
|
213
216
|
|
214
217
|
def assert_annotation(name, annotated_type:, original_type:)
|
218
|
+
annotated_type = subtyping.expand_alias(annotated_type)
|
219
|
+
original_type = subtyping.expand_alias(original_type)
|
220
|
+
|
215
221
|
relation = Subtyping::Relation.new(sub_type: annotated_type, super_type: original_type)
|
216
222
|
constraints = Subtyping::Constraints.new(unknowns: Set.new)
|
217
223
|
|
data/lib/steep/type_name.rb
CHANGED
data/lib/steep/typing.rb
CHANGED
@@ -5,9 +5,15 @@ module Steep
|
|
5
5
|
attr_reader :nodes
|
6
6
|
attr_reader :var_typing
|
7
7
|
attr_reader :parent
|
8
|
+
attr_reader :parent_last_update
|
9
|
+
attr_reader :last_update
|
10
|
+
attr_reader :should_update
|
8
11
|
|
9
|
-
def initialize(parent: nil)
|
12
|
+
def initialize(parent: nil, parent_last_update: parent&.last_update)
|
10
13
|
@parent = parent
|
14
|
+
@parent_last_update = parent_last_update
|
15
|
+
@last_update = parent&.last_update || 0
|
16
|
+
@should_update = false
|
11
17
|
|
12
18
|
@errors = []
|
13
19
|
@nodes = {}
|
@@ -23,6 +29,11 @@ module Steep
|
|
23
29
|
typing[node.__id__] = type
|
24
30
|
nodes[node.__id__] = node
|
25
31
|
|
32
|
+
if should_update
|
33
|
+
@last_update += 1
|
34
|
+
@should_update = false
|
35
|
+
end
|
36
|
+
|
26
37
|
type
|
27
38
|
end
|
28
39
|
|
@@ -65,7 +76,14 @@ module Steep
|
|
65
76
|
end
|
66
77
|
|
67
78
|
def new_child
|
68
|
-
|
79
|
+
child = self.class.new(parent: self)
|
80
|
+
@should_update = true
|
81
|
+
|
82
|
+
if block_given?
|
83
|
+
yield child
|
84
|
+
else
|
85
|
+
child
|
86
|
+
end
|
69
87
|
end
|
70
88
|
|
71
89
|
def each_typing
|
@@ -76,6 +94,7 @@ module Steep
|
|
76
94
|
|
77
95
|
def save!
|
78
96
|
raise "Unexpected save!" unless parent
|
97
|
+
raise "Parent modified since new_child" unless parent.last_update == parent_last_update
|
79
98
|
|
80
99
|
each_typing do |node, type|
|
81
100
|
parent.add_typing(node, type)
|
data/lib/steep/version.rb
CHANGED
data/lib/steep.rb
CHANGED
@@ -25,6 +25,7 @@ require "steep/ast/types/nil"
|
|
25
25
|
require "steep/ast/types/literal"
|
26
26
|
require "steep/ast/types/boolean"
|
27
27
|
require "steep/ast/types/tuple"
|
28
|
+
require "steep/ast/types/proc"
|
28
29
|
require "steep/ast/method_type"
|
29
30
|
require "steep/ast/type_params"
|
30
31
|
require "steep/ast/signature/class"
|
@@ -35,6 +36,7 @@ require "steep/ast/signature/interface"
|
|
35
36
|
require "steep/ast/signature/env"
|
36
37
|
require "steep/ast/signature/const"
|
37
38
|
require "steep/ast/signature/gvar"
|
39
|
+
require "steep/ast/signature/alias"
|
38
40
|
require "steep/ast/annotation"
|
39
41
|
require "steep/ast/annotation/collection"
|
40
42
|
require "steep/ast/buffer"
|
data/smoke/alias/a.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# @type var x: foo
|
2
|
+
x = ""
|
3
|
+
|
4
|
+
# !expects NoMethodError: type=foo, method=+
|
5
|
+
x + 123
|
6
|
+
|
7
|
+
# @type var y: bar<Integer>
|
8
|
+
y = x
|
9
|
+
y = []
|
10
|
+
|
11
|
+
# @type var z: Symbol
|
12
|
+
case x
|
13
|
+
when String
|
14
|
+
# !expects IncompatibleAssignment: lhs_type=::Symbol, rhs_type=::String
|
15
|
+
z = x
|
16
|
+
when Integer
|
17
|
+
# !expects IncompatibleAssignment: lhs_type=::Symbol, rhs_type=::Integer
|
18
|
+
z = x
|
19
|
+
end
|
data/smoke/alias/a.rbi
ADDED
data/smoke/alias/b.rb
ADDED
data/smoke/alias/c.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# @type var x: String
|
2
|
+
|
3
|
+
# !expects IncompatibleAssignment: lhs_type=::String, rhs_type=::Integer
|
4
|
+
x = AliasMethodArg.new.foo(:foo)
|
5
|
+
|
6
|
+
# @type var name: name
|
7
|
+
name = :bar
|
8
|
+
|
9
|
+
# !expects IncompatibleAssignment: lhs_type=::String, rhs_type=::Integer
|
10
|
+
x = AliasMethodArg.new.foo(name)
|
data/smoke/array/c.rb
ADDED
data/smoke/block/c.rb
ADDED
data/smoke/block/c.rbi
ADDED
data/smoke/block/d.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# @type var a: ^(Integer) -> String
|
2
|
+
a = -> (x) { x.to_s }
|
3
|
+
|
4
|
+
# @type var b: Array<Float>
|
5
|
+
|
6
|
+
# !expects IncompatibleAssignment: lhs_type=::Array<::Float>, rhs_type=::Array<::String>
|
7
|
+
b = [1,2,3].map(&a)
|
8
|
+
|
9
|
+
# !expects IncompatibleAssignment: lhs_type=::Array<::Float>, rhs_type=::Array<::String>
|
10
|
+
b = [1,2,3].map(&:to_s)
|
11
|
+
|
12
|
+
# !expects* BlockTypeMismatch:
|
13
|
+
[1,2,3].map(&:no_such_method)
|
14
|
+
# !expects* BlockTypeMismatch:
|
15
|
+
[1,2,3].map(&:floor)
|
data/smoke/class/c.rb
CHANGED
data/smoke/class/e.rb
CHANGED
data/smoke/class/h.rb
ADDED
data/smoke/class/h.rbi
ADDED
data/smoke/class/i.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class IncompatibleChild
|
2
|
+
def foo(arg)
|
3
|
+
# @type var x: Symbol
|
4
|
+
# !expects IncompatibleAssignment: lhs_type=::Symbol, rhs_type=::Integer
|
5
|
+
x = super()
|
6
|
+
|
7
|
+
"123"
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
# !expects IncompatibleArguments: receiver=::IncompatibleChild, method_type=(name: ::String) -> any
|
12
|
+
super()
|
13
|
+
|
14
|
+
# !expects IncompatibleZuper: method=initialize
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
data/smoke/class/i.rbi
ADDED
data/smoke/extension/a.rbi
CHANGED
data/smoke/hash/a.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
{ foo: "bar" }.each do |x, y|
|
2
|
+
# @type var x1: Symbol
|
3
|
+
# @type var y1: String
|
4
|
+
|
5
|
+
x1 = x
|
6
|
+
y1 = y
|
7
|
+
end
|
8
|
+
|
9
|
+
{ foo: "bar" }.each.with_index do |x, y|
|
10
|
+
# @type var a: Symbol
|
11
|
+
# @type var b: String
|
12
|
+
# @type var c: Integer
|
13
|
+
|
14
|
+
a = x[0]
|
15
|
+
b = x[1]
|
16
|
+
c = y
|
17
|
+
end
|
data/smoke/hash/b.rb
ADDED
data/smoke/implements/a.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# !expects@+2 MethodDefinitionMissing: module
|
2
|
-
# !expects MethodDefinitionMissing: module
|
1
|
+
# !expects@+2 MethodDefinitionMissing: module=::A, method=baz
|
2
|
+
# !expects MethodDefinitionMissing: module=::A, method=self.bar
|
3
3
|
class A
|
4
4
|
# @implements A
|
5
5
|
|
data/smoke/initialize/a.rb
CHANGED
data/smoke/lambda/a.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# @type var a: Integer
|
2
|
+
|
3
|
+
# !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=::String
|
4
|
+
a = -> (x, y) do
|
5
|
+
# @type var x: String
|
6
|
+
# @type var y: String
|
7
|
+
x + y
|
8
|
+
end["foo", "bar"]
|
9
|
+
|
10
|
+
# !expects NoMethodError: type=::Object, method=lambda
|
11
|
+
b = lambda {|x| x + 1 }
|