typeprof 0.30.1 → 0.31.1
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 +23 -4
- data/lib/typeprof/cli/cli.rb +27 -7
- data/lib/typeprof/code_range.rb +9 -7
- data/lib/typeprof/core/ast/base.rb +27 -10
- data/lib/typeprof/core/ast/call.rb +85 -24
- data/lib/typeprof/core/ast/const.rb +7 -12
- data/lib/typeprof/core/ast/control.rb +345 -71
- data/lib/typeprof/core/ast/meta.rb +5 -5
- data/lib/typeprof/core/ast/method.rb +15 -5
- data/lib/typeprof/core/ast/misc.rb +78 -2
- data/lib/typeprof/core/ast/module.rb +10 -7
- data/lib/typeprof/core/ast/pattern.rb +9 -1
- data/lib/typeprof/core/ast/sig_decl.rb +163 -42
- data/lib/typeprof/core/ast/sig_type.rb +394 -24
- data/lib/typeprof/core/ast/value.rb +10 -2
- data/lib/typeprof/core/ast/variable.rb +32 -2
- data/lib/typeprof/core/ast.rb +17 -4
- data/lib/typeprof/core/builtin.rb +15 -9
- data/lib/typeprof/core/env/method.rb +21 -16
- data/lib/typeprof/core/env/method_entity.rb +11 -2
- data/lib/typeprof/core/env/module_entity.rb +57 -0
- data/lib/typeprof/core/env/narrowing.rb +131 -0
- data/lib/typeprof/core/env/static_read.rb +9 -8
- data/lib/typeprof/core/env.rb +41 -12
- data/lib/typeprof/core/graph/box.rb +208 -98
- data/lib/typeprof/core/graph/change_set.rb +44 -37
- data/lib/typeprof/core/graph/vertex.rb +4 -21
- data/lib/typeprof/core/service.rb +30 -1
- data/lib/typeprof/core/type.rb +50 -124
- data/lib/typeprof/core.rb +1 -0
- data/lib/typeprof/diagnostic.rb +5 -6
- data/lib/typeprof/lsp/messages.rb +21 -15
- data/lib/typeprof/lsp/server.rb +132 -39
- data/lib/typeprof/lsp/text.rb +1 -0
- data/lib/typeprof/version.rb +1 -1
- data/typeprof.conf.jsonc +22 -0
- data/typeprof.gemspec +1 -0
- metadata +19 -6
|
@@ -17,6 +17,29 @@ module TypeProf::Core
|
|
|
17
17
|
def retrieve_at(pos)
|
|
18
18
|
yield self if code_range.include?(pos)
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
def narrowings
|
|
22
|
+
@narrowings ||= [
|
|
23
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(false) }),
|
|
24
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(true) }),
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class ItLocalVariableReadNode < Node
|
|
30
|
+
def initialize(raw_node, lenv)
|
|
31
|
+
super(raw_node, lenv)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def attrs = {}
|
|
35
|
+
|
|
36
|
+
def install0(genv)
|
|
37
|
+
@lenv.get_var(:it)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def retrieve_at(pos)
|
|
41
|
+
yield self if code_range.include?(pos)
|
|
42
|
+
end
|
|
20
43
|
end
|
|
21
44
|
|
|
22
45
|
class LocalVariableWriteNode < Node
|
|
@@ -64,7 +87,7 @@ module TypeProf::Core
|
|
|
64
87
|
case @lenv.cref.scope_level
|
|
65
88
|
when :class, :instance
|
|
66
89
|
box = @changes.add_ivar_read_box(genv, lenv.cref.cpath, lenv.cref.scope_level == :class, @var)
|
|
67
|
-
@lenv.
|
|
90
|
+
@lenv.apply_ivar_narrowing(genv, self, @var, box.ret)
|
|
68
91
|
else
|
|
69
92
|
Source.new()
|
|
70
93
|
end
|
|
@@ -73,6 +96,13 @@ module TypeProf::Core
|
|
|
73
96
|
def retrieve_at(pos)
|
|
74
97
|
yield self if code_range.include?(pos)
|
|
75
98
|
end
|
|
99
|
+
|
|
100
|
+
def narrowings
|
|
101
|
+
@narrowings ||= [
|
|
102
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(false) }),
|
|
103
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(true) }),
|
|
104
|
+
]
|
|
105
|
+
end
|
|
76
106
|
end
|
|
77
107
|
|
|
78
108
|
class InstanceVariableWriteNode < Node
|
|
@@ -289,7 +319,7 @@ module TypeProf::Core
|
|
|
289
319
|
|
|
290
320
|
def install0(genv)
|
|
291
321
|
box = @changes.add_cvar_read_box(genv, lenv.cref.cpath, @var)
|
|
292
|
-
@lenv.
|
|
322
|
+
@lenv.apply_ivar_narrowing(genv, self, @var, box.ret)
|
|
293
323
|
end
|
|
294
324
|
|
|
295
325
|
def retrieve_at(pos)
|
data/lib/typeprof/core/ast.rb
CHANGED
|
@@ -58,6 +58,7 @@ module TypeProf::Core
|
|
|
58
58
|
when :begin_node then BeginNode.new(raw_node, lenv)
|
|
59
59
|
when :retry_node then RetryNode.new(raw_node, lenv)
|
|
60
60
|
when :rescue_modifier_node then RescueModifierNode.new(raw_node, lenv)
|
|
61
|
+
when :rescue_node then RescueNode.new(raw_node, lenv)
|
|
61
62
|
|
|
62
63
|
# constants
|
|
63
64
|
when :constant_read_node, :constant_path_node
|
|
@@ -92,6 +93,8 @@ module TypeProf::Core
|
|
|
92
93
|
# variables
|
|
93
94
|
when :local_variable_read_node
|
|
94
95
|
LocalVariableReadNode.new(raw_node, lenv)
|
|
96
|
+
when :it_local_variable_read_node
|
|
97
|
+
ItLocalVariableReadNode.new(raw_node, lenv)
|
|
95
98
|
when :local_variable_write_node
|
|
96
99
|
LocalVariableWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
|
|
97
100
|
when :local_variable_operator_write_node
|
|
@@ -223,7 +226,7 @@ module TypeProf::Core
|
|
|
223
226
|
when :flip_flop_node then FlipFlopNode.new(raw_node, lenv)
|
|
224
227
|
when :shareable_constant_node then create_node(raw_node.write, lenv)
|
|
225
228
|
when :match_required_node then MatchRequiredNode.new(raw_node, lenv)
|
|
226
|
-
when :match_predicate_node then
|
|
229
|
+
when :match_predicate_node then MatchPredicateNode.new(raw_node, lenv)
|
|
227
230
|
|
|
228
231
|
# call
|
|
229
232
|
when :super_node then SuperNode.new(raw_node, lenv)
|
|
@@ -267,6 +270,8 @@ module TypeProf::Core
|
|
|
267
270
|
IndexWriteNode.new(raw_node, dummy_node, lenv)
|
|
268
271
|
when :call_target_node
|
|
269
272
|
CallWriteNode.new(raw_node, dummy_node, lenv)
|
|
273
|
+
when :multi_target_node
|
|
274
|
+
MultiTargetNode.new(raw_node, dummy_node, lenv)
|
|
270
275
|
else
|
|
271
276
|
pp raw_node
|
|
272
277
|
raise "not supported yet: #{ raw_node.type }"
|
|
@@ -343,8 +348,7 @@ module TypeProf::Core
|
|
|
343
348
|
break
|
|
344
349
|
when :constant_path_node, :constant_path_target_node
|
|
345
350
|
if raw_node.parent
|
|
346
|
-
|
|
347
|
-
names << (raw_node.respond_to?(:name) ? raw_node.name : raw_node.child.name)
|
|
351
|
+
names << raw_node.name
|
|
348
352
|
raw_node = raw_node.parent
|
|
349
353
|
else
|
|
350
354
|
return names.reverse
|
|
@@ -356,7 +360,8 @@ module TypeProf::Core
|
|
|
356
360
|
return nil
|
|
357
361
|
end
|
|
358
362
|
end
|
|
359
|
-
|
|
363
|
+
cpath = cref.cpath # annotate
|
|
364
|
+
return cpath + names.reverse if cpath
|
|
360
365
|
end
|
|
361
366
|
|
|
362
367
|
def self.parse_rbs(path, src)
|
|
@@ -397,6 +402,8 @@ module TypeProf::Core
|
|
|
397
402
|
SigDefNode.new(raw_decl, lenv)
|
|
398
403
|
when RBS::AST::Members::Include
|
|
399
404
|
SigIncludeNode.new(raw_decl, lenv)
|
|
405
|
+
when RBS::AST::Members::Prepend
|
|
406
|
+
SigPrependNode.new(raw_decl, lenv)
|
|
400
407
|
when RBS::AST::Members::Extend
|
|
401
408
|
when RBS::AST::Members::Public
|
|
402
409
|
when RBS::AST::Members::Private
|
|
@@ -410,6 +417,12 @@ module TypeProf::Core
|
|
|
410
417
|
SigAttrAccessorNode.new(raw_decl, lenv)
|
|
411
418
|
when RBS::AST::Declarations::Base
|
|
412
419
|
self.create_rbs_decl(raw_decl, lenv)
|
|
420
|
+
when RBS::AST::Members::InstanceVariable
|
|
421
|
+
SigInstanceVariableNode.new(raw_decl, lenv, false)
|
|
422
|
+
when RBS::AST::Members::ClassInstanceVariable
|
|
423
|
+
SigInstanceVariableNode.new(raw_decl, lenv, true)
|
|
424
|
+
when RBS::AST::Members::ClassVariable
|
|
425
|
+
SigClassVariableNode.new(raw_decl, lenv)
|
|
413
426
|
else
|
|
414
427
|
raise "unsupported: #{ raw_decl.class }"
|
|
415
428
|
end
|
|
@@ -5,12 +5,11 @@ module TypeProf::Core
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def class_new(changes, node, ty, a_args, ret)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
8
|
+
type_param_vtxs = ty.mod.type_params.map { Vertex.new(node) }
|
|
9
|
+
temp_instance_ty = Type::Instance.new(@genv, ty.mod, type_param_vtxs)
|
|
10
|
+
recv = Source.new(temp_instance_ty)
|
|
11
|
+
changes.add_method_call_box(@genv, recv, :initialize, a_args, false)
|
|
12
|
+
changes.add_edge(@genv, recv, ret)
|
|
14
13
|
true
|
|
15
14
|
end
|
|
16
15
|
|
|
@@ -26,7 +25,8 @@ module TypeProf::Core
|
|
|
26
25
|
def proc_call(changes, node, ty, a_args, ret)
|
|
27
26
|
case ty
|
|
28
27
|
when Type::Proc
|
|
29
|
-
ty.block.accept_args(@genv, changes, a_args.positionals
|
|
28
|
+
ty.block.accept_args(@genv, changes, a_args.positionals)
|
|
29
|
+
ty.block.add_ret(@genv, changes, ret)
|
|
30
30
|
true
|
|
31
31
|
else
|
|
32
32
|
false
|
|
@@ -90,10 +90,16 @@ module TypeProf::Core
|
|
|
90
90
|
def hash_aref(changes, node, ty, a_args, ret)
|
|
91
91
|
if a_args.positionals.size == 1
|
|
92
92
|
case ty
|
|
93
|
-
when Type::Hash
|
|
93
|
+
when Type::Hash, Type::Record
|
|
94
94
|
idx = node.positional_args[0]
|
|
95
95
|
idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
|
|
96
|
-
|
|
96
|
+
value = ty.get_value(idx)
|
|
97
|
+
if value
|
|
98
|
+
changes.add_edge(@genv, value, ret)
|
|
99
|
+
else
|
|
100
|
+
# Return untyped for unknown fields
|
|
101
|
+
changes.add_edge(@genv, Source.new(), ret)
|
|
102
|
+
end
|
|
97
103
|
true
|
|
98
104
|
else
|
|
99
105
|
false
|
|
@@ -41,7 +41,7 @@ module TypeProf::Core
|
|
|
41
41
|
ActualArguments.new(positionals, splat_flags, keywords, block)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def get_rest_args(genv, start_rest, end_rest)
|
|
44
|
+
def get_rest_args(genv, changes, start_rest, end_rest)
|
|
45
45
|
vtxs = []
|
|
46
46
|
|
|
47
47
|
start_rest.upto(end_rest - 1) do |i|
|
|
@@ -50,7 +50,7 @@ module TypeProf::Core
|
|
|
50
50
|
a_arg.each_type do |ty|
|
|
51
51
|
ty = ty.base_type(genv)
|
|
52
52
|
if ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0]
|
|
53
|
-
vtxs <<
|
|
53
|
+
vtxs << changes.new_vertex(genv, self, ty.args[0])
|
|
54
54
|
else
|
|
55
55
|
"???"
|
|
56
56
|
end
|
|
@@ -82,6 +82,7 @@ module TypeProf::Core
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
class Block
|
|
85
|
+
#: (AST::CallBaseNode, Vertex, Array[Vertex], Array[EscapeBox]) -> void
|
|
85
86
|
def initialize(node, f_ary_arg, f_args, next_boxes)
|
|
86
87
|
@node = node
|
|
87
88
|
@f_ary_arg = f_ary_arg
|
|
@@ -89,25 +90,26 @@ module TypeProf::Core
|
|
|
89
90
|
@next_boxes = next_boxes
|
|
90
91
|
end
|
|
91
92
|
|
|
92
|
-
attr_reader :node, :f_args, :
|
|
93
|
+
attr_reader :node, :f_args, :next_boxes
|
|
93
94
|
|
|
94
|
-
def accept_args(genv, changes, caller_positionals
|
|
95
|
+
def accept_args(genv, changes, caller_positionals)
|
|
95
96
|
if caller_positionals.size == 1 && @f_args.size >= 2
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
single_arg = caller_positionals[0]
|
|
98
|
+
|
|
99
|
+
@f_args.each_with_index do |f_arg, i|
|
|
100
|
+
elem_vtx = changes.add_splat_box(genv, single_arg, i).ret
|
|
101
|
+
changes.add_edge(genv, elem_vtx, f_arg)
|
|
102
|
+
end
|
|
98
103
|
else
|
|
99
104
|
caller_positionals.zip(@f_args) do |a_arg, f_arg|
|
|
100
105
|
changes.add_edge(genv, a_arg, f_arg) if f_arg
|
|
101
106
|
end
|
|
102
107
|
end
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@next_boxes.each do |box|
|
|
109
|
-
changes.add_edge(genv, box.a_ret, caller_ret)
|
|
110
|
-
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def add_ret(genv, changes, ret)
|
|
111
|
+
@next_boxes.each do |box|
|
|
112
|
+
changes.add_edge(genv, box.a_ret, ret)
|
|
111
113
|
end
|
|
112
114
|
end
|
|
113
115
|
end
|
|
@@ -126,12 +128,15 @@ module TypeProf::Core
|
|
|
126
128
|
|
|
127
129
|
attr_reader :node, :f_args, :ret, :used
|
|
128
130
|
|
|
129
|
-
def accept_args(genv, changes, caller_positionals
|
|
131
|
+
def accept_args(genv, changes, caller_positionals)
|
|
130
132
|
@used = true
|
|
131
133
|
caller_positionals.each_with_index do |a_arg, i|
|
|
132
134
|
changes.add_edge(genv, a_arg.new_vertex(genv, @node), get_f_arg(i))
|
|
133
135
|
end
|
|
134
|
-
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def add_ret(genv, changes, ret)
|
|
139
|
+
changes.add_edge(genv, ret, @ret)
|
|
135
140
|
end
|
|
136
141
|
end
|
|
137
142
|
end
|
|
@@ -3,6 +3,7 @@ module TypeProf::Core
|
|
|
3
3
|
def initialize
|
|
4
4
|
@builtin = nil
|
|
5
5
|
@decls = Set[]
|
|
6
|
+
@overloading_decls = Set[]
|
|
6
7
|
@defs = Set[]
|
|
7
8
|
@aliases = {}
|
|
8
9
|
@method_call_boxes = Set[]
|
|
@@ -12,11 +13,19 @@ module TypeProf::Core
|
|
|
12
13
|
attr_accessor :builtin
|
|
13
14
|
|
|
14
15
|
def add_decl(decl)
|
|
15
|
-
|
|
16
|
+
if decl.overloading
|
|
17
|
+
@overloading_decls << decl
|
|
18
|
+
else
|
|
19
|
+
@decls << decl
|
|
20
|
+
end
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
def remove_decl(decl)
|
|
19
|
-
|
|
24
|
+
if decl.overloading
|
|
25
|
+
@overloading_decls.delete(decl) || raise
|
|
26
|
+
else
|
|
27
|
+
@decls.delete(decl) || raise
|
|
28
|
+
end
|
|
20
29
|
end
|
|
21
30
|
|
|
22
31
|
def add_def(mdef)
|
|
@@ -7,6 +7,8 @@ module TypeProf::Core
|
|
|
7
7
|
@module_defs = Set[]
|
|
8
8
|
@include_decls = Set[]
|
|
9
9
|
@include_defs = Set[]
|
|
10
|
+
@prepend_decls = []
|
|
11
|
+
@prepend_defs = []
|
|
10
12
|
|
|
11
13
|
@inner_modules = {}
|
|
12
14
|
@outer_module = outer_module
|
|
@@ -15,6 +17,7 @@ module TypeProf::Core
|
|
|
15
17
|
@superclass = nil
|
|
16
18
|
@self_types = {}
|
|
17
19
|
@included_modules = {}
|
|
20
|
+
@prepended_modules = {}
|
|
18
21
|
@basic_object = @cpath == [:BasicObject]
|
|
19
22
|
|
|
20
23
|
# child modules (subclasses and all modules that include me)
|
|
@@ -46,6 +49,7 @@ module TypeProf::Core
|
|
|
46
49
|
attr_reader :superclass
|
|
47
50
|
attr_reader :self_types
|
|
48
51
|
attr_reader :included_modules
|
|
52
|
+
attr_reader :prepended_modules
|
|
49
53
|
attr_reader :child_modules
|
|
50
54
|
|
|
51
55
|
attr_reader :superclass_type_args
|
|
@@ -192,6 +196,26 @@ module TypeProf::Core
|
|
|
192
196
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
193
197
|
end
|
|
194
198
|
|
|
199
|
+
def add_prepend_decl(genv, node)
|
|
200
|
+
@prepend_decls << node
|
|
201
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def remove_prepend_decl(genv, node)
|
|
205
|
+
@prepend_decls.delete(node) || raise
|
|
206
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def add_prepend_def(genv, node)
|
|
210
|
+
@prepend_defs << node
|
|
211
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def remove_prepend_def(genv, node)
|
|
215
|
+
@prepend_defs.delete(node) || raise
|
|
216
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
217
|
+
end
|
|
218
|
+
|
|
195
219
|
def update_parent(genv, origin, old_parent, new_parent_cpath)
|
|
196
220
|
new_parent = new_parent_cpath ? genv.resolve_cpath(new_parent_cpath) : nil
|
|
197
221
|
if old_parent != new_parent
|
|
@@ -323,6 +347,30 @@ module TypeProf::Core
|
|
|
323
347
|
any_updated = true
|
|
324
348
|
end
|
|
325
349
|
end
|
|
350
|
+
@prepend_decls.each do |pdecl|
|
|
351
|
+
new_parent_cpath = pdecl.static_ret.last.cpath
|
|
352
|
+
new_parent, updated = update_parent(genv, pdecl, @prepended_modules[pdecl], new_parent_cpath)
|
|
353
|
+
if updated
|
|
354
|
+
if new_parent
|
|
355
|
+
@prepended_modules[pdecl] = new_parent
|
|
356
|
+
else
|
|
357
|
+
@prepended_modules.delete(pdecl) || raise
|
|
358
|
+
end
|
|
359
|
+
any_updated = true
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
@prepend_defs.each do |pdef|
|
|
363
|
+
new_parent_cpath = pdef.static_ret ? pdef.static_ret.cpath : nil
|
|
364
|
+
new_parent, updated = update_parent(genv, pdef, @prepended_modules[pdef], new_parent_cpath)
|
|
365
|
+
if updated
|
|
366
|
+
if new_parent
|
|
367
|
+
@prepended_modules[pdef] = new_parent
|
|
368
|
+
else
|
|
369
|
+
@prepended_modules.delete(pdef) || raise
|
|
370
|
+
end
|
|
371
|
+
any_updated = true
|
|
372
|
+
end
|
|
373
|
+
end
|
|
326
374
|
@included_modules.delete_if do |origin, old_mod|
|
|
327
375
|
if @include_decls.include?(origin) || @include_defs.include?(origin)
|
|
328
376
|
false
|
|
@@ -332,6 +380,15 @@ module TypeProf::Core
|
|
|
332
380
|
true
|
|
333
381
|
end
|
|
334
382
|
end
|
|
383
|
+
@prepended_modules.delete_if do |origin, old_mod|
|
|
384
|
+
if @prepend_decls.include?(origin) || @prepend_defs.include?(origin)
|
|
385
|
+
false
|
|
386
|
+
else
|
|
387
|
+
_new_parent, updated = update_parent(genv, origin, old_mod, nil)
|
|
388
|
+
any_updated ||= updated
|
|
389
|
+
true
|
|
390
|
+
end
|
|
391
|
+
end
|
|
335
392
|
|
|
336
393
|
if any_updated
|
|
337
394
|
@subclass_checks.each do |mcall_box|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
module TypeProf::Core
|
|
2
|
+
class Narrowing
|
|
3
|
+
def initialize(map)
|
|
4
|
+
raise unless map.is_a?(Hash)
|
|
5
|
+
@map = map
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :map
|
|
9
|
+
|
|
10
|
+
def and(other)
|
|
11
|
+
new_map = @map.dup
|
|
12
|
+
other.map.each do |var, constraint|
|
|
13
|
+
new_map[var] = new_map[var] ? new_map[var].and(constraint) : constraint
|
|
14
|
+
end
|
|
15
|
+
Narrowing.new(new_map)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def or(other)
|
|
19
|
+
new_map = {}
|
|
20
|
+
@map.each do |var, constraint|
|
|
21
|
+
new_map[var] = constraint.or(other.map[var]) if other.map[var]
|
|
22
|
+
end
|
|
23
|
+
Narrowing.new(new_map)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
EmptyNarrowings = [Narrowing.new({}), Narrowing.new({})]
|
|
27
|
+
|
|
28
|
+
# Narrowing system for type refinement
|
|
29
|
+
class Constraint
|
|
30
|
+
def and(other)
|
|
31
|
+
AndConstraint.new(self, other)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def or(other)
|
|
35
|
+
OrConstraint.new(self, other)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class IsAConstraint < Constraint
|
|
40
|
+
def initialize(arg, neg)
|
|
41
|
+
@arg = arg
|
|
42
|
+
@neg = neg
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
attr_reader :arg, :neg
|
|
46
|
+
|
|
47
|
+
def negate
|
|
48
|
+
IsAConstraint.new(@arg, !@neg)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def inspect
|
|
52
|
+
@neg ? "!#{@arg}" : "#{@arg}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def narrow(genv, node, vtx)
|
|
56
|
+
if @arg.static_ret
|
|
57
|
+
IsAFilter.new(genv, node, vtx, @neg, @arg.static_ret).next_vtx
|
|
58
|
+
else
|
|
59
|
+
vtx
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class NilConstraint < Constraint
|
|
65
|
+
def initialize(neg)
|
|
66
|
+
@neg = neg
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
attr_reader :neg
|
|
70
|
+
|
|
71
|
+
def inspect
|
|
72
|
+
@neg ? "!nil" : "nil"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def negate
|
|
76
|
+
NilConstraint.new(!@neg)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def narrow(genv, node, vtx)
|
|
80
|
+
NilFilter.new(genv, node, vtx, @neg).next_vtx
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class AndConstraint < Constraint
|
|
85
|
+
def initialize(left, right)
|
|
86
|
+
@left = left
|
|
87
|
+
@right = right
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
attr_reader :left, :right
|
|
91
|
+
|
|
92
|
+
def inspect
|
|
93
|
+
"(#{@left.inspect} & #{@right.inspect})"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def negate
|
|
97
|
+
OrConstraint.new(@left.negate, @right.negate)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def narrow(genv, node, vtx)
|
|
101
|
+
@left.narrow(genv, node, @right.narrow(genv, node, vtx))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class OrConstraint < Constraint
|
|
106
|
+
def initialize(left, right)
|
|
107
|
+
@left = left
|
|
108
|
+
@right = right
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
attr_reader :left, :right
|
|
112
|
+
|
|
113
|
+
def inspect
|
|
114
|
+
"(#{@left.inspect} | #{@right.inspect})"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def negate
|
|
118
|
+
AndConstraint.new(@left.negate, @right.negate)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def narrow(genv, node, vtx)
|
|
122
|
+
ret = Vertex.new(node)
|
|
123
|
+
vtx1 = @left.narrow(genv, node, vtx)
|
|
124
|
+
vtx2 = @right.narrow(genv, node, vtx)
|
|
125
|
+
vtx1.add_edge(genv, ret)
|
|
126
|
+
vtx2.add_edge(genv, ret)
|
|
127
|
+
ret
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -30,10 +30,9 @@ module TypeProf::Core
|
|
|
30
30
|
@source_modules.clear
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def resolve(genv, cref, break_object)
|
|
33
|
+
def resolve(genv, cref, search_ancestors, break_object)
|
|
34
34
|
destroy(genv)
|
|
35
35
|
|
|
36
|
-
first = true
|
|
37
36
|
while cref
|
|
38
37
|
scope = cref.cpath
|
|
39
38
|
mod = genv.resolve_cpath(scope)
|
|
@@ -47,9 +46,9 @@ module TypeProf::Core
|
|
|
47
46
|
|
|
48
47
|
return if check_module(genv, mod)
|
|
49
48
|
|
|
50
|
-
break unless
|
|
49
|
+
break unless search_ancestors
|
|
51
50
|
end
|
|
52
|
-
|
|
51
|
+
search_ancestors = false
|
|
53
52
|
cref = cref.outer
|
|
54
53
|
end
|
|
55
54
|
resolution_failed(genv)
|
|
@@ -57,29 +56,31 @@ module TypeProf::Core
|
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
class BaseStaticRead < StaticRead
|
|
60
|
-
def initialize(genv, name, cref)
|
|
59
|
+
def initialize(genv, name, cref, strict_const_scope)
|
|
61
60
|
super(name)
|
|
62
61
|
@cref = cref
|
|
62
|
+
@search_ancestors = !strict_const_scope
|
|
63
63
|
genv.add_static_eval_queue(:static_read_changed, self)
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
attr_reader :cref
|
|
67
67
|
|
|
68
68
|
def on_scope_updated(genv)
|
|
69
|
-
resolve(genv, @cref, false)
|
|
69
|
+
resolve(genv, @cref, @search_ancestors, false)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
class ScopedStaticRead < StaticRead
|
|
74
|
-
def initialize(name, cbase)
|
|
74
|
+
def initialize(name, cbase, strict_const_scope)
|
|
75
75
|
super(name)
|
|
76
76
|
@cbase = cbase
|
|
77
77
|
@cbase.followers << self if @cbase
|
|
78
|
+
@search_ancestors = !strict_const_scope
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
def on_cbase_updated(genv)
|
|
81
82
|
if @cbase && @cbase.cpath
|
|
82
|
-
resolve(genv, CRef.new(@cbase.cpath, :class, nil, nil), true)
|
|
83
|
+
resolve(genv, CRef.new(@cbase.cpath, :class, nil, nil), @search_ancestors, true)
|
|
83
84
|
else
|
|
84
85
|
resolution_failed(genv)
|
|
85
86
|
end
|
data/lib/typeprof/core/env.rb
CHANGED
|
@@ -8,6 +8,8 @@ module TypeProf::Core
|
|
|
8
8
|
@run_queue = []
|
|
9
9
|
@run_queue_set = Set[]
|
|
10
10
|
|
|
11
|
+
@pending_diagnostic_paths = Set[]
|
|
12
|
+
|
|
11
13
|
@mod_object = ModuleEntity.new([])
|
|
12
14
|
@mod_object.inner_modules[:Object] = @mod_object
|
|
13
15
|
|
|
@@ -112,7 +114,11 @@ module TypeProf::Core
|
|
|
112
114
|
ty_env = base_ty_env.dup
|
|
113
115
|
if base_ty.is_a?(Type::Instance)
|
|
114
116
|
base_ty.mod.type_params.zip(base_ty.args) do |param, arg|
|
|
115
|
-
ty_env[param] = arg
|
|
117
|
+
ty_env[param] = arg || Source.new
|
|
118
|
+
end
|
|
119
|
+
elsif base_ty.is_a?(Type::Singleton)
|
|
120
|
+
base_ty.mod.type_params&.each do |param|
|
|
121
|
+
ty_env[param] = Source.new
|
|
116
122
|
end
|
|
117
123
|
end
|
|
118
124
|
args = mod.type_params.zip(type_args).map do |param, arg|
|
|
@@ -179,6 +185,19 @@ module TypeProf::Core
|
|
|
179
185
|
@run_count += run_count
|
|
180
186
|
end
|
|
181
187
|
|
|
188
|
+
def process_diagnostic_paths
|
|
189
|
+
processed_paths = []
|
|
190
|
+
@pending_diagnostic_paths.each do |path|
|
|
191
|
+
processed = yield path
|
|
192
|
+
processed_paths << path if processed
|
|
193
|
+
end
|
|
194
|
+
processed_paths.each {|path| @pending_diagnostic_paths.delete(path) }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def add_diagnostic_path(path)
|
|
198
|
+
@pending_diagnostic_paths << path unless @pending_diagnostic_paths.include?(path)
|
|
199
|
+
end
|
|
200
|
+
|
|
182
201
|
# just for validation
|
|
183
202
|
def get_vertexes(vtxs)
|
|
184
203
|
@mod_object.get_vertexes(vtxs)
|
|
@@ -284,10 +303,11 @@ module TypeProf::Core
|
|
|
284
303
|
@return_boxes = return_boxes
|
|
285
304
|
@break_vtx = nil
|
|
286
305
|
@next_boxes = []
|
|
287
|
-
@
|
|
306
|
+
@ivar_narrowings = {}
|
|
307
|
+
@strict_const_scope = false
|
|
288
308
|
end
|
|
289
309
|
|
|
290
|
-
attr_reader :path, :cref, :locals, :return_boxes, :break_vtx, :next_boxes
|
|
310
|
+
attr_reader :path, :cref, :locals, :return_boxes, :break_vtx, :next_boxes, :strict_const_scope
|
|
291
311
|
|
|
292
312
|
def new_var(name, node)
|
|
293
313
|
@locals[name] = Vertex.new(node)
|
|
@@ -318,23 +338,32 @@ module TypeProf::Core
|
|
|
318
338
|
end
|
|
319
339
|
|
|
320
340
|
|
|
321
|
-
def
|
|
322
|
-
|
|
341
|
+
def push_ivar_narrowing(name, narrowing)
|
|
342
|
+
raise unless narrowing.is_a?(Narrowing::Constraint)
|
|
343
|
+
(@ivar_narrowings[name] ||= []) << narrowing
|
|
323
344
|
end
|
|
324
345
|
|
|
325
|
-
def
|
|
326
|
-
(@
|
|
346
|
+
def pop_ivar_narrowing(name)
|
|
347
|
+
(@ivar_narrowings[name] ||= []).pop
|
|
327
348
|
end
|
|
328
349
|
|
|
329
|
-
def
|
|
330
|
-
if @
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
350
|
+
def apply_ivar_narrowing(genv, node, name, vtx)
|
|
351
|
+
if @ivar_narrowings[name] && !@ivar_narrowings[name].empty?
|
|
352
|
+
# Apply all accumulated narrowings in order
|
|
353
|
+
@ivar_narrowings[name].each do |narrowing|
|
|
354
|
+
vtx = narrowing.narrow(genv, node, vtx)
|
|
334
355
|
end
|
|
356
|
+
return vtx
|
|
335
357
|
end
|
|
336
358
|
vtx
|
|
337
359
|
end
|
|
360
|
+
|
|
361
|
+
def use_strict_const_scope
|
|
362
|
+
@strict_const_scope = true
|
|
363
|
+
yield
|
|
364
|
+
ensure
|
|
365
|
+
@strict_const_scope = false
|
|
366
|
+
end
|
|
338
367
|
end
|
|
339
368
|
|
|
340
369
|
class CRef
|