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
@@ -6,7 +6,7 @@ module TypeProf::Core
6
6
  stmts = raw_node.body
7
7
  @stmts = stmts.map.with_index do |n, i|
8
8
  if n
9
- AST.create_node(n, lenv, i == stmts.length - 1 ? use_result : false)
9
+ AST.create_node(n, lenv, i == stmts.length - 1 ? use_result : false, true)
10
10
  else
11
11
  last = code_range.last
12
12
  DummyNilNode.new(TypeProf::CodeRange.new(last, last), lenv)
@@ -139,6 +139,63 @@ module TypeProf::Core
139
139
  end
140
140
  end
141
141
 
142
+ class MultiTargetNode < Node
143
+ def initialize(raw_node, rhs, lenv)
144
+ super(raw_node, lenv)
145
+ @rhs = rhs
146
+ @lefts = raw_node.lefts.map do |raw_lhs|
147
+ AST.create_target_node(raw_lhs, lenv)
148
+ end
149
+ if raw_node.rest
150
+ case raw_node.rest.type
151
+ when :splat_node
152
+ if raw_node.rest.expression
153
+ @rest = AST.create_target_node(raw_node.rest.expression, lenv)
154
+ end
155
+ when :implicit_rest_node
156
+ # no assignment target
157
+ else
158
+ raise "unexpected rest node in multi_target: #{raw_node.rest.type}"
159
+ end
160
+ end
161
+ @rights = raw_node.rights.map do |raw_rhs|
162
+ AST.create_target_node(raw_rhs, lenv)
163
+ end
164
+ end
165
+
166
+ attr_reader :rhs, :lefts, :rest, :rights
167
+
168
+ def subnodes = { rhs:, lefts:, rest:, rights: }
169
+
170
+ def install0(genv)
171
+ # The rhs should be installed by the parent MultiWriteNode
172
+ # Here we set up the multi-assignment box for nested destructuring
173
+ value = @rhs.install(genv)
174
+
175
+ @lefts.each {|lhs| lhs.install(genv) }
176
+ @lefts.each {|lhs| lhs.rhs.ret || raise(lhs.rhs.inspect) }
177
+ lefts = @lefts.map {|lhs| lhs.rhs.ret }
178
+
179
+ rest_elem = nil
180
+ if @rest
181
+ rest_elem = Vertex.new(self)
182
+ @rest.install(genv)
183
+ @rest.rhs.ret || raise(@rest.rhs.inspect)
184
+ @changes.add_edge(genv, Source.new(Type::Instance.new(genv, genv.mod_ary, [rest_elem])), @rest.rhs.ret)
185
+ end
186
+
187
+ rights = nil
188
+ if @rights && !@rights.empty?
189
+ @rights.each {|rhs| rhs.install(genv) }
190
+ @rights.each {|rhs| rhs.rhs.ret || raise(rhs.rhs.inspect) }
191
+ rights = @rights.map {|rhs| rhs.rhs.ret }
192
+ end
193
+
194
+ box = @changes.add_masgn_box(genv, value, lefts, rest_elem, rights)
195
+ box.ret
196
+ end
197
+ end
198
+
142
199
  class MatchWriteNode < Node
143
200
  def initialize(raw_node, lenv)
144
201
  super(raw_node, lenv)
@@ -199,28 +256,48 @@ module TypeProf::Core
199
256
  vtx = @expr.install(genv)
200
257
 
201
258
  a_args = ActualArguments.new([], [], nil, nil)
202
- vtx = @changes.add_method_call_box(genv, vtx, :to_a, a_args, false).ret
259
+ to_a_vtx = @changes.add_method_call_box(genv, vtx, :to_a, a_args, false, suppress_errors: true).ret
203
260
 
204
- @changes.add_splat_box(genv, vtx).ret
261
+ @changes.add_splat_box(genv, to_a_vtx, nil, vtx).ret
205
262
  end
206
263
  end
207
264
 
208
265
  class ForNode < Node
