typeprof 0.32.0 → 0.33.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/lib/typeprof/core/ast/base.rb +13 -0
- data/lib/typeprof/core/ast/call.rb +47 -30
- data/lib/typeprof/core/ast/const.rb +15 -7
- data/lib/typeprof/core/ast/control.rb +2 -2
- data/lib/typeprof/core/ast/meta.rb +96 -23
- data/lib/typeprof/core/ast/method.rb +18 -14
- data/lib/typeprof/core/ast/misc.rb +16 -7
- data/lib/typeprof/core/ast/module.rb +6 -2
- data/lib/typeprof/core/ast/pattern.rb +51 -23
- data/lib/typeprof/core/ast/sig_decl.rb +57 -4
- data/lib/typeprof/core/ast/sig_type.rb +36 -1
- data/lib/typeprof/core/ast/variable.rb +6 -0
- data/lib/typeprof/core/ast.rb +3 -0
- data/lib/typeprof/core/env/method.rb +192 -20
- data/lib/typeprof/core/env/module_entity.rb +61 -1
- data/lib/typeprof/core/env.rb +34 -6
- data/lib/typeprof/core/graph/box.rb +135 -17
- data/lib/typeprof/core/graph/change_set.rb +11 -6
- data/lib/typeprof/core/service.rb +24 -2
- data/lib/typeprof/version.rb +1 -1
- metadata +2 -2
|
@@ -9,6 +9,8 @@ module TypeProf::Core
|
|
|
9
9
|
@include_defs = Set.empty
|
|
10
10
|
@prepend_decls = []
|
|
11
11
|
@prepend_defs = []
|
|
12
|
+
@extend_decls = Set.empty
|
|
13
|
+
@extend_defs = Set.empty
|
|
12
14
|
|
|
13
15
|
# `class Foo = Bar` / `module Foo = Bar` declarations attached to this entity.
|
|
14
16
|
# Maps an alias decl to the target ModuleEntity at the time of registration.
|
|
@@ -23,6 +25,7 @@ module TypeProf::Core
|
|
|
23
25
|
@self_types = {}
|
|
24
26
|
@included_modules = {}
|
|
25
27
|
@prepended_modules = {}
|
|
28
|
+
@extended_modules = {}
|
|
26
29
|
@basic_object = @cpath == [:BasicObject]
|
|
27
30
|
|
|
28
31
|
# child modules (subclasses and all modules that include me)
|
|
@@ -57,6 +60,7 @@ module TypeProf::Core
|
|
|
57
60
|
attr_reader :self_types
|
|
58
61
|
attr_reader :included_modules
|
|
59
62
|
attr_reader :prepended_modules
|
|
63
|
+
attr_reader :extended_modules
|
|
60
64
|
attr_reader :child_modules
|
|
61
65
|
|
|
62
66
|
attr_reader :superclass_type_args
|
|
@@ -219,6 +223,26 @@ module TypeProf::Core
|
|
|
219
223
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
220
224
|
end
|
|
221
225
|
|
|
226
|
+
def add_extend_decl(genv, node)
|
|
227
|
+
@extend_decls << node
|
|
228
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def remove_extend_decl(genv, node)
|
|
232
|
+
@extend_decls.delete(node) || raise
|
|
233
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def add_extend_def(genv, node)
|
|
237
|
+
@extend_defs << node
|
|
238
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def remove_extend_def(genv, node)
|
|
242
|
+
@extend_defs.delete(node) || raise
|
|
243
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
244
|
+
end
|
|
245
|
+
|
|
222
246
|
def add_prepend_decl(genv, node)
|
|
223
247
|
@prepend_decls << node
|
|
224
248
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
@@ -285,7 +309,8 @@ module TypeProf::Core
|
|
|
285
309
|
when AST::ModuleNode
|
|
286
310
|
return nil
|
|
287
311
|
when AST::StructNewNode
|
|
288
|
-
|
|
312
|
+
base_cpath = mdef.struct_base_cpath
|
|
313
|
+
return base_cpath == @cpath ? [] : base_cpath
|
|
289
314
|
else
|
|
290
315
|
raise
|
|
291
316
|
end
|
|
@@ -396,6 +421,30 @@ module TypeProf::Core
|
|
|
396
421
|
any_updated = true
|
|
397
422
|
end
|
|
398
423
|
end
|
|
424
|
+
@extend_decls.each do |edecl|
|
|
425
|
+
new_parent_cpath = edecl.static_ret.last.cpath
|
|
426
|
+
new_parent, updated = update_parent(genv, edecl, @extended_modules[edecl], new_parent_cpath)
|
|
427
|
+
if updated
|
|
428
|
+
if new_parent
|
|
429
|
+
@extended_modules[edecl] = new_parent
|
|
430
|
+
else
|
|
431
|
+
@extended_modules.delete(edecl) || raise
|
|
432
|
+
end
|
|
433
|
+
any_updated = true
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
@extend_defs.each do |edef|
|
|
437
|
+
new_parent_cpath = edef.static_ret ? edef.static_ret.cpath : nil
|
|
438
|
+
new_parent, updated = update_parent(genv, edef, @extended_modules[edef], new_parent_cpath)
|
|
439
|
+
if updated
|
|
440
|
+
if new_parent
|
|
441
|
+
@extended_modules[edef] = new_parent
|
|
442
|
+
else
|
|
443
|
+
@extended_modules.delete(edef) || raise
|
|
444
|
+
end
|
|
445
|
+
any_updated = true
|
|
446
|
+
end
|
|
447
|
+
end
|
|
399
448
|
@included_modules.delete_if do |origin, old_mod|
|
|
400
449
|
if @include_decls.include?(origin) || @include_defs.include?(origin)
|
|
401
450
|
false
|
|
@@ -414,6 +463,15 @@ module TypeProf::Core
|
|
|
414
463
|
true
|
|
415
464
|
end
|
|
416
465
|
end
|
|
466
|
+
@extended_modules.delete_if do |origin, old_mod|
|
|
467
|
+
if @extend_decls.include?(origin) || @extend_defs.include?(origin)
|
|
468
|
+
false
|
|
469
|
+
else
|
|
470
|
+
_new_parent, updated = update_parent(genv, origin, old_mod, nil)
|
|
471
|
+
any_updated ||= updated
|
|
472
|
+
true
|
|
473
|
+
end
|
|
474
|
+
end
|
|
417
475
|
|
|
418
476
|
if any_updated
|
|
419
477
|
@subclass_checks.each do |mcall_box|
|
|
@@ -424,6 +482,8 @@ module TypeProf::Core
|
|
|
424
482
|
end
|
|
425
483
|
|
|
426
484
|
def on_ancestors_updated(genv, base_mod)
|
|
485
|
+
# `include` and `extend` can form a cycle in valid Ruby
|
|
486
|
+
return if base_mod == self
|
|
427
487
|
@child_modules.each_key {|child_mod| child_mod.on_ancestors_updated(genv, base_mod || self) }
|
|
428
488
|
@static_reads.each_value do |static_reads|
|
|
429
489
|
static_reads.each do |static_read|
|
data/lib/typeprof/core/env.rb
CHANGED
|
@@ -80,7 +80,7 @@ module TypeProf::Core
|
|
|
80
80
|
# TODO: prepended modules
|
|
81
81
|
yield mod, singleton
|
|
82
82
|
if singleton
|
|
83
|
-
|
|
83
|
+
each_extended_module(mod, &blk)
|
|
84
84
|
else
|
|
85
85
|
each_included_module(mod, &blk)
|
|
86
86
|
end
|
|
@@ -95,6 +95,15 @@ module TypeProf::Core
|
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
def each_extended_module(mod, &blk)
|
|
99
|
+
# An extended module contributes its instance methods (singleton = false)
|
|
100
|
+
# as the receiver's singleton methods.
|
|
101
|
+
mod.extended_modules.each do |_ext_decl, ext_mod|
|
|
102
|
+
yield ext_mod, false
|
|
103
|
+
each_included_module(ext_mod, &blk)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
98
107
|
def get_superclass(singleton, mod)
|
|
99
108
|
super_mod = mod.superclass
|
|
100
109
|
if super_mod
|
|
@@ -106,6 +115,9 @@ module TypeProf::Core
|
|
|
106
115
|
else
|
|
107
116
|
return nil
|
|
108
117
|
end
|
|
118
|
+
elsif mod == @mod_object
|
|
119
|
+
# Unresolved while loading the core RBS; the Module fallback below would cycle
|
|
120
|
+
return [singleton, @mod_basic_object]
|
|
109
121
|
elsif mod == @mod_module && !singleton
|
|
110
122
|
return nil
|
|
111
123
|
else
|
|
@@ -271,6 +283,17 @@ module TypeProf::Core
|
|
|
271
283
|
mod.get_type_alias(name)
|
|
272
284
|
end
|
|
273
285
|
|
|
286
|
+
# Returns the type parameter names of the first generic declaration of cpath
|
|
287
|
+
def find_type_params(decls, cpath)
|
|
288
|
+
decls.each do |decl|
|
|
289
|
+
next unless decl.cpath == cpath
|
|
290
|
+
next unless decl.respond_to?(:params)
|
|
291
|
+
params = decl.params
|
|
292
|
+
return params if params && !params.empty?
|
|
293
|
+
end
|
|
294
|
+
nil
|
|
295
|
+
end
|
|
296
|
+
|
|
274
297
|
def load_core_rbs(raw_decls, position_encoding)
|
|
275
298
|
file_context = FileContext.new(nil, position_encoding)
|
|
276
299
|
lenv = LocalEnv.new(file_context, CRef::Toplevel, {}, [])
|
|
@@ -278,6 +301,11 @@ module TypeProf::Core
|
|
|
278
301
|
AST.create_rbs_decl(raw_decl, lenv)
|
|
279
302
|
end.compact
|
|
280
303
|
|
|
304
|
+
# A module entity has one set of parameter names shared by all its declarations,
|
|
305
|
+
# so the shim must reuse the core's ones (Array's was `Elem`, and is `E` since RBS 4.1)
|
|
306
|
+
ary_elem, = find_type_params(decls, [:Array]) || [:Elem]
|
|
307
|
+
hash_key, hash_val = find_type_params(decls, [:Hash]) || [:K, :V]
|
|
308
|
+
|
|
281
309
|
decls += AST.parse_rbs("typeprof-rbs-shim.rbs", <<-RBS, position_encoding)
|
|
282
310
|
class Exception
|
|
283
311
|
include _Exception
|
|
@@ -286,12 +314,12 @@ module TypeProf::Core
|
|
|
286
314
|
include _ToS
|
|
287
315
|
include _ToStr
|
|
288
316
|
end
|
|
289
|
-
class Array[
|
|
290
|
-
include _ToAry[
|
|
291
|
-
include _Each[
|
|
317
|
+
class Array[#{ ary_elem }]
|
|
318
|
+
include _ToAry[#{ ary_elem }]
|
|
319
|
+
include _Each[#{ ary_elem }]
|
|
292
320
|
end
|
|
293
|
-
class Hash[
|
|
294
|
-
include _Each[[
|
|
321
|
+
class Hash[#{ hash_key }, #{ hash_val }]
|
|
322
|
+
include _Each[[#{ hash_key }, #{ hash_val }]]
|
|
295
323
|
end
|
|
296
324
|
class Object
|
|
297
325
|
include Hash::_Key
|
|
@@ -17,6 +17,7 @@ module TypeProf::Core
|
|
|
17
17
|
$box_counts[self.class] -= 1
|
|
18
18
|
$box_counts[Box] -= 1
|
|
19
19
|
@destroyed = true
|
|
20
|
+
destroy_symbol_proc_call_boxes(genv)
|
|
20
21
|
@changes.reinstall(genv) # rollback all changes
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -43,6 +44,24 @@ module TypeProf::Core
|
|
|
43
44
|
raise NotImplementedError
|
|
44
45
|
end
|
|
45
46
|
|
|
47
|
+
def add_symbol_proc_call_box(_changes, genv, sym, caller_positionals, caller_keywords = nil)
|
|
48
|
+
return if caller_positionals.empty?
|
|
49
|
+
|
|
50
|
+
recv = caller_positionals.first
|
|
51
|
+
positionals = caller_positionals[1..]
|
|
52
|
+
@symbol_proc_call_boxes ||= {}
|
|
53
|
+
@symbol_proc_call_boxes[[recv, sym, *positionals, caller_keywords]] ||= begin
|
|
54
|
+
a_args = ActualArguments.new(positionals, ::Array.new(positionals.size, false), caller_keywords, nil)
|
|
55
|
+
MethodCallBox.new(@node, genv, recv, sym, a_args, false)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def destroy_symbol_proc_call_boxes(genv)
|
|
60
|
+
return unless @symbol_proc_call_boxes
|
|
61
|
+
@symbol_proc_call_boxes.each_value { |box| box.destroy(genv) }
|
|
62
|
+
@symbol_proc_call_boxes = nil
|
|
63
|
+
end
|
|
64
|
+
|
|
46
65
|
def to_s
|
|
47
66
|
"#{ self.class.to_s.split("::").last }#{ @id ||= $new_id += 1 }"
|
|
48
67
|
end
|
|
@@ -127,6 +146,12 @@ module TypeProf::Core
|
|
|
127
146
|
}
|
|
128
147
|
end
|
|
129
148
|
|
|
149
|
+
# lazy cache: overloads split into fixed-arity ones and rest-positional ones
|
|
150
|
+
def partition_by_rest_positionals
|
|
151
|
+
@partition_by_rest_positionals ||=
|
|
152
|
+
@method_types.partition {|method_type| !method_type.rest_positionals }
|
|
153
|
+
end
|
|
154
|
+
|
|
130
155
|
private
|
|
131
156
|
|
|
132
157
|
# Check if two method types have structurally identical positional
|
|
@@ -258,6 +283,7 @@ module TypeProf::Core
|
|
|
258
283
|
me = genv.resolve_method(@cpath, @singleton, @mid)
|
|
259
284
|
me.remove_decl(self)
|
|
260
285
|
me.add_run_all_method_call_boxes(genv)
|
|
286
|
+
destroy_symbol_proc_call_boxes(genv)
|
|
261
287
|
end
|
|
262
288
|
|
|
263
289
|
def match_arguments?(genv, changes, param_map, a_args, method_type)
|
|
@@ -382,6 +408,8 @@ module TypeProf::Core
|
|
|
382
408
|
end
|
|
383
409
|
end
|
|
384
410
|
end
|
|
411
|
+
when Type::Symbol
|
|
412
|
+
resolve_symbol_proc(changes, genv, ty.sym, blk_a_args, rbs_blk, param_map0)
|
|
385
413
|
end
|
|
386
414
|
end
|
|
387
415
|
end
|
|
@@ -396,6 +424,13 @@ module TypeProf::Core
|
|
|
396
424
|
end
|
|
397
425
|
end
|
|
398
426
|
|
|
427
|
+
def resolve_symbol_proc(changes, genv, sym, blk_a_args, rbs_blk, param_map)
|
|
428
|
+
box = add_symbol_proc_call_box(changes, genv, sym, blk_a_args)
|
|
429
|
+
return unless box
|
|
430
|
+
|
|
431
|
+
rbs_blk.return_type.typecheck(genv, changes, box.ret, param_map)
|
|
432
|
+
end
|
|
433
|
+
|
|
399
434
|
def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
|
|
400
435
|
if @method_types.size == 1
|
|
401
436
|
method_type = @method_types.first
|
|
@@ -451,11 +486,19 @@ module TypeProf::Core
|
|
|
451
486
|
return
|
|
452
487
|
end
|
|
453
488
|
|
|
489
|
+
# A splatted call can match only a rest-positional overload; otherwise prefer
|
|
490
|
+
# the fixed-arity ones, as a rest-positional one is usually a catch-all
|
|
491
|
+
overload_groups =
|
|
492
|
+
a_args.splat_flags.any? ? [@method_types] : @method_types.partition_by_rest_positionals
|
|
493
|
+
|
|
454
494
|
match_any_overload = false
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
495
|
+
overload_groups.each do |method_types|
|
|
496
|
+
method_types.each do |method_type|
|
|
497
|
+
if resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, false, &blk)
|
|
498
|
+
match_any_overload = true
|
|
499
|
+
end
|
|
458
500
|
end
|
|
501
|
+
break if match_any_overload
|
|
459
502
|
end
|
|
460
503
|
unless match_any_overload
|
|
461
504
|
meth = node.mid_code_range ? :mid_code_range : :code_range
|
|
@@ -600,13 +643,13 @@ module TypeProf::Core
|
|
|
600
643
|
end
|
|
601
644
|
|
|
602
645
|
class SplatBox < Box
|
|
603
|
-
def initialize(node, genv, ary, idx,
|
|
646
|
+
def initialize(node, genv, ary, idx, unresolved_recv = nil)
|
|
604
647
|
super(node)
|
|
605
648
|
@ary = ary
|
|
606
649
|
@idx = idx
|
|
607
|
-
@
|
|
650
|
+
@unresolved_recv = unresolved_recv
|
|
608
651
|
@ary.add_edge(genv, self)
|
|
609
|
-
@
|
|
652
|
+
@unresolved_recv.add_edge(genv, self) if @unresolved_recv
|
|
610
653
|
@ret = Vertex.new(node)
|
|
611
654
|
end
|
|
612
655
|
|
|
@@ -632,14 +675,41 @@ module TypeProf::Core
|
|
|
632
675
|
end
|
|
633
676
|
end
|
|
634
677
|
# For types where to_a is not defined, [*x] wraps x as [x]
|
|
635
|
-
if @
|
|
636
|
-
@
|
|
678
|
+
if @unresolved_recv
|
|
679
|
+
@unresolved_recv.each_type do |ty|
|
|
637
680
|
changes.add_edge(genv, Source.new(ty), @ret)
|
|
638
681
|
end
|
|
639
682
|
end
|
|
640
683
|
end
|
|
641
684
|
end
|
|
642
685
|
|
|
686
|
+
# Merges the keywords being forwarded into the `**rest` hash while keeping the
|
|
687
|
+
# rest's own fields, so that the callee can still tell the two apart.
|
|
688
|
+
class KeywordMergeBox < Box
|
|
689
|
+
def initialize(node, genv, rest, literal_pairs, fallback)
|
|
690
|
+
super(node)
|
|
691
|
+
@rest = rest
|
|
692
|
+
@literal_pairs = literal_pairs
|
|
693
|
+
@fallback = fallback
|
|
694
|
+
@rest.add_edge(genv, self)
|
|
695
|
+
@ret = Vertex.new(node)
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
attr_reader :ret
|
|
699
|
+
|
|
700
|
+
def run0(genv, changes)
|
|
701
|
+
merged = false
|
|
702
|
+
@rest.each_type do |ty|
|
|
703
|
+
if ty.is_a?(Type::Record)
|
|
704
|
+
fields = ty.fields.merge(@literal_pairs)
|
|
705
|
+
changes.add_edge(genv, Source.new(Type::Record.new(genv, fields, ty.base_type(genv))), @ret)
|
|
706
|
+
merged = true
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
changes.add_edge(genv, @fallback, @ret) unless merged
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
643
713
|
class HashSplatBox < Box
|
|
644
714
|
def initialize(node, genv, hsh, unified_key, unified_val)
|
|
645
715
|
super(node)
|
|
@@ -1004,29 +1074,42 @@ module TypeProf::Core
|
|
|
1004
1074
|
end
|
|
1005
1075
|
|
|
1006
1076
|
class MethodCallBox < Box
|
|
1007
|
-
|
|
1077
|
+
# `unresolved_recv`, when given, collects the receiver types for which no
|
|
1078
|
+
# method entity was found. Without it those types only become "undefined
|
|
1079
|
+
# method" diagnostics; with it the caller can handle them itself, as `[*x]`
|
|
1080
|
+
# does to wrap a receiver that has no `to_a`.
|
|
1081
|
+
def initialize(node, genv, recv, mid, a_args, subclasses, suppress_errors: false, unresolved_recv: nil)
|
|
1008
1082
|
raise mid.to_s unless mid
|
|
1009
1083
|
super(node)
|
|
1010
1084
|
@recv = recv.new_vertex(genv, node)
|
|
1011
1085
|
@recv.add_edge(genv, self)
|
|
1012
1086
|
@mid = mid
|
|
1013
1087
|
@a_args = a_args.new_vertexes(genv, node)
|
|
1014
|
-
@a_args.
|
|
1015
|
-
@a_args.block.add_edge(genv, self) if @a_args.block
|
|
1088
|
+
@a_args.add_box_edges(genv, self)
|
|
1016
1089
|
@ret = Vertex.new(node)
|
|
1017
1090
|
@subclasses = subclasses
|
|
1018
1091
|
@suppress_errors = suppress_errors
|
|
1092
|
+
@unresolved_recv = unresolved_recv
|
|
1019
1093
|
@generics = {}
|
|
1020
1094
|
end
|
|
1021
1095
|
|
|
1022
1096
|
attr_reader :recv, :mid, :ret
|
|
1023
1097
|
|
|
1024
1098
|
def run0(genv, changes)
|
|
1099
|
+
a_args = @a_args.normalize_for_method_call(genv)
|
|
1100
|
+
return unless a_args
|
|
1101
|
+
|
|
1025
1102
|
edges = Set.empty
|
|
1026
1103
|
called_mdefs = Set.empty
|
|
1027
1104
|
error_count = 0
|
|
1028
1105
|
resolve(genv, changes) do |me, ty, mid, orig_ty|
|
|
1029
|
-
if
|
|
1106
|
+
if @node.is_a?(AST::YieldNode) && mid == :call && orig_ty.is_a?(Type::Symbol)
|
|
1107
|
+
box = add_symbol_proc_call_box(changes, genv, orig_ty.sym, a_args.positionals, a_args.keywords)
|
|
1108
|
+
changes.add_edge(genv, box.ret, @ret) if box
|
|
1109
|
+
elsif !me
|
|
1110
|
+
if @unresolved_recv
|
|
1111
|
+
changes.add_edge(genv, Source.new(orig_ty), @unresolved_recv)
|
|
1112
|
+
end
|
|
1030
1113
|
unless @suppress_errors
|
|
1031
1114
|
if error_count < 3
|
|
1032
1115
|
meth = @node.mid_code_range ? :mid_code_range : :code_range
|
|
@@ -1034,7 +1117,7 @@ module TypeProf::Core
|
|
|
1034
1117
|
end
|
|
1035
1118
|
end
|
|
1036
1119
|
error_count += 1
|
|
1037
|
-
elsif me.builtin && me.builtin[changes, @node, orig_ty,
|
|
1120
|
+
elsif me.builtin && me.builtin[changes, @node, orig_ty, a_args, @ret]
|
|
1038
1121
|
# do nothing
|
|
1039
1122
|
elsif !me.decls.empty?
|
|
1040
1123
|
# TODO: support "| ..."
|
|
@@ -1047,7 +1130,7 @@ module TypeProf::Core
|
|
|
1047
1130
|
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(genv, changes, ty_env) : Source.new)
|
|
1048
1131
|
end
|
|
1049
1132
|
end
|
|
1050
|
-
mdecl.resolve_overloads(changes, genv, @node, ty_env,
|
|
1133
|
+
mdecl.resolve_overloads(changes, genv, @node, ty_env, a_args, @ret) do |method_type|
|
|
1051
1134
|
@generics[method_type] ||= method_type.type_params.map { Vertex.new(@node) }
|
|
1052
1135
|
end
|
|
1053
1136
|
end
|
|
@@ -1055,7 +1138,7 @@ module TypeProf::Core
|
|
|
1055
1138
|
me.defs.each do |mdef|
|
|
1056
1139
|
next if called_mdefs.include?(mdef)
|
|
1057
1140
|
called_mdefs << mdef
|
|
1058
|
-
mdef.call(changes, genv,
|
|
1141
|
+
mdef.call(changes, genv, a_args, @ret)
|
|
1059
1142
|
end
|
|
1060
1143
|
else
|
|
1061
1144
|
pp me
|
|
@@ -1068,7 +1151,7 @@ module TypeProf::Core
|
|
|
1068
1151
|
me.defs.each do |mdef|
|
|
1069
1152
|
next if called_mdefs.include?(mdef)
|
|
1070
1153
|
called_mdefs << mdef
|
|
1071
|
-
mdef.call(changes, genv,
|
|
1154
|
+
mdef.call(changes, genv, a_args, @ret)
|
|
1072
1155
|
end
|
|
1073
1156
|
end
|
|
1074
1157
|
end
|
|
@@ -1126,7 +1209,10 @@ module TypeProf::Core
|
|
|
1126
1209
|
skip = false
|
|
1127
1210
|
|
|
1128
1211
|
if ty.is_a?(Type::Singleton)
|
|
1129
|
-
#
|
|
1212
|
+
# Check extended modules (their instance methods are singleton methods here)
|
|
1213
|
+
break if resolve_extended_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
|
|
1214
|
+
yield me, ty, mid, orig_ty
|
|
1215
|
+
end
|
|
1130
1216
|
else
|
|
1131
1217
|
# Finally check included modules
|
|
1132
1218
|
break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
|
|
@@ -1226,6 +1312,38 @@ module TypeProf::Core
|
|
|
1226
1312
|
found
|
|
1227
1313
|
end
|
|
1228
1314
|
|
|
1315
|
+
def resolve_extended_modules(genv, changes, base_ty_env, ty, mid, &blk)
|
|
1316
|
+
found = false
|
|
1317
|
+
|
|
1318
|
+
alias_limit = 0
|
|
1319
|
+
# An extended module's instance methods are resolved as the receiver's
|
|
1320
|
+
# singleton methods, so look them up with singleton = false.
|
|
1321
|
+
ty.mod.extended_modules.each do |ext_decl, ext_mod|
|
|
1322
|
+
if ext_decl.is_a?(AST::SigExtendNode) && ext_mod.type_params
|
|
1323
|
+
ext_ty = genv.get_instance_type(ext_mod, ext_decl.args, changes, base_ty_env, ty)
|
|
1324
|
+
else
|
|
1325
|
+
type_params = ext_mod.type_params.map { Source.new() } # TODO: better support
|
|
1326
|
+
ext_ty = Type::Instance.new(genv, ext_mod, type_params)
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
me = ext_ty.mod.get_method(false, mid)
|
|
1330
|
+
changes.add_depended_method_entity(me) if changes
|
|
1331
|
+
if !me.aliases.empty?
|
|
1332
|
+
mid = me.aliases.values.first
|
|
1333
|
+
alias_limit += 1
|
|
1334
|
+
redo if alias_limit < 5
|
|
1335
|
+
end
|
|
1336
|
+
if me.exist?
|
|
1337
|
+
found = true
|
|
1338
|
+
yield me, ext_ty, mid
|
|
1339
|
+
else
|
|
1340
|
+
# The extended module may itself include other modules.
|
|
1341
|
+
found ||= resolve_included_modules(genv, changes, base_ty_env, ext_ty, mid, &blk)
|
|
1342
|
+
end
|
|
1343
|
+
end
|
|
1344
|
+
found
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1229
1347
|
def resolve_subclasses(genv, changes)
|
|
1230
1348
|
# TODO: This does not follow new subclasses
|
|
1231
1349
|
@recv.each_type do |ty|
|
|
@@ -71,9 +71,9 @@ module TypeProf::Core
|
|
|
71
71
|
|
|
72
72
|
# TODO: if an edge is removed during one analysis, we may need to remove sub-boxes?
|
|
73
73
|
|
|
74
|
-
def add_method_call_box(genv, recv, mid, a_args, subclasses, suppress_errors: false)
|
|
75
|
-
key = [:mcall, recv, mid, a_args, subclasses, suppress_errors]
|
|
76
|
-
new_boxes[key] ||= MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses, suppress_errors: suppress_errors)
|
|
74
|
+
def add_method_call_box(genv, recv, mid, a_args, subclasses, suppress_errors: false, unresolved_recv: nil)
|
|
75
|
+
key = [:mcall, recv, mid, a_args, subclasses, suppress_errors, unresolved_recv]
|
|
76
|
+
new_boxes[key] ||= MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses, suppress_errors: suppress_errors, unresolved_recv: unresolved_recv)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def add_escape_box(genv, a_ret)
|
|
@@ -81,9 +81,14 @@ module TypeProf::Core
|
|
|
81
81
|
new_boxes[key] ||= EscapeBox.new(@node, genv, a_ret)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
def add_splat_box(genv, arg, idx = nil,
|
|
85
|
-
key = [:splat, arg, idx,
|
|
86
|
-
new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx,
|
|
84
|
+
def add_splat_box(genv, arg, idx = nil, unresolved_recv = nil)
|
|
85
|
+
key = [:splat, arg, idx, unresolved_recv]
|
|
86
|
+
new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx, unresolved_recv)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def add_keyword_merge_box(genv, rest, literal_pairs, fallback)
|
|
90
|
+
key = [:kw_merge, rest, literal_pairs, fallback]
|
|
91
|
+
new_boxes[key] ||= KeywordMergeBox.new(@node, genv, rest, literal_pairs, fallback)
|
|
87
92
|
end
|
|
88
93
|
|
|
89
94
|
def add_hash_splat_box(genv, arg, unified_key, unified_val)
|
|
@@ -405,7 +405,9 @@ module TypeProf::Core
|
|
|
405
405
|
break
|
|
406
406
|
end
|
|
407
407
|
end
|
|
408
|
-
|
|
408
|
+
# The base class has no name to show
|
|
409
|
+
owner = mod.cpath.last == AST::StructNewNode::BASE_CNAME ? base_ty.mod : mod
|
|
410
|
+
yield mid, "#{ owner.cpath.join("::" )}#{ singleton ? "." : "#" }#{ mid } : #{ sig }" if sig
|
|
409
411
|
end
|
|
410
412
|
end
|
|
411
413
|
end
|
|
@@ -456,6 +458,7 @@ module TypeProf::Core
|
|
|
456
458
|
def dump_declarations(path)
|
|
457
459
|
stack = []
|
|
458
460
|
out = []
|
|
461
|
+
seen_consts = Set.empty
|
|
459
462
|
@rb_text_nodes[path]&.traverse do |event, node|
|
|
460
463
|
case node
|
|
461
464
|
when AST::ModuleNode
|
|
@@ -480,6 +483,10 @@ module TypeProf::Core
|
|
|
480
483
|
s = "class #{ format_declared_const_path(node.static_cpath, stack) }"
|
|
481
484
|
mod = @genv.resolve_cpath(node.static_cpath)
|
|
482
485
|
superclass = mod.superclass
|
|
486
|
+
# The base class is not shown; its members are printed inline
|
|
487
|
+
while superclass && superclass.cpath.last == AST::StructNewNode::BASE_CNAME
|
|
488
|
+
superclass = superclass.superclass
|
|
489
|
+
end
|
|
483
490
|
if superclass == nil
|
|
484
491
|
s << " # failed to identify its superclass"
|
|
485
492
|
elsif superclass.cpath != []
|
|
@@ -496,8 +503,16 @@ module TypeProf::Core
|
|
|
496
503
|
out << " " * stack.size + "include #{ inc_mod.show_cpath }"
|
|
497
504
|
end
|
|
498
505
|
end
|
|
506
|
+
mod.extended_modules.each do |ext_def, ext_mod|
|
|
507
|
+
if ext_def.is_a?(AST::ConstantReadNode) && ext_def.lenv.path == path
|
|
508
|
+
out << " " * stack.size + "extend #{ ext_mod.show_cpath }"
|
|
509
|
+
end
|
|
510
|
+
end
|
|
499
511
|
# Output method definitions from meta nodes (StructNewNode etc.)
|
|
500
512
|
node.boxes(:mdef) do |mdef|
|
|
513
|
+
# A user-written method overrides the generated one
|
|
514
|
+
next if node.is_a?(AST::StructNewNode) &&
|
|
515
|
+
!@genv.resolve_method(node.static_cpath, mdef.singleton, mdef.mid).defs.empty?
|
|
501
516
|
out << " " * stack.size + "def #{ mdef.singleton ? "self." : "" }#{ mdef.mid }: " + mdef.show(@options[:output_parameter_names])
|
|
502
517
|
end
|
|
503
518
|
else
|
|
@@ -508,7 +523,14 @@ module TypeProf::Core
|
|
|
508
523
|
when AST::ConstantWriteNode
|
|
509
524
|
if node.static_cpath
|
|
510
525
|
if event == :enter
|
|
511
|
-
|
|
526
|
+
unless seen_consts.include?(node.static_cpath)
|
|
527
|
+
seen_consts << node.static_cpath
|
|
528
|
+
cdef = @genv.resolve_const(node.static_cpath)
|
|
529
|
+
# Use the assigned value for a single write so a same-named class
|
|
530
|
+
# or module (e.g. declared in RBS) is not mixed in; union the types otherwise.
|
|
531
|
+
ret = cdef.defs.size > 1 ? cdef.vtx : node.ret
|
|
532
|
+
out << " " * stack.size + "#{ format_declared_const_path(node.static_cpath, stack) }: #{ ret.show }"
|
|
533
|
+
end
|
|
512
534
|
end
|
|
513
535
|
end
|
|
514
536
|
else
|
data/lib/typeprof/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typeprof
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.33.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yusuke Endoh
|
|
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
118
118
|
- !ruby/object:Gem::Version
|
|
119
119
|
version: '0'
|
|
120
120
|
requirements: []
|
|
121
|
-
rubygems_version: 4.0.
|
|
121
|
+
rubygems_version: 4.0.16
|
|
122
122
|
specification_version: 4
|
|
123
123
|
summary: TypeProf is a type analysis tool for Ruby code based on abstract interpretation
|
|
124
124
|
test_files: []
|