typeprof 0.31.0 → 0.32.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/doc/report_guide.md +88 -0
  4. data/lib/typeprof/cli/cli.rb +9 -3
  5. data/lib/typeprof/code_range.rb +7 -5
  6. data/lib/typeprof/core/ast/base.rb +18 -6
  7. data/lib/typeprof/core/ast/call.rb +96 -32
  8. data/lib/typeprof/core/ast/const.rb +12 -9
  9. data/lib/typeprof/core/ast/control.rb +60 -30
  10. data/lib/typeprof/core/ast/meta.rb +194 -2
  11. data/lib/typeprof/core/ast/method.rb +74 -20
  12. data/lib/typeprof/core/ast/misc.rb +84 -7
  13. data/lib/typeprof/core/ast/module.rb +33 -3
  14. data/lib/typeprof/core/ast/sig_decl.rb +85 -24
  15. data/lib/typeprof/core/ast/sig_type.rb +78 -32
  16. data/lib/typeprof/core/ast/value.rb +14 -6
  17. data/lib/typeprof/core/ast/variable.rb +11 -4
  18. data/lib/typeprof/core/ast.rb +97 -14
  19. data/lib/typeprof/core/builtin.rb +184 -12
  20. data/lib/typeprof/core/env/method.rb +171 -6
  21. data/lib/typeprof/core/env/method_entity.rb +18 -15
  22. data/lib/typeprof/core/env/module_entity.rb +56 -18
  23. data/lib/typeprof/core/env/static_read.rb +4 -4
  24. data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
  25. data/lib/typeprof/core/env/value_entity.rb +25 -3
  26. data/lib/typeprof/core/env.rb +81 -15
  27. data/lib/typeprof/core/graph/box.rb +380 -53
  28. data/lib/typeprof/core/graph/change_set.rb +59 -46
  29. data/lib/typeprof/core/graph/filter.rb +8 -5
  30. data/lib/typeprof/core/graph/vertex.rb +20 -19
  31. data/lib/typeprof/core/service.rb +317 -23
  32. data/lib/typeprof/core/type.rb +43 -8
  33. data/lib/typeprof/core/util.rb +6 -0
  34. data/lib/typeprof/lsp/messages.rb +5 -0
  35. data/lib/typeprof/lsp/server.rb +35 -4
  36. data/lib/typeprof/version.rb +1 -1
  37. metadata +3 -2
@@ -69,6 +69,20 @@ module TypeProf::Core
69
69
  else
70
70
  false
71
71
  end
72
+ elsif a_args.positionals.size == 3
73
+ # ary[start, len] = val
74
+ # Use SplatBox to extract element types from the assigned value
75
+ elem_vtx = case ty
76
+ when Type::Array
77
+ ty.get_elem(@genv)
78
+ when Type::Instance
79
+ ty.mod == @genv.mod_ary ? ty.args[0] : nil
80
+ end
81
+ return false unless elem_vtx
82
+ val = a_args.positionals[2]
83
+ splat_ret = changes.add_splat_box(@genv, val).ret
84
+ changes.add_edge(@genv, splat_ret, elem_vtx)
85
+ true
72
86
  else
73
87
  false
74
88
  end
@@ -90,7 +104,7 @@ module TypeProf::Core
90
104
  def hash_aref(changes, node, ty, a_args, ret)
91
105
  if a_args.positionals.size == 1
92
106
  case ty
93
- when Type::Hash, Type::Record
107
+ when Type::Hash
94
108
  idx = node.positional_args[0]
95
109
  idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
96
110
  value = ty.get_value(idx)
@@ -101,6 +115,20 @@ module TypeProf::Core
101
115
  changes.add_edge(@genv, Source.new(), ret)
102
116
  end
103
117
  true
118
+ when Type::Record
119
+ idx = node.positional_args[0]
120
+ idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
121
+ value = ty.get_value(idx)
122
+ if value
123
+ changes.add_edge(@genv, value, ret)
124
+ else
125
+ changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
126
+ end
127
+ # Symbol variable access - add nil possibility
128
+ if idx.nil?
129
+ changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
130
+ end
131
+ true
104
132
  else
105
133
  false
106
134
  end
@@ -125,6 +153,15 @@ module TypeProf::Core
125
153
  end
126
154
  changes.add_edge(@genv, val, ret)