209
266
  def initialize(raw_node, lenv)
210
267
  super(raw_node, lenv)
211
- # XXX: tentative implementation
212
- # raw_node.index
268
+ @index = AST.create_target_node(raw_node.index, lenv)
213
269
  @expr = AST.create_node(raw_node.collection, lenv)
214
270
  @body = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : DummyNilNode.new(TypeProf::CodeRange.new(code_range.last, code_range.last), lenv)
215
271
  end
216
272
 
217
- attr_reader :expr, :body
273
+ attr_reader :index, :expr, :body
218
274
 
219
- def subnodes = { expr:, body: }
275
+ def subnodes = { index:, expr:, body: }
220
276
 
221
277
  def install0(genv)
222
278
  @expr.install(genv)
279
+
280
+ vars = []
281
+ @index.modified_vars(@lenv.locals.keys, vars)
282
+ @body.modified_vars(@lenv.locals.keys, vars)
283
+ vars.uniq!
284
+
285
+ old_vtxs = {}
286
+ vars.each do |var|
287
+ vtx = @lenv.get_var(var)
288
+ nvtx = vtx.new_vertex(genv, self)
289
+ old_vtxs[var] = nvtx
290
+ @lenv.set_var(var, nvtx)
291
+ end
292
+
293
+ @index.install(genv)
223
294
  @body.install(genv)
295
+
296
+ vars.each do |var|
297
+ @changes.add_edge(genv, @lenv.get_var(var), old_vtxs[var])
298
+ @lenv.set_var(var, old_vtxs[var])
299
+ end
300
+
224
301
  Source.new(genv.nil_type)
225
302
  end
226
303
  end
@@ -12,13 +12,13 @@ module TypeProf::Core
12
12
 
13
13
  if @static_cpath
14
14
  ncref = CRef.new(@static_cpath, meta ? :metaclass : :class, nil, lenv.cref)
15
- nlenv = LocalEnv.new(@lenv.path, ncref, {}, [])
15
+ nlenv = LocalEnv.new(@lenv.file_context, ncref, {}, [])
16
16
  @body = raw_scope ? AST.create_node(raw_scope, nlenv, use_result) : DummyNilNode.new(code_range, lenv)
17
17
  else
18
18
  @body = nil
19
19
  end
20
20
 
21
- @cname_code_range = meta ? nil : TypeProf::CodeRange.from_node(raw_node.constant_path)
21
+ @cname_code_range = meta ? nil : lenv.code_range_from_node(raw_node.constant_path)
22
22
  @mod_cdef = nil
23
23
  end
24
24
 
@@ -89,7 +89,22 @@ module TypeProf::Core
89
89
  def initialize(raw_node, lenv, use_result)
90
90
  super(raw_node, lenv, raw_node.constant_path, false, raw_node.body, use_result)
91
91
  raw_superclass = raw_node.superclass
92
- @superclass_cpath = raw_superclass ? AST.create_node(raw_superclass, lenv) : nil
92
+ if raw_superclass
93
+ # In Ruby, the superclass expression is evaluated before the class constant
94
+ # is created. When the superclass is a bare constant with the same name as
95
+ # the class being defined (e.g., `class Foo < Foo` inside a module), use the
96
+ # outer scope to avoid resolving to the class itself.
97
+ if @static_cpath && lenv.cref.outer &&
98
+ raw_superclass.type == :constant_read_node &&
99
+ raw_superclass.name == @static_cpath.last
100
+ slenv = LocalEnv.new(lenv.file_context, lenv.cref.outer, {}, [])
101
+ @superclass_cpath = AST.create_node(raw_superclass, slenv)
102
+ else
103
+ @superclass_cpath = AST.create_node(raw_superclass, lenv)
104
+ end
105
+ else
106
+ @superclass_cpath = nil
107
+ end
93
108
  end
94
109
 
95
110
  attr_reader :superclass_cpath
