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