127
155
  true
156
+ when Type::Record
157
+ val = a_args.positionals[1]
158
+ idx = node.positional_args[0]
159
+ if idx.is_a?(AST::SymbolNode)
160
+ field_vtx = ty.get_value(idx.lit)
161
+ changes.add_edge(@genv, val, field_vtx) if field_vtx
162
+ end
163
+ changes.add_edge(@genv, val, ret)
164
+ true
128
165
  else
129
166
  false
130
167
  end
@@ -133,19 +170,154 @@ module TypeProf::Core
133
170
  end
134
171
  end
135
172
 
173
+ def object_method(changes, node, ty, a_args, ret)
174
+ if a_args.positionals.size == 1
175
+ sym_node = node.positional_args[0]
176
+ if sym_node.is_a?(AST::SymbolNode)
177
+ method_ty = Type::Method.new(@genv, ty, sym_node.lit)
178
+ changes.add_edge(@genv, Source.new(method_ty), ret)
179
+ return true
180
+ end
181
+ end
182
+ false
183
+ end
184
+
185
+ def method_call(changes, node, ty, a_args, ret)
186
+ case ty
187
+ when Type::Method
188
+ recv = Source.new(ty.recv_ty)
189
+ box = changes.add_method_call_box(@genv, recv, ty.mid, a_args, false)
190
+ changes.add_edge(@genv, box.ret, ret)
191
+ true
192
+ else
193
+ false
194
+ end
195
+ end
196
+
197
+ def kernel_send(changes, node, ty, a_args, ret)
198
+ return false if a_args.positionals.empty?
199
+
200
+ if a_args.splat_flags[0]
201
+ # send(*array) case: extract method name and args from array elements
202
+ splat_vtx = a_args.positionals[0]
203
+ changes.add_edge(@genv, splat_vtx, changes.target)
204
+
205
+ rest_positionals = a_args.positionals[1..]
206
+ rest_splat_flags = a_args.splat_flags[1..]
207
+
208
+ splat_vtx.each_type do |ary_ty|
209
+ next unless ary_ty.is_a?(Type::Array)
210
+
211
+ if ary_ty.elems && ary_ty.elems.size >= 1
212
+ # Tuple: use per-element precision
213
+ method_name_vtx = ary_ty.elems[0]
214
+ changes.add_edge(@genv, method_name_vtx, changes.target)
215
+
216
+ elem_args = ary_ty.elems[1..] + rest_positionals
217
+ elem_flags = ::Array.new(ary_ty.elems.size - 1, false) + rest_splat_flags
218
+ send_a_args = ActualArguments.new(elem_args, elem_flags, a_args.keywords, a_args.block)
219
+
220
+ method_name_vtx.each_type do |sym_ty|
221
+ if sym_ty.is_a?(Type::Symbol)
222
+ recv = Source.new(ty)
223
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
224
+ changes.add_edge(@genv, box.ret, ret)
225
+ end
226
+ end
227
+ else
228
+ # Non-tuple array: use unified element type for method name
229
+ elem_vtx = ary_ty.get_elem(@genv)
230
+ next unless elem_vtx
231
+ changes.add_edge(@genv, elem_vtx, changes.target)
232
+
233
+ send_a_args = ActualArguments.new(rest_positionals, rest_splat_flags, a_args.keywords, a_args.block)
234
+
235
+ elem_vtx.each_type do |sym_ty|
236
+ if sym_ty.is_a?(Type::Symbol)
237
+ recv = Source.new(ty)
238
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
239
+ changes.add_edge(@genv, box.ret, ret)
240
+ end
241
+ end
242
+ end
243
+ end
244
+ else
245
+ # send(:sym, ...) case
246
+ changes.add_edge(@genv, a_args.positionals[0], changes.target)
247
+ send_a_args = ActualArguments.new(
248
+ a_args.positionals[1..],
249
+ a_args.splat_flags[1..],
250
+ a_args.keywords,
251
+ a_args.block,
252
+ )
253
+ a_args.positionals[0].each_type do |sym_ty|
254
+ if sym_ty.is_a?(Type::Symbol)
255
+ recv = Source.new(ty)
256
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
257
+ changes.add_edge(@genv, box.ret, ret)
258
+ end
259
+ end
260
+ end
261
+ true
262
+ end
263
+
264
+ def kernel_array(changes, node, ty, a_args, ret)
265
+ return false unless a_args.positionals.size == 1
266
+
267
+ arg_vtx = a_args.positionals[0]
268
+ elem_vtx = Vertex.new(node)
269
+ handled = false
270
+ needs_elem_wrap = false
271
+
272
+ arg_vtx.each_type do |arg_ty|
273
+ handled = true
274
+ case arg_ty
275
+ when Type::Instance
276
+ if arg_ty.mod == @genv.mod_range && arg_ty.args && !arg_ty.args.empty?
277
+ changes.add_edge(@genv, arg_ty.args[0], elem_vtx)
278
+ needs_elem_wrap = true
279
+ elsif arg_ty.mod == @genv.mod_ary
280
+ changes.add_edge(@genv, Source.new(arg_ty), ret)
281
+ else
282
+ changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
283
+ needs_elem_wrap = true
284
+ end
285
+ when Type::Array
286
+ changes.add_edge(@genv, Source.new(arg_ty), ret)
287
+ else
288
+ changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
289
+ needs_elem_wrap = true
290
+ end
291
+ end
292
+
293
+ return false unless handled
294
+
295
+ if needs_elem_wrap
296
+ ary_ty = @genv.gen_ary_type(elem_vtx)
297
+ changes.add_edge(@genv, Source.new(ary_ty), ret)
298
+ end
299
+ true
300
+ end
301
+
136
302
  def deploy