@@ -113,6 +128,21 @@ module TypeProf::Core
113
128
 
114
129
  def install0(genv)
115
130
  @superclass_cpath.install(genv) if @superclass_cpath
131
+ if @static_cpath && @superclass_cpath
132
+ const_read = @superclass_cpath.static_ret
133
+ if const_read && const_read.cpath
134
+ super_mod = genv.resolve_cpath(const_read.cpath)
135
+ self_mod = genv.resolve_cpath(@static_cpath)
136
+ mod = super_mod
137
+ while mod
138
+ if mod == self_mod
139
+ @changes.add_diagnostic(:code_range, "circular inheritance", @superclass_cpath)
140
+ break
141
+ end
142
+ mod = mod.superclass
143
+ end
144
+ end
145
+ end
116
146
  super(genv)
117
147
  end
118
148
  end
@@ -15,20 +15,27 @@ module TypeProf::Core
15
15
  # TODO: decl.type_params
16
16
  # TODO: decl.super_class.args
17
17
  ncref = CRef.new(@cpath, :class, nil, lenv.cref)
18
- nlenv = LocalEnv.new(@lenv.path, ncref, {}, [])
18
+ nlenv = LocalEnv.new(@lenv.file_context, ncref, {}, [])
19
19
  @members = raw_decl.members.map do |member|
20
20
  AST.create_rbs_member(member, nlenv)
21
21
  end.compact
22
22
  # TODO?: param.variance, param.unchecked, param.upper_bound
23
23
  @params = raw_decl.type_params.map {|param| param.name }
24
+ @params_default_types = raw_decl.type_params.map do |param|
25
+ ty = param.default_type
26
+ ty ? AST.create_rbs_type(ty, lenv) : nil
27
+ end
24
28
  end
25
29
 
26
- attr_reader :cpath, :members, :params
30
+ attr_reader :cpath, :members, :params, :params_default_types
27
31
 
28
- def subnodes = { members: }
32
+ def subnodes = { members:, params_default_types: }
29
33
  def attrs = { cpath:, params: }
30
34
 
31
35
  def define0(genv)
36
+ @params_default_types.each do |ty|
37
+ ty&.define(genv)
38
+ end
32
39
  @members.each do |member|
33
40
  member.define(genv)
34
41
  end
@@ -46,6 +53,9 @@ module TypeProf::Core
46
53
  def undefine0(genv)
47
54
  mod = genv.resolve_cpath(@cpath)
48
55
  mod.remove_module_decl(genv, self)
56
+ @params_default_types.each do |ty|
57
+ ty&.undefine(genv)
58
+ end
49
59
  @members.each do |member|
50
60
  member.undefine(genv)
51
61
  end
@@ -180,19 +190,19 @@ module TypeProf::Core
180
190
  def initialize(raw_decl, lenv)
181
191
  super(raw_decl, lenv)
182
192
  @mid = raw_decl.name
183
- @mid_code_range = TypeProf::CodeRange.from_node(raw_decl.location[:name])
193
+ @mid_code_range = lenv.code_range_from_node(raw_decl.location[:name])
184
194
  @singleton = raw_decl.singleton?
185
195
  @instance = raw_decl.instance?
186
- @method_types = raw_decl.overloads.map do |overload|
196
+ @method_types = OverloadSet.new(raw_decl.overloads.map do |overload|
187
197
  method_type = overload.method_type
188
198
  AST.create_rbs_func_type(method_type, method_type.type_params, method_type.block, lenv)
189
- end
199
+ end)
190
200
  @overloading = raw_decl.overloading
191
201
  end
192
202
 
193
203
  attr_reader :mid, :singleton, :instance, :method_types, :overloading, :mid_code_range
194
204
 
195
- def subnodes = { method_types: }
205
+ def subnodes = { method_types: @method_types.to_a }
196
206
  def attrs = { mid:, mid_code_range:, singleton:, instance:, overloading: }
197
207
 
198
208
  def mname_code_range(_name) = @mid_code_range
