steep 0.1.0.pre2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +1 -1
- data/README.md +146 -33
- data/bin/smoke_runner.rb +43 -10
- data/lib/steep/ast/annotation/collection.rb +93 -0
- data/lib/steep/ast/annotation.rb +131 -0
- data/lib/steep/ast/buffer.rb +47 -0
- data/lib/steep/ast/location.rb +82 -0
- data/lib/steep/ast/method_type.rb +116 -0
- data/lib/steep/ast/signature/class.rb +33 -0
- data/lib/steep/ast/signature/const.rb +17 -0
- data/lib/steep/ast/signature/env.rb +123 -0
- data/lib/steep/ast/signature/extension.rb +21 -0
- data/lib/steep/ast/signature/gvar.rb +17 -0
- data/lib/steep/ast/signature/interface.rb +31 -0
- data/lib/steep/ast/signature/members.rb +71 -0
- data/lib/steep/ast/signature/module.rb +21 -0
- data/lib/steep/ast/type_params.rb +13 -0
- data/lib/steep/ast/types/any.rb +39 -0
- data/lib/steep/ast/types/bot.rb +39 -0
- data/lib/steep/ast/types/class.rb +35 -0
- data/lib/steep/ast/types/helper.rb +21 -0
- data/lib/steep/ast/types/instance.rb +39 -0
- data/lib/steep/ast/types/intersection.rb +74 -0
- data/lib/steep/ast/types/name.rb +124 -0
- data/lib/steep/ast/types/self.rb +39 -0
- data/lib/steep/ast/types/top.rb +39 -0
- data/lib/steep/ast/types/union.rb +74 -0
- data/lib/steep/ast/types/var.rb +57 -0
- data/lib/steep/ast/types/void.rb +35 -0
- data/lib/steep/cli.rb +28 -1
- data/lib/steep/drivers/annotations.rb +32 -0
- data/lib/steep/drivers/check.rb +53 -77
- data/lib/steep/drivers/scaffold.rb +303 -0
- data/lib/steep/drivers/utils/each_signature.rb +66 -0
- data/lib/steep/drivers/utils/validator.rb +115 -0
- data/lib/steep/drivers/validate.rb +39 -0
- data/lib/steep/errors.rb +291 -19
- data/lib/steep/interface/abstract.rb +44 -0
- data/lib/steep/interface/builder.rb +470 -0
- data/lib/steep/interface/instantiated.rb +126 -0
- data/lib/steep/interface/ivar_chain.rb +26 -0
- data/lib/steep/interface/method.rb +60 -0
- data/lib/steep/{interface.rb → interface/method_type.rb} +111 -100
- data/lib/steep/interface/substitution.rb +65 -0
- data/lib/steep/module_name.rb +116 -0
- data/lib/steep/parser.rb +1314 -814
- data/lib/steep/parser.y +536 -175
- data/lib/steep/source.rb +220 -25
- data/lib/steep/subtyping/check.rb +673 -0
- data/lib/steep/subtyping/constraints.rb +275 -0
- data/lib/steep/subtyping/relation.rb +41 -0
- data/lib/steep/subtyping/result.rb +126 -0
- data/lib/steep/subtyping/trace.rb +48 -0
- data/lib/steep/subtyping/variable_occurrence.rb +49 -0
- data/lib/steep/subtyping/variable_variance.rb +69 -0
- data/lib/steep/type_construction.rb +1630 -524
- data/lib/steep/type_inference/block_params.rb +100 -0
- data/lib/steep/type_inference/constant_env.rb +55 -0
- data/lib/steep/type_inference/send_args.rb +222 -0
- data/lib/steep/type_inference/type_env.rb +226 -0
- data/lib/steep/type_name.rb +27 -7
- data/lib/steep/typing.rb +4 -0
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +71 -16
- data/smoke/and/a.rb +4 -2
- data/smoke/array/a.rb +4 -5
- data/smoke/array/b.rb +4 -4
- data/smoke/block/a.rb +2 -2
- data/smoke/block/a.rbi +2 -0
- data/smoke/block/b.rb +15 -0
- data/smoke/case/a.rb +3 -3
- data/smoke/class/a.rb +3 -3
- data/smoke/class/b.rb +0 -2
- data/smoke/class/d.rb +2 -2
- data/smoke/class/e.rb +1 -1
- data/smoke/class/f.rb +2 -2
- data/smoke/class/g.rb +8 -0
- data/smoke/const/a.rb +3 -3
- data/smoke/dstr/a.rb +1 -1
- data/smoke/ensure/a.rb +22 -0
- data/smoke/enumerator/a.rb +6 -6
- data/smoke/enumerator/b.rb +22 -0
- data/smoke/extension/a.rb +2 -2
- data/smoke/extension/b.rb +3 -3
- data/smoke/extension/c.rb +1 -1
- data/smoke/hello/hello.rb +2 -2
- data/smoke/if/a.rb +4 -2
- data/smoke/kwbegin/a.rb +8 -0
- data/smoke/literal/a.rb +5 -5
- data/smoke/method/a.rb +5 -5
- data/smoke/method/a.rbi +4 -0
- data/smoke/method/b.rb +29 -0
- data/smoke/module/a.rb +3 -3
- data/smoke/module/a.rbi +9 -0
- data/smoke/module/b.rb +2 -2
- data/smoke/module/c.rb +1 -1
- data/smoke/module/d.rb +5 -0
- data/smoke/module/e.rb +13 -0
- data/smoke/module/f.rb +13 -0
- data/smoke/rescue/a.rb +62 -0
- data/smoke/super/a.rb +2 -2
- data/smoke/type_case/a.rb +35 -0
- data/smoke/yield/a.rb +2 -2
- data/stdlib/builtin.rbi +463 -24
- data/steep.gemspec +3 -2
- metadata +91 -29
- data/lib/steep/annotation.rb +0 -223
- data/lib/steep/signature/class.rb +0 -450
- data/lib/steep/signature/extension.rb +0 -51
- data/lib/steep/signature/interface.rb +0 -49
- data/lib/steep/types/any.rb +0 -31
- data/lib/steep/types/class.rb +0 -27
- data/lib/steep/types/instance.rb +0 -27
- data/lib/steep/types/merge.rb +0 -32
- data/lib/steep/types/name.rb +0 -57
- data/lib/steep/types/union.rb +0 -42
- data/lib/steep/types/var.rb +0 -38
- data/lib/steep/types.rb +0 -4
@@ -0,0 +1,100 @@
|
|
1
|
+
module Steep
|
2
|
+
module TypeInference
|
3
|
+
class BlockParams
|
4
|
+
class Param
|
5
|
+
attr_reader :var
|
6
|
+
attr_reader :type
|
7
|
+
attr_reader :value
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def initialize(var:, type:, value:, node:)
|
11
|
+
@var = var
|
12
|
+
@type = type
|
13
|
+
@value = value
|
14
|
+
@node = node
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
other.is_a?(Param) && other.var == var && other.type == type && other.value == value && other.node == node
|
19
|
+
end
|
20
|
+
|
21
|
+
alias eql? ==
|
22
|
+
|
23
|
+
def hash
|
24
|
+
self.class.hash ^ var.hash ^ type.hash ^ value.hash ^ node.hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :params
|
29
|
+
attr_reader :rest
|
30
|
+
|
31
|
+
def initialize(params:, rest:)
|
32
|
+
@params = params
|
33
|
+
@rest = rest
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_node(node, annotations:)
|
37
|
+
params = []
|
38
|
+
rest = nil
|
39
|
+
|
40
|
+
node.children.each do |arg|
|
41
|
+
var = arg.children.first
|
42
|
+
type = annotations.lookup_var_type(var.name)
|
43
|
+
|
44
|
+
case arg.type
|
45
|
+
when :arg, :procarg0
|
46
|
+
params << Param.new(var: var, type: type, value: nil, node: arg)
|
47
|
+
when :optarg
|
48
|
+
params << Param.new(var: var, type: type, value: arg.children.last, node: arg)
|
49
|
+
when :restarg
|
50
|
+
rest = Param.new(var: var, type: type, value: nil, node: arg)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
new(
|
55
|
+
params: params,
|
56
|
+
rest: rest
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def zip(params_type)
|
61
|
+
[].tap do |zip|
|
62
|
+
types = params_type.flat_unnamed_params
|
63
|
+
params.each do |param|
|
64
|
+
type = types.shift&.last || params_type.rest || AST::Types::Any.new
|
65
|
+
|
66
|
+
if type
|
67
|
+
zip << [param, type]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if rest
|
72
|
+
if types.empty?
|
73
|
+
array = AST::Types::Name.new_instance(
|
74
|
+
name: :Array,
|
75
|
+
args: [params_type.rest || AST::Types::Any.new]
|
76
|
+
)
|
77
|
+
zip << [rest, array]
|
78
|
+
else
|
79
|
+
union = AST::Types::Union.build(types: types.map(&:last) + [params_type.rest])
|
80
|
+
array = AST::Types::Name.new_instance(
|
81
|
+
name: :Array,
|
82
|
+
args: [union]
|
83
|
+
)
|
84
|
+
zip << [rest, array]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def each(&block)
|
91
|
+
if block_given?
|
92
|
+
params.each &block
|
93
|
+
yield rest if rest
|
94
|
+
else
|
95
|
+
enum_for :each
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Steep
|
2
|
+
module TypeInference
|
3
|
+
class ConstantEnv
|
4
|
+
attr_reader :builder
|
5
|
+
attr_reader :current_namespace
|
6
|
+
attr_reader :cache
|
7
|
+
|
8
|
+
def initialize(builder:, current_namespace:)
|
9
|
+
@cache = {}
|
10
|
+
@builder = builder
|
11
|
+
@current_namespace = current_namespace
|
12
|
+
end
|
13
|
+
|
14
|
+
def signatures
|
15
|
+
builder.signatures
|
16
|
+
end
|
17
|
+
|
18
|
+
def lookup(name)
|
19
|
+
unless cache.key?(name)
|
20
|
+
cache[name] = lookup0(name, namespace: current_namespace)
|
21
|
+
end
|
22
|
+
|
23
|
+
cache[name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def lookup0(name, namespace:)
|
27
|
+
if name.absolute?
|
28
|
+
case
|
29
|
+
when signatures.module_name?(name)
|
30
|
+
AST::Types::Name.new_module(name: name)
|
31
|
+
when signatures.class_name?(name)
|
32
|
+
AST::Types::Name.new_class(name: name, constructor: true)
|
33
|
+
when signatures.const_name?(name)
|
34
|
+
builder.absolute_type(signatures.find_const(name).type, current: nil)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
if namespace
|
38
|
+
case
|
39
|
+
when signatures.module_name?(name, current_module: namespace)
|
40
|
+
AST::Types::Name.new_module(name: namespace + name)
|
41
|
+
when signatures.class_name?(name, current_module: namespace)
|
42
|
+
AST::Types::Name.new_class(name: namespace + name, constructor: true)
|
43
|
+
when signatures.const_name?(name, current_module: namespace)
|
44
|
+
builder.absolute_type(signatures.find_const(name, current_module: namespace).type, current: nil)
|
45
|
+
else
|
46
|
+
lookup0(name, namespace: namespace.parent)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
lookup0(name.absolute!, namespace: nil)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module Steep
|
2
|
+
module TypeInference
|
3
|
+
class SendArgs
|
4
|
+
attr_reader :args
|
5
|
+
attr_reader :kw_args
|
6
|
+
|
7
|
+
def initialize(args:, kw_args:)
|
8
|
+
@args = args
|
9
|
+
@kw_args = kw_args
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_nodes(nodes)
|
13
|
+
args = []
|
14
|
+
last_hash = nil
|
15
|
+
|
16
|
+
nodes.each do |node|
|
17
|
+
if last_hash
|
18
|
+
args << last_hash
|
19
|
+
last_hash = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
case node.type
|
23
|
+
when :hash
|
24
|
+
last_hash = node
|
25
|
+
else
|
26
|
+
args << node
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if last_hash
|
31
|
+
unless kw_args?(last_hash)
|
32
|
+
args << last_hash
|
33
|
+
last_hash = nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
new(args: args, kw_args: last_hash)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.kw_args?(node)
|
41
|
+
node.children.all? do |child|
|
42
|
+
case child.type
|
43
|
+
when :pair
|
44
|
+
child.children[0].type == :sym
|
45
|
+
when :kwsplat
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def each_keyword_arg
|
52
|
+
if block_given?
|
53
|
+
if kw_args
|
54
|
+
kw_args.children.each do |node|
|
55
|
+
if node.type == :pair
|
56
|
+
yield node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
else
|
61
|
+
enum_for :each_keyword_arg
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def kwsplat_nodes
|
66
|
+
if kw_args
|
67
|
+
kw_args.children.select do |node|
|
68
|
+
node.type == :kwsplat
|
69
|
+
end
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def zip(params)
|
76
|
+
Set.new(
|
77
|
+
[].tap do |pairs|
|
78
|
+
consumed_keywords = Set.new
|
79
|
+
rest_types = []
|
80
|
+
|
81
|
+
params.required_keywords.each do |name, type|
|
82
|
+
if (node = each_keyword_arg.find {|pair| pair.children[0].children[0] == name })
|
83
|
+
pairs << [node.children[1], type]
|
84
|
+
consumed_keywords << name
|
85
|
+
else
|
86
|
+
if kwsplat_nodes.any?
|
87
|
+
rest_types << type
|
88
|
+
else
|
89
|
+
return
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
params.optional_keywords.each do |name, type|
|
95
|
+
if (node = each_keyword_arg.find {|pair| pair.children[0].children[0] == name })
|
96
|
+
pairs << [node.children[1], type]
|
97
|
+
consumed_keywords << name
|
98
|
+
else
|
99
|
+
if kwsplat_nodes.any?
|
100
|
+
rest_types << type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if params.rest_keywords
|
106
|
+
each_keyword_arg do |pair|
|
107
|
+
name = pair.children[0].children[0]
|
108
|
+
node = pair.children[1]
|
109
|
+
|
110
|
+
unless consumed_keywords.include?(name)
|
111
|
+
pairs << [node, params.rest_keywords]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if kwsplat_nodes.any?
|
116
|
+
pairs << [kw_args,
|
117
|
+
AST::Types::Name.new_instance(
|
118
|
+
name: "::Hash",
|
119
|
+
args: [
|
120
|
+
AST::Types::Name.new_instance(name: "::Symbol"),
|
121
|
+
AST::Types::Union.build(types: rest_types + [params.rest_keywords])
|
122
|
+
]
|
123
|
+
)]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
if params.has_keyword?
|
128
|
+
if !params.rest_keywords
|
129
|
+
if kwsplat_nodes.empty?
|
130
|
+
if each_keyword_arg.any? {|pair| !consumed_keywords.include?(pair.children[0].children[0]) }
|
131
|
+
return
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
args = self.args.dup
|
138
|
+
unless params.has_keyword?
|
139
|
+
args << kw_args if kw_args
|
140
|
+
end
|
141
|
+
|
142
|
+
arg_types = {}
|
143
|
+
|
144
|
+
params.required.each do |param|
|
145
|
+
if args.any?
|
146
|
+
next_arg(args) do |arg|
|
147
|
+
save_arg_type(arg, param, arg_types)
|
148
|
+
end
|
149
|
+
consume_arg(args)
|
150
|
+
else
|
151
|
+
return
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
params.optional.each do |param|
|
156
|
+
next_arg(args) do |arg|
|
157
|
+
save_arg_type(arg, param, arg_types)
|
158
|
+
end
|
159
|
+
consume_arg(args)
|
160
|
+
end
|
161
|
+
|
162
|
+
if args.any?
|
163
|
+
if params.rest
|
164
|
+
args.each do |arg|
|
165
|
+
save_arg_type(arg, params.rest, arg_types)
|
166
|
+
end
|
167
|
+
else
|
168
|
+
if args.none? {|arg| arg.type == :splat }
|
169
|
+
return
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
(self.args + [kw_args].compact).each do |arg|
|
175
|
+
types = arg_types[arg.object_id]
|
176
|
+
|
177
|
+
if types
|
178
|
+
if arg.type == :splat
|
179
|
+
type = AST::Types::Name.new_instance(name: "::Array", args: [AST::Types::Union.build(types: types)])
|
180
|
+
else
|
181
|
+
type = AST::Types::Union.build(types: types)
|
182
|
+
end
|
183
|
+
pairs << [arg, type]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
def save_arg_type(arg, type, hash)
|
191
|
+
if hash.key?(arg.object_id)
|
192
|
+
types = hash[arg.object_id]
|
193
|
+
else
|
194
|
+
types = hash[arg.object_id] = []
|
195
|
+
end
|
196
|
+
|
197
|
+
types << type
|
198
|
+
end
|
199
|
+
|
200
|
+
def next_arg(args)
|
201
|
+
if args.any?
|
202
|
+
case args[0].type
|
203
|
+
when :splat
|
204
|
+
args.each do |arg|
|
205
|
+
yield arg
|
206
|
+
end
|
207
|
+
else
|
208
|
+
yield args[0]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def consume_arg(args)
|
214
|
+
if args.any?
|
215
|
+
unless args[0].type == :splat
|
216
|
+
args.shift
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module Steep
|
2
|
+
module TypeInference
|
3
|
+
class TypeEnv
|
4
|
+
attr_reader :subtyping
|
5
|
+
attr_reader :lvar_types
|
6
|
+
attr_reader :const_types
|
7
|
+
attr_reader :gvar_types
|
8
|
+
attr_reader :ivar_types
|
9
|
+
attr_reader :const_env
|
10
|
+
|
11
|
+
def initialize(subtyping:, const_env:)
|
12
|
+
@subtyping = subtyping
|
13
|
+
@lvar_types = {}
|
14
|
+
@const_types = {}
|
15
|
+
@gvar_types = {}
|
16
|
+
@ivar_types = {}
|
17
|
+
@const_env = const_env
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize_copy(other)
|
21
|
+
@subtyping = other.subtyping
|
22
|
+
@lvar_types = other.lvar_types.dup
|
23
|
+
@const_types = other.const_types.dup
|
24
|
+
@gvar_types = other.gvar_types.dup
|
25
|
+
@ivar_types = other.ivar_types.dup
|
26
|
+
@const_env = other.const_env
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.build(annotations:, signatures:, subtyping:, const_env:)
|
30
|
+
new(subtyping: subtyping, const_env: const_env).tap do |env|
|
31
|
+
annotations.var_types.each do |name, annot|
|
32
|
+
env.set(lvar: name, type: subtyping.builder.absolute_type(annot.type, current: const_env.current_namespace))
|
33
|
+
end
|
34
|
+
annotations.ivar_types.each do |name, type|
|
35
|
+
env.set(ivar: name, type: subtyping.builder.absolute_type(type, current: const_env.current_namespace))
|
36
|
+
end
|
37
|
+
annotations.const_types.each do |name, type|
|
38
|
+
env.set(const: name, type: subtyping.builder.absolute_type(type, current: const_env.current_namespace))
|
39
|
+
end
|
40
|
+
signatures.globals.each do |name, annot|
|
41
|
+
type = subtyping.builder.absolute_type(annot.type, current: nil)
|
42
|
+
env.set(gvar: name, type: type)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_annotations(lvar_types: {}, ivar_types: {}, const_types: {}, gvar_types: {}, &block)
|
48
|
+
dup.tap do |env|
|
49
|
+
merge!(original_env: env.lvar_types, override_env: lvar_types, &block)
|
50
|
+
merge!(original_env: env.ivar_types, override_env: ivar_types, &block)
|
51
|
+
merge!(original_env: env.gvar_types, override_env: gvar_types, &block)
|
52
|
+
|
53
|
+
const_types.each do |name, annotated_type|
|
54
|
+
original_type = self.const_types[name] || const_env.lookup(name)
|
55
|
+
if original_type
|
56
|
+
assert_annotation name, original_type: original_type, annotated_type: annotated_type, &block
|
57
|
+
end
|
58
|
+
env.const_types[name] = annotated_type
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def join!(envs)
|
64
|
+
lvars = {}
|
65
|
+
|
66
|
+
common_vars = envs.map {|env| Set.new(env.lvar_types.keys) }.inject {|a, b| a & b }
|
67
|
+
|
68
|
+
envs.each do |env|
|
69
|
+
env.lvar_types.each do |name, type|
|
70
|
+
unless lvar_types.key?(name)
|
71
|
+
lvars[name] = [] unless lvars[name]
|
72
|
+
lvars[name] << type
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
lvars.each do |name, types|
|
78
|
+
if lvar_types.key?(name) || common_vars.member?(name)
|
79
|
+
set(lvar: name, type: AST::Types::Union.build(types: types))
|
80
|
+
else
|
81
|
+
set(lvar: name, type: AST::Types::Union.build(types: types + [AST::Types::Name.new_instance(name: "::NilClass")]))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @type method assert: (const: ModuleName) { () -> void } -> AST::Type
|
87
|
+
# | (gvar: Symbol) { () -> void } -> AST::Type
|
88
|
+
# | (ivar: Symbol) { () -> void } -> AST::Type
|
89
|
+
# | (lvar: Symbol) { () -> AST::Type | nil } -> AST::Type
|
90
|
+
def get(lvar: nil, const: nil, gvar: nil, ivar: nil)
|
91
|
+
case
|
92
|
+
when lvar
|
93
|
+
lvar_name(lvar).yield_self do |name|
|
94
|
+
if lvar_types.key?(name)
|
95
|
+
lvar_types[name]
|
96
|
+
else
|
97
|
+
ty = yield
|
98
|
+
lvar_types[name] = ty || AST::Types::Any.new
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when const
|
102
|
+
if const_types.key?(const)
|
103
|
+
const_types[const]
|
104
|
+
else
|
105
|
+
const_env.lookup(const).yield_self do |type|
|
106
|
+
if type
|
107
|
+
type
|
108
|
+
else
|
109
|
+
yield
|
110
|
+
AST::Types::Any.new
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
else
|
115
|
+
lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
|
116
|
+
if dictionary.key?(var_name)
|
117
|
+
dictionary[var_name]
|
118
|
+
else
|
119
|
+
yield
|
120
|
+
AST::Types::Any.new
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def set(lvar: nil, const: nil, gvar: nil, ivar: nil, type:)
|
127
|
+
case
|
128
|
+
when lvar
|
129
|
+
lvar_name(lvar).yield_self do |name|
|
130
|
+
lvar_types[name] = type
|
131
|
+
end
|
132
|
+
when const
|
133
|
+
const_types[const] = type
|
134
|
+
else
|
135
|
+
lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
|
136
|
+
dictionary[var_name] = type
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# @type method assign: (const: ModuleName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
|
142
|
+
# | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
|
143
|
+
# | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
|
144
|
+
# | (lvar: Symbol | LabeledName, type: AST::Type) { (Subtyping::Result::Failure) -> void } -> AST::Type
|
145
|
+
def assign(lvar: nil, const: nil, gvar: nil, ivar: nil, type:, &block)
|
146
|
+
case
|
147
|
+
when lvar
|
148
|
+
yield_self do
|
149
|
+
name = lvar_name(lvar)
|
150
|
+
var_type = lvar_types[name]
|
151
|
+
if var_type
|
152
|
+
assert_assign(var_type: var_type, lhs_type: type, &block)
|
153
|
+
else
|
154
|
+
lvar_types[name] = type
|
155
|
+
end
|
156
|
+
end
|
157
|
+
when const
|
158
|
+
yield_self do
|
159
|
+
const_type = const_types[const] || const_env.lookup(const)
|
160
|
+
if const_type
|
161
|
+
assert_assign(var_type: const_type, lhs_type: type, &block)
|
162
|
+
else
|
163
|
+
yield nil
|
164
|
+
AST::Types::Any.new
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
|
169
|
+
if dictionary.key?(var_name)
|
170
|
+
assert_assign(var_type: dictionary[var_name], lhs_type: type, &block)
|
171
|
+
else
|
172
|
+
yield nil
|
173
|
+
AST::Types::Any.new
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def lookup_dictionary(ivar:, gvar:)
|
180
|
+
case
|
181
|
+
when ivar
|
182
|
+
yield ivar, ivar_types
|
183
|
+
when gvar
|
184
|
+
yield gvar, gvar_types
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def lvar_name(lvar)
|
189
|
+
case lvar
|
190
|
+
when Symbol
|
191
|
+
lvar
|
192
|
+
when ASTUtils::Labeling::LabeledName
|
193
|
+
lvar.name
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def assert_assign(var_type:, lhs_type:)
|
198
|
+
relation = Subtyping::Relation.new(sub_type: lhs_type, super_type: var_type)
|
199
|
+
constraints = Subtyping::Constraints.new(unknowns: Set.new)
|
200
|
+
|
201
|
+
subtyping.check(relation, constraints: constraints).else do |result|
|
202
|
+
yield result
|
203
|
+
end
|
204
|
+
|
205
|
+
var_type
|
206
|
+
end
|
207
|
+
|
208
|
+
def merge!(original_env:, override_env:, &block)
|
209
|
+
original_env.merge!(override_env) do |name, original_type, override_type|
|
210
|
+
assert_annotation name, annotated_type: override_type, original_type: original_type, &block
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def assert_annotation(name, annotated_type:, original_type:)
|
215
|
+
relation = Subtyping::Relation.new(sub_type: annotated_type, super_type: original_type)
|
216
|
+
constraints = Subtyping::Constraints.new(unknowns: Set.new)
|
217
|
+
|
218
|
+
subtyping.check(relation, constraints: constraints).else do |result|
|
219
|
+
yield name, relation, result
|
220
|
+
end
|
221
|
+
|
222
|
+
annotated_type
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/steep/type_name.rb
CHANGED
@@ -12,21 +12,27 @@ module Steep
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def hash
|
15
|
-
name.hash
|
15
|
+
self.class.hash ^ name.hash
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
self == other
|
20
|
-
end
|
18
|
+
alias eql? ==
|
21
19
|
|
22
20
|
def to_s
|
23
21
|
name.to_s
|
24
22
|
end
|
23
|
+
|
24
|
+
def map_module_name
|
25
|
+
self.class.new(name: yield(name))
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
|
-
class Interface < Base
|
29
|
+
class Interface < Base
|
30
|
+
def map_module_name
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
28
34
|
|
29
|
-
class
|
35
|
+
class Class < Base
|
30
36
|
attr_reader :constructor
|
31
37
|
|
32
38
|
def to_s
|
@@ -39,7 +45,7 @@ module Steep
|
|
39
45
|
" noconstructor"
|
40
46
|
end
|
41
47
|
|
42
|
-
"#{name}.
|
48
|
+
"#{name}.class#{k}"
|
43
49
|
end
|
44
50
|
|
45
51
|
def initialize(name:, constructor:)
|
@@ -51,6 +57,10 @@ module Steep
|
|
51
57
|
other.is_a?(self.class) && other.name == name && other.constructor == constructor
|
52
58
|
end
|
53
59
|
|
60
|
+
def hash
|
61
|
+
self.class.hash ^ name.hash ^ constructor.hash
|
62
|
+
end
|
63
|
+
|
54
64
|
NOTHING = Object.new
|
55
65
|
|
56
66
|
def updated(constructor: NOTHING)
|
@@ -60,6 +70,16 @@ module Steep
|
|
60
70
|
|
61
71
|
self.class.new(name: name, constructor: constructor)
|
62
72
|
end
|
73
|
+
|
74
|
+
def map_module_name
|
75
|
+
self.class.new(name: yield(name), constructor: constructor)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Module < Base
|
80
|
+
def to_s
|
81
|
+
"#{name}.module"
|
82
|
+
end
|
63
83
|
end
|
64
84
|
|
65
85
|
class Instance < Base; end
|
data/lib/steep/typing.rb
CHANGED
data/lib/steep/version.rb
CHANGED