137
- {
138
- class_new: [[:Class], false, :new],
139
- object_class: [[:Object], false, :class],
140
- proc_call: [[:Proc], false, :call],
141
- array_aref: [[:Array], false, :[]],
142
- array_aset: [[:Array], false, :[]=],
143
- array_push: [[:Array], false, :<<],
144
- hash_aref: [[:Hash], false, :[]],
145
- hash_aset: [[:Hash], false, :[]=],
146
- }.each do |key, (cpath, singleton, mid)|
303
+ [
304
+ [method(:class_new), [:Class], false, :new],
305
+ [method(:object_class), [:Object], false, :class],
306
+ [method(:proc_call), [:Proc], false, :call],
307
+ [method(:array_aref), [:Array], false, :[]],
308
+ [method(:array_aset), [:Array], false, :[]=],
309
+ [method(:array_push), [:Array], false, :<<],
310
+ [method(:hash_aref), [:Hash], false, :[]],
311
+ [method(:hash_aset), [:Hash], false, :[]=],
312
+ [method(:object_method), [:Kernel], false, :method],
313
+ [method(:method_call), [:Method], false, :call],
314
+ [method(:kernel_send), [:BasicObject], false, :__send__],
315
+ [method(:kernel_send), [:Kernel], false, :public_send],
316
+ [method(:kernel_send), [:Kernel], false, :send],
317
+ [method(:kernel_array), [:Kernel], false, :Array],
318
+ ].each do |builtin, cpath, singleton, mid|
147
319
  me = @genv.resolve_method(cpath, singleton, mid)
148
- me.builtin = method(key)
320
+ me.builtin = builtin
149
321
  end
150
322
  end
151
323
  end
@@ -41,6 +41,17 @@ module TypeProf::Core
41
41
  ActualArguments.new(positionals, splat_flags, keywords, block)
42
42
  end
43
43
 
44
+ def with_keywords_as_last_positional_hash
45
+ return self unless @keywords
46
+
47
+ ActualArguments.new(
48
+ @positionals + [@keywords],
49
+ @splat_flags + [false],
50
+ nil,
51
+ @block
52
+ )
53
+ end
54
+
44
55
  def get_rest_args(genv, changes, start_rest, end_rest)
45
56
  vtxs = []
46
57
 
@@ -69,6 +80,9 @@ module TypeProf::Core
69
80
  case ty
70
81
  when Type::Hash
71
82
  changes.add_edge(genv, ty.get_value(name), vtx)
83
+ when Type::Record
84
+ field_vtx = ty.get_value(name)
85
+ changes.add_edge(genv, field_vtx, vtx) if field_vtx
72
86
  when Type::Instance
73
87
  if ty.mod == genv.mod_hash
74
88
  changes.add_edge(genv, ty.args[1], vtx)
@@ -81,6 +95,162 @@ module TypeProf::Core
81
95
  end