@@ -222,10 +232,10 @@ module TypeProf::Core
222
232
  def define0(genv)
223
233
  @args.each {|arg| arg.define(genv) }
224
234
  const_reads = []
225
- const_read = BaseConstRead.new(genv, @cpath.first, @toplevel ? CRef::Toplevel : @lenv.cref, false)
235
+ const_read = BaseConstRead.new(genv, @cpath.first, @toplevel ? CRef::Toplevel : @lenv.cref, true)
226
236
  const_reads << const_read
227
237
  @cpath[1..].each do |cname|
228
- const_read = ScopedConstRead.new(cname, const_read, false)
238
+ const_read = ScopedConstRead.new(cname, const_read, true)
229
239
  const_reads << const_read
230
240
  end
231
241
  mod = genv.resolve_cpath(@lenv.cref.cpath)
@@ -271,10 +281,10 @@ module TypeProf::Core
271
281
  def define0(genv)
272
282
  @args.each {|arg| arg.define(genv) }
273
283
  const_reads = []
274
- const_read = BaseConstRead.new(genv, @cpath.first, @toplevel ? CRef::Toplevel : @lenv.cref, false)
284
+ const_read = BaseConstRead.new(genv, @cpath.first, @toplevel ? CRef::Toplevel : @lenv.cref, true)
275
285
  const_reads << const_read
276
286
  @cpath[1..].each do |cname|
277
- const_read = ScopedConstRead.new(cname, const_read, false)
287
+ const_read = ScopedConstRead.new(cname, const_read, true)
278
288
  const_reads << const_read
279
289
  end
280
290
  mod = genv.resolve_cpath(@lenv.cref.cpath)
@@ -336,6 +346,7 @@ module TypeProf::Core
336
346
  location: raw_decl.type.location
337
347
  )
338
348
  @method_type = AST.create_rbs_func_type(rbs_method_type, [], nil, lenv)
349
+ @method_types = OverloadSet.new([@method_type])
339
350
  end
340
351
 
341
352
  attr_reader :mid, :method_type
@@ -344,7 +355,7 @@ module TypeProf::Core
344
355
  def attrs = { mid: }
345
356
 
346
357
  def install0(genv)
347
- @changes.add_method_decl_box(genv, @lenv.cref.cpath, false, @mid, [@method_type], false)
358
+ @changes.add_method_decl_box(genv, @lenv.cref.cpath, false, @mid, @method_types, false)
348
359
  Source.new
349
360
  end
350
361
  end
@@ -371,6 +382,7 @@ module TypeProf::Core
371
382
  location: raw_decl.type.location
372
383
  )
373
384
  @method_type = AST.create_rbs_func_type(rbs_method_type, [], nil, lenv)
385
+ @method_types = OverloadSet.new([@method_type])
374
386
  end
375
387
 
376
388
  attr_reader :mid, :method_type
@@ -379,7 +391,7 @@ module TypeProf::Core
379
391
  def attrs = { mid: }
380
392
 
381
393
  def install0(genv)
382
- @changes.add_method_decl_box(genv, @lenv.cref.cpath, false, @mid, [@method_type], false)
394
+ @changes.add_method_decl_box(genv, @lenv.cref.cpath, false, @mid, @method_types, false)
383
395
  Source.new
384
396
  end
385
397
  end
@@ -402,6 +414,52 @@ module TypeProf::Core
402
414
  end
403
415
  end
404
416
 