82
96
  end
83
97
 
98
+ class ForwardingArguments
99
+ def initialize(req_positionals, opt_positionals, opt_positional_elems, rest_positionals, post_positionals, req_keyword_pairs, opt_keyword_pairs, rest_keywords, block)
100
+ @req_positionals = req_positionals
101
+ @opt_positionals = opt_positionals
102
+ @opt_positional_elems = opt_positional_elems
103
+ @rest_positionals = rest_positionals
104
+ @post_positionals = post_positionals
105
+ @req_keyword_pairs = req_keyword_pairs
106
+ @opt_keyword_pairs = opt_keyword_pairs
107
+ @rest_keywords = rest_keywords
108
+ @block = block
109
+ end
110
+
111
+ attr_reader :block
112
+
113
+ def to_actual_arguments(genv, changes, node)
114
+ positionals = @req_positionals.dup
115
+ splat_flags = ::Array.new(positionals.size, false)
116
+
117
+ @opt_positionals.each do |arg|
118
+ positionals << arg
119
+ splat_flags << true
120
+ end
121
+
122
+ if @rest_positionals
123
+ positionals << @rest_positionals
124
+ splat_flags << true
125
+ end
126
+
127
+ @post_positionals.each do |arg|
128
+ positionals << arg
129
+ splat_flags << false
130
+ end
131
+
132
+ keywords = build_keyword_args(genv, changes, node)
133
+ ActualArguments.new(positionals, splat_flags, keywords, @block)
134
+ end
135
+
136
+ def accept_actual_arguments(genv, changes, a_args)
137
+ if a_args.splat_flags.any?
138
+ start_rest = [a_args.splat_flags.index(true), @req_positionals.size + @opt_positionals.size].min
139
+ end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @post_positionals.size].max
140
+ rest_vtxs = a_args.get_rest_args(genv, changes, start_rest, end_rest)
141
+
142
+ @req_positionals.each_with_index do |f_vtx, i|
143
+ if i < start_rest
144
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
145
+ else
146
+ rest_vtxs.each do |vtx|
147
+ changes.add_edge(genv, vtx, f_vtx)
148
+ end
149
+ end
150
+ end
151
+
152
+ @opt_positional_elems.each_with_index do |elem_vtx, i|
153
+ i += @req_positionals.size
154
+ if i < start_rest
155
+ changes.add_edge(genv, a_args.positionals[i], elem_vtx)
156
+ else
157
+ rest_vtxs.each do |vtx|
158
+ changes.add_edge(genv, vtx, elem_vtx)
159
+ end
160
+ end
161
+ end
162
+
163
+ @post_positionals.each_with_index do |f_vtx, i|
164
+ i += a_args.positionals.size - @post_positionals.size
165
+ if end_rest <= i
166
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
167
+ else
168
+ rest_vtxs.each do |vtx|
169
+ changes.add_edge(genv, vtx, f_vtx)
170
+ end
171
+ end
172
+ end
173
+
174
+ else
175
+ @req_positionals.each_with_index do |f_vtx, i|
176
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
177
+ end
178
+
179
+ @post_positionals.each_with_index do |f_vtx, i|
180
+ i -= @post_positionals.size
181
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
182
+ end
183
+
184
+ start_rest = @req_positionals.size
185
+ end_rest = a_args.positionals.size - @post_positionals.size
186
+ i = 0
187
+ while i < @opt_positional_elems.size && start_rest < end_rest
188
+ changes.add_edge(genv, a_args.positionals[start_rest], @opt_positional_elems[i])
189
+ i += 1
190
+ start_rest += 1
191
+ end
192
+ end
193
+
194
+ changes.add_edge(genv, a_args.block, @block) if @block && a_args.block
195
+
196
+ return unless a_args.keywords
197
+
198
+ @req_keyword_pairs.each do |name, f_vtx|
199
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
200
+ end
201
+
202
+ @opt_keyword_pairs.each do |name, f_vtx|
203
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
204
+ end
205
+
206
+ if @rest_keywords
207
+ named_keys = @req_keyword_pairs.map(&:first) + @opt_keyword_pairs.map(&:first)
208
+ a_args.keywords.each_type do |kw_ty|
209
+ case kw_ty
210
+ when Type::Record
211
+ rest_fields = kw_ty.fields.reject {|key, _| named_keys.include?(key) }
212
+ base = kw_ty.base_type(genv)
213
+ rest_record = Type::Record.new(genv, rest_fields, base)
214
+ changes.add_edge(genv, Source.new(rest_record), @rest_keywords)
215
+ when Type::Hash, Type::Instance
216
+ changes.add_edge(genv, Source.new(kw_ty), @rest_keywords)
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ private
223
+
224
+ def build_keyword_args(genv, changes, node)
225
+ return nil if @req_keyword_pairs.empty? && @opt_keyword_pairs.empty? && !@rest_keywords
226
+ return @rest_keywords if @req_keyword_pairs.empty? && @opt_keyword_pairs.empty?
227
+
228
+ unified_key = Vertex.new(node)
229
+ unified_val = Vertex.new(node)
230
+ literal_pairs = {}
231
+
232
+ @req_keyword_pairs.each do |name, vtx|
233
+ changes.add_edge(genv, Source.new(Type::Symbol.new(genv, name)), unified_key)
234
+ changes.add_edge(genv, vtx, unified_val)
235
+ literal_pairs[name] = vtx
236
+ end
237
+
238
+ @opt_keyword_pairs.each do |name, vtx|
239
+ changes.add_edge(genv, Source.new(Type::Symbol.new(genv, name)), unified_key)
240
+ changes.add_edge(genv, vtx, unified_val)
241
+ end
242
+
243
+ base_hash_type = genv.gen_hash_type(unified_key, unified_val)
244
+ changes.add_hash_splat_box(genv, @rest_keywords, unified_key, unified_val) if @rest_keywords
245
+
246
+ if literal_pairs.empty?
247
+ Source.new(base_hash_type)
248
+ else
249
+ Source.new(Type::Record.new(genv, literal_pairs, base_hash_type))
250
+ end
251
+ end
252
+ end
253
+
84
254
  class Block
85
255
  #: (AST::CallBaseNode, Vertex, Array[Vertex], Array[EscapeBox]) -> void
86
256
  def initialize(node, f_ary_arg, f_args, next_boxes)
@@ -94,12 +264,7 @@ module TypeProf::Core
94
264
 
95
265
  def accept_args(genv, changes, caller_positionals)
96
266
  if caller_positionals.size == 1 && @f_args.size >= 2
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
267
+ changes.add_edge(genv, caller_positionals[0], @f_ary_arg)
103
268
  else
104
269
  caller_positionals.zip(@f_args) do |a_arg, f_arg|
105
270
  changes.add_edge(genv, a_arg, f_arg) if f_arg
@@ -2,60 +2,63 @@ module TypeProf::Core
2
2
  class MethodEntity
3
3
  def initialize
4
4
  @builtin = nil
5
- @decls = Set[]
6
- @overloading_decls = Set[]
7
- @defs = Set[]
8
- @aliases = {}
9
- @method_call_boxes = Set[]
10
5
  end
11
6
 
12
- attr_reader :decls, :defs, :aliases, :method_call_boxes
13
7
  attr_accessor :builtin
14
8
 
9
+ def decls = @decls ||= Set.empty
10
+ def defs = @defs ||= Set.empty
11
+ def aliases = @aliases ||= {}
12
+ def method_call_boxes = @method_call_boxes ||= Set.empty
13
+
14
+ private def overloading_decls = @overloading_decls ||= Set.empty
15
+
15
16
  def add_decl(decl)
16
17
  if decl.overloading
17
- @overloading_decls << decl
18
+ overloading_decls << decl
18
19
  else
19
- @decls << decl
20
+ decls << decl
20
21
  end
21
22
  end
22
23
 
23
24
  def remove_decl(decl)
24
25
  if decl.overloading
25
- @overloading_decls.delete(decl) || raise
26
+ overloading_decls.delete(decl) || raise
26
27
  else
27
- @decls.delete(decl) || raise
28
+ decls.delete(decl) || raise
28
29
  end
29
30
  end
30
31
 
31
32
  def add_def(mdef)
32
- @defs << mdef
33
+ defs << mdef
33
34
  self
34
35
  end
35
36
 
36
37
  def remove_def(mdef)
37
- @defs.delete(mdef) || raise
38
+ defs.delete(mdef) || raise
38
39
  end
39
40
 
40
41
  def add_alias(node, old_mid)
41
- @aliases[node] = old_mid
42
+ aliases[node] = old_mid
42
43
  end
43
44
 
44
45
  def remove_alias(node)
45
- @aliases.delete(node) || raise
46
+ aliases.delete(node) || raise
46
47
  end
47
48
 
48
49
  def exist?
49
- @builtin || !@decls.empty? || !@defs.empty?
50
+ @builtin || (@decls && !@decls.empty?) || (@defs && !@defs.empty?)
50
51
  end
51
52
 
52
53
  def add_run_all_mdefs(genv)
54
+ return unless @defs
53
55
  @defs.each do |mdef|
54
56
  genv.add_run(mdef)
55
57
  end
56
58
  end
57
59
 
58
60
  def add_run_all_method_call_boxes(genv)
61
+ return unless @method_call_boxes
59
62
  @method_call_boxes.each do |box|
60
63
  genv.add_run(box)
61
64
  end
@@ -3,13 +3,18 @@ module TypeProf::Core
3
3
  def initialize(cpath, outer_module = self)
4
4
  @cpath = cpath
5
5
 
6
- @module_decls = Set[]
7
- @module_defs = Set[]
8
- @include_decls = Set[]
9
- @include_defs = Set[]
6
+ @module_decls = Set.empty
7
+ @module_defs = Set.empty
8
+ @include_decls = Set.empty
9
+ @include_defs = Set.empty
10
10
  @prepend_decls = []
11
11
  @prepend_defs = []
12
12
 
13
+ # `class Foo = Bar` / `module Foo = Bar` declarations attached to this entity.
14
+ # Maps an alias decl to the target ModuleEntity at the time of registration.
15
+ @alias_decls = {}
16
+ @alias_target = nil
17
+
13
18
  @inner_modules = {}
14
19
  @outer_module = outer_module
15
20
 
@@ -25,7 +30,7 @@ module TypeProf::Core
25
30
 
26
31
  # class Foo[X, Y, Z] < Bar[A, B, C]
27
32
  @superclass_type_args = nil # A, B, C
28
- @type_params = [] # X, Y, Z
33
+ @type_params = {} # X, Y, Z
29
34
 
30
35
  @consts = {}
31
36
  @methods = { true => {}, false => {} }
@@ -34,14 +39,16 @@ module TypeProf::Core
34
39
  @type_aliases = {}
35
40
 
36
41
  @static_reads = {}
37
- @subclass_checks = Set[]
38
- @ivar_reads = Set[] # should be handled in @ivars ??
39
- @cvar_reads = Set[]
42
+ @subclass_checks = Set.empty
43
+ @ivar_reads = Set.empty # should be handled in @ivars ??
44
+ @cvar_reads = Set.empty
40
45
  end
41
46
 
42
47
  attr_reader :cpath
43
48
  attr_reader :module_decls
44
49
  attr_reader :module_defs
50
+ attr_reader :alias_decls
51
+ attr_reader :alias_target
45
52
 
46
53
  attr_reader :inner_modules
47
54
  attr_reader :outer_module
@@ -79,7 +86,7 @@ module TypeProf::Core
79
86
  end
80
87
 
81
88
  def exist?
82
- !@module_decls.empty? || !@module_defs.empty?
89
+ !@module_decls.empty? || !@module_defs.empty? || !@alias_decls.empty?
83
90
  end
84
91
 
85
92
  def on_inner_modules_changed(genv, changed_cname)
@@ -115,9 +122,10 @@ module TypeProf::Core
115
122
  @module_decls << decl
116
123
 
117
124
  if @type_params
118
- update_type_params if @type_params != decl.params
125
+ update_type_params
119
126
  else
120
- @type_params = decl.params
127
+ @type_params = {}
128
+ decl.params.zip(decl.params_default_types) {|name, default_type| @type_params[name] = default_type }
121
129
  end
122
130
 
123
131
  if decl.is_a?(AST::SigClassNode) && !@superclass_type_args
@@ -133,7 +141,7 @@ module TypeProf::Core
133
141
  @outer_module.get_const(get_cname).remove_decl(decl)
134
142
  @module_decls.delete(decl) || raise
135
143
 
136
- update_type_params if @type_params == decl.params
144
+ update_type_params
137
145
  if decl.is_a?(AST::SigClassNode) && @superclass_type_args == decl.superclass_args
138
146
  @superclass_type_args = nil
139
147
  @module_decls.each do |decl|
@@ -152,13 +160,12 @@ module TypeProf::Core
152
160
  @module_decls.each do |decl|
153
161
  params = decl.params
154
162
  next unless params
155
- if @type_params
156
- @type_params = params if (@type_params <=> params) > 0
157
- else
158
- @type_params = params
163
+ if !@type_params || @type_params.size < params.size
164
+ @type_params = {}
165
+ params.zip(decl.params_default_types) {|name, default_type| @type_params[name] = default_type }
159
166
  end
160
167
  end
161
- @type_params ||= []
168
+ @type_params ||= {}
162
169
  # TODO: report an error if there are multiple inconsistent declarations
163
170
  end
164
171
 
@@ -176,6 +183,22 @@ module TypeProf::Core
176
183
  on_module_removed(genv)
177
184
  end
178
185
 
186
+ def add_alias_decl(genv, decl, target_mod)
187
+ on_module_added(genv)
188
+ @alias_decls[decl] = target_mod
189
+ @alias_target = @alias_decls.values.first
190
+ ce = @outer_module.get_const(get_cname)
191
+ ce.add_decl(decl)
192
+ ce
193
+ end
194
+
195
+ def remove_alias_decl(genv, decl)
196
+ @outer_module.get_const(get_cname).remove_decl(decl)
197
+ @alias_decls.delete(decl) || raise
198
+ @alias_target = @alias_decls.values.first
199
+ on_module_removed(genv)
200
+ end
201
+
179
202
  def add_include_decl(genv, node)
180
203
  @include_decls << node
181
204
  genv.add_static_eval_queue(:parent_modules_changed, self)
@@ -237,7 +260,7 @@ module TypeProf::Core
237
260
  old_parent.child_modules.delete(self) if set.empty?
238
261
  end
239
262
  if new_parent
240
- set = new_parent.child_modules[self] ||= Set[]
263
+ set = new_parent.child_modules[self] ||= Set.empty
241
264
  set << origin
242
265
  end
243
266
  return [new_parent, true]
@@ -261,6 +284,8 @@ module TypeProf::Core
261
284
  next
262
285
  when AST::ModuleNode
263
286
  return nil
287
+ when AST::StructNewNode
288
+ return [] # inherits from Object (Struct < Object)
264
289
  else
265
290
  raise
266
291
  end
@@ -436,6 +461,19 @@ module TypeProf::Core
436
461
  @ivars[singleton][name] ||= ValueEntity.new
437
462
  end
438
463
 
464
+ def add_ivar_decl(genv, singleton, name, decl)
465
+ ive = get_ivar(singleton, name)
466
+ ive.add_decl(decl)
467
+ ive.on_decl_changed(genv)
468
+ ive
469
+ end
470
+
471
+ def remove_ivar_decl(genv, singleton, name, decl)
472
+ ive = get_ivar(singleton, name)
473
+ ive.remove_decl(decl)
474
+ ive.on_decl_changed(genv)
475
+ end
476
+
439
477
  def get_cvar(name)
440
478
  @cvars[name] ||= ValueEntity.new
441
479
  end
@@ -2,8 +2,8 @@ module TypeProf::Core
2
2
  class StaticRead
3
3
  def initialize(name)
4
4
  @name = name
5
- @followers = Set[]
6
- @source_modules = Set[]
5
+ @followers = Set.empty
6
+ @source_modules = Set.empty
7
7
  end
8
8
 
9
9
  attr_reader :name, :followers
@@ -37,11 +37,11 @@ module TypeProf::Core
37
37
  scope = cref.cpath
38
38
  mod = genv.resolve_cpath(scope)
39
39
  genv.each_superclass(mod, false) do |mod, _singleton|
40
- break if mod == genv.mod_object && break_object
40
+ break if mod == genv.mod_object && (break_object || cref.outer)
41
41
 
42
42
  unless @source_modules.include?(mod)
43
43
  @source_modules << mod
44
- (mod.static_reads[@name] ||= Set[]) << self
44
+ (mod.static_reads[@name] ||= Set.empty) << self
45
45
  end
46
46
 
47
47
  return if check_module(genv, mod)