417
+ class SigModuleAliasBaseNode < Node
418
+ def initialize(raw_decl, lenv)
419
+ super(raw_decl, lenv)
420
+ @cpath = AST.resolve_rbs_name(raw_decl.new_name, lenv)
421
+ @old_cpath = AST.resolve_rbs_name(raw_decl.old_name, lenv)
422
+ end
423
+
424
+ attr_reader :cpath, :old_cpath
425
+ def attrs = { cpath:, old_cpath: }
426
+
427
+ def define0(genv)
428
+ outer = genv.resolve_cpath(@cpath[0..-2])
429
+ cname = @cpath.last
430
+ alias_mod = outer.inner_modules[cname] ||= ModuleEntity.new(outer.cpath + [cname], outer)
431
+ target_mod = genv.resolve_cpath(@old_cpath)
432
+ alias_mod.add_alias_decl(genv, self, target_mod)
433
+ end
434
+
435
+ def define_copy(genv)
436
+ outer = genv.resolve_cpath(@cpath[0..-2])
437
+ alias_mod = outer.inner_modules[@cpath.last]
438
+ target_mod = genv.resolve_cpath(@old_cpath)
439
+ alias_mod.add_alias_decl(genv, self, target_mod)
440
+ alias_mod.remove_alias_decl(genv, @prev_node)
441
+ super(genv)
442
+ end
443
+
444
+ def undefine0(genv)
445
+ outer = genv.resolve_cpath(@cpath[0..-2])
446
+ alias_mod = outer.inner_modules[@cpath.last]
447
+ alias_mod.remove_alias_decl(genv, self)
448
+ end
449
+
450
+ def install0(genv)
451
+ mod_val = Source.new(Type::Singleton.new(genv, genv.resolve_cpath(@cpath)))
452
+ @changes.add_edge(genv, mod_val, @static_ret.vtx)
453
+ Source.new
454
+ end
455
+ end
456
+
457
+ class SigClassAliasNode < SigModuleAliasBaseNode
458
+ end
459
+
460
+ class SigModuleAliasNode < SigModuleAliasBaseNode
461
+ end
462
+
405
463
  class SigConstNode < Node
406
464
  def initialize(raw_decl, lenv)
407
465
  super(raw_decl, lenv)
@@ -415,9 +473,10 @@ module TypeProf::Core
415
473
 
416
474
  def define0(genv)
417
475
  @type.define(genv)
418
- mod = genv.resolve_const(@cpath)
419
- mod.add_decl(self)
420
- mod
476
+ cdef = genv.resolve_const(@cpath)
477
+ cdef.on_const_added(genv, @cpath)
478
+ cdef.add_decl(self)
479
+ cdef
421
480
  end
422
481
 
423
482
  def define_copy(genv)
@@ -428,7 +487,9 @@ module TypeProf::Core
428
487
  end
429
488
 
430
489
  def undefine0(genv)
431
- genv.resolve_const(@cpath).remove_decl(self)
490
+ cdef = genv.resolve_const(@cpath)
491
+ cdef.remove_decl(self)
492
+ cdef.on_const_removed(genv, @cpath)
432
493
  @type.undefine(genv)
433
494
  end
434
495
 
@@ -490,20 +551,20 @@ module TypeProf::Core
490
551
 
491
552
  def define0(genv)
492
553
  @type.define(genv)
493
- mod = genv.resolve_ivar(cpath, @class_scope, @var)
494
- mod.add_decl(self)
495
- mod
554
+ mod = genv.resolve_cpath(cpath)
555
+ mod.add_ivar_decl(genv, @class_scope, @var, self)
496
556
  end
497
557
 
498
558
  def define_copy(genv)
499
- mod = genv.resolve_ivar(cpath, @class_scope, @var)
500
- mod.add_decl(self)
501
- mod.remove_decl(@prev_node)
559
+ mod = genv.resolve_cpath(cpath)
560
+ mod.add_ivar_decl(genv, @class_scope, @var, self)
561
+ mod.remove_ivar_decl(genv, @class_scope, @var, @prev_node)
502
562
  super(genv)
503
563
  end
504
564
 
505
565
  def undefine0(genv)
506
- genv.resolve_ivar(cpath, @class_scope, @var).remove_decl(self)
566
+ mod = genv.resolve_cpath(cpath)
567
+ mod.remove_ivar_decl(genv, @class_scope, @var, self)
507
568
  @type.undefine(genv)
508
569
  end
509
570