typeprof 0.32.0 → 0.33.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.
@@ -256,9 +256,20 @@ module TypeProf::Core
256
256
  vtx = @expr.install(genv)
257
257
 
258
258
  a_args = ActualArguments.new([], [], nil, nil)
259
- to_a_vtx = @changes.add_method_call_box(genv, vtx, :to_a, a_args, false, suppress_errors: true).ret
260
-
261
- @changes.add_splat_box(genv, to_a_vtx, nil, vtx).ret
259
+ # Receiver types with no `to_a` are collected here, so that each union
260
+ # member can independently fall back to wrapping itself as `[x]`.
261
+ unresolved_recv = Vertex.new(self)
262
+ to_a_box = @changes.add_method_call_box(
263
+ genv,
264
+ vtx,
265
+ :to_a,
266
+ a_args,
267
+ false,
268
+ suppress_errors: true,
269
+ unresolved_recv: unresolved_recv,
270
+ )
271
+
272
+ @changes.add_splat_box(genv, to_a_box.ret, nil, unresolved_recv).ret
262
273
  end
263
274
  end
264
275
 
@@ -332,8 +343,7 @@ module TypeProf::Core
332
343
  def subnodes = { value:, pat: }
333
344
 
334
345
  def install0(genv)
335
- @value.install(genv)
336
- @pat.install(genv)
346
+ @pat.install_pattern(genv, @value.install(genv))
337
347
  Source.new(genv.nil_type)
338
348
  end
339
349
  end
@@ -350,8 +360,7 @@ module TypeProf::Core
350
360
  def subnodes = { value:, pat: }
351
361
 
352
362
  def install0(genv)
353
- @value.install(genv)
354
- @pat.install(genv)
363
+ @pat.install_pattern(genv, @value.install(genv))
355
364
  Source.new(genv.true_type, genv.false_type)
356
365
  end
357
366
  end
@@ -18,11 +18,15 @@ module TypeProf::Core
18
18
  @body = nil
19
19
  end
20
20
 
21
- @cname_code_range = meta ? nil : lenv.code_range_from_node(raw_node.constant_path)
21
+ @cname_code_range_loc = meta ? nil : raw_node.constant_path
22
22
  @mod_cdef = nil
23
23
  end
24
24
 
25
- attr_reader :tbl, :cpath, :static_cpath, :cname_code_range, :body
25
+ attr_reader :tbl, :cpath, :static_cpath, :body
26
+
27
+ def cname_code_range
28
+ @cname_code_range ||= @lenv.code_range_from_node(@cname_code_range_loc) if @cname_code_range_loc
29
+ end
26
30
 
27
31
  def subnodes = { cpath:, body: }
28
32
  def attrs = { static_cpath:, tbl: }
@@ -22,14 +22,19 @@ module TypeProf::Core
22
22
  def attrs = { rest: }
23
23
  def subnodes = { requireds:, rest_pattern:, posts: }
24
24
 
25
- def install0(genv)
26
- @requireds.each do |pat|
27
- pat.install(genv)
25
+ def install_pattern0(genv, subject)
26
+ @requireds.each_with_index do |pat, i|
27
+ pat.install_pattern(genv, @changes.add_splat_box(genv, subject, i).ret)
28
+ end
29
+ if @rest_pattern
30
+ elem = @changes.add_splat_box(genv, subject).ret
31
+ @rest_pattern.install_pattern(genv, Source.new(genv.gen_ary_type(elem)))
28
32
  end
29
- @rest_pattern.install(genv) if @rest_pattern
30
33
  @posts.each do |pat|
31
- pat.install(genv)
34
+ # TODO: precise indices for post elements (those after `*rest`)
35
+ pat.install_pattern(genv, @changes.add_splat_box(genv, subject).ret)
32
36
  end
37
+ subject
33
38
  end
34
39
  end
35
40
 
@@ -39,7 +44,14 @@ module TypeProf::Core
39
44
  @keys = raw_node.elements.map {|raw_assoc| raw_assoc.key.value.to_sym }
40
45
  @values = raw_node.elements.map {|raw_assoc| AST.create_pattern_node(raw_assoc.value, lenv) }
41
46
  @rest = !!raw_node.rest
42
- @rest_pattern = raw_node.rest && raw_node.rest.value ? AST.create_pattern_node(raw_node.rest.value, lenv) : nil
47
+ @rest_pattern = case raw_node.rest
48
+ when Prism::AssocSplatNode
49
+ AST.create_pattern_node(raw_node.rest.value, lenv) if raw_node.rest.value
50
+ when Prism::NoKeywordsParameterNode, nil
51
+ nil
52
+ else
53
+ raise
54
+ end
43
55
  end
44
56
 
45
57
  attr_reader :keys, :values, :rest, :rest_pattern
@@ -47,32 +59,37 @@ module TypeProf::Core
47
59
  def attrs = { keys:, rest: }
48
60
  def subnodes = { values:, rest_pattern: }
49
61
 
50
- def install0(genv)
62
+ def install_pattern0(genv, subject)
63
+ # TODO: extract each key's value type from `subject` (captures stay untyped for now)
51
64
  @values.each do |pat|
52
- pat.install(genv)
65
+ pat.install_pattern(genv, Vertex.new(self))
53
66
  end
54
- @rest_pattern.install(genv) if @rest_pattern
67
+ @rest_pattern.install_pattern(genv, Vertex.new(self)) if @rest_pattern
68
+ subject
55
69
  end
56
70
  end
57
71
 
58
72
  class FindPatternNode < Node
59
73
  def initialize(raw_node, lenv)
60
74
  super(raw_node, lenv)
61
- @left = raw_node.left ? AST.create_pattern_node(raw_node.left.expression, lenv) : nil
75
+ @left = raw_node.left.expression ? AST.create_pattern_node(raw_node.left.expression, lenv) : nil
62
76
  @requireds = raw_node.requireds.map {|raw_elem| AST.create_pattern_node(raw_elem, lenv) }
63
- @right = raw_node.right ? AST.create_pattern_node(raw_node.right.expression, lenv) : nil
77
+ @right = raw_node.right.expression ? AST.create_pattern_node(raw_node.right.expression, lenv) : nil
64
78
  end
65
79
 
66
80
  attr_reader :left, :requireds, :right
67
81
 
68
82
  def subnodes = { left:, requireds:, right: }
69
83
 
70
- def install0(genv)
71
- @left.install(genv) if @left
84
+ def install_pattern0(genv, subject)
85
+ elem = @changes.add_splat_box(genv, subject).ret
86
+ rest_ary = Source.new(genv.gen_ary_type(elem))
87
+ @left.install_pattern(genv, rest_ary) if @left
72
88
  @requireds.each do |pat|
73
- pat.install(genv)
89
+ pat.install_pattern(genv, elem)
74
90
  end
75
- @right.install(genv) if @right
91
+ @right.install_pattern(genv, rest_ary) if @right
92
+ subject
76
93
  end
77
94
  end
78
95
 
@@ -87,9 +104,10 @@ module TypeProf::Core
87
104
 
88
105
  def subnodes = { left:, right: }
89
106
 
90
- def install0(genv)
91
- @left.install(genv)
92
- @right.install(genv)
107
+ def install_pattern0(genv, subject)
108
+ @left.install_pattern(genv, subject)
109
+ @right.install_pattern(genv, subject)
110
+ subject
93
111
  end
94
112
  end
95
113
 
@@ -104,9 +122,18 @@ module TypeProf::Core
104
122
 
105
123
  def subnodes = { value:, target: }
106
124
 
107
- def install0(genv)
108
- @value.install(genv)
109
- @target.install(genv)
125
+ def install_pattern0(genv, subject)
126
+ @value.install_pattern(genv, subject)
127
+ # For `Const => var`, narrow the capture by the class, as `when Const` does
128
+ narrowed =
129
+ if @value.is_a?(ConstantReadNode) && @value.static_ret
130
+ filtered = subject.new_vertex(genv, self)
131
+ IsAFilter.new(genv, self, filtered, false, @value.static_ret).next_vtx
132
+ else
133
+ subject
134
+ end
135
+ @target.install_pattern(genv, narrowed)
136
+ subject
110
137
  end
111
138
  end
112
139
 
@@ -124,9 +151,10 @@ module TypeProf::Core
124
151
 
125
152
  def subnodes = { cond:, body: }
126
153
 
127
- def install0(genv)
154
+ def install_pattern0(genv, subject)
128
155
  @cond.install(genv)
129
- @body.install(genv)
156
+ @body.install_pattern(genv, subject)
157
+ subject
130
158
  end
131
159
  end
132
160
 
@@ -14,16 +14,20 @@ module TypeProf::Core
14
14
  @cpath = AST.resolve_rbs_name(raw_decl.name, lenv)
15
15
  # TODO: decl.type_params
16
16
  # TODO: decl.super_class.args
17
+ # TODO?: param.variance, param.unchecked, param.upper_bound
18
+ @params = raw_decl.type_params.map {|param| param.name }
19
+ sig_type_params = [@cpath, @params]
20
+ # The header (default types, self types, and superclass arguments) is
21
+ # resolved in the outer scope but may refer to the type parameters
22
+ @header_lenv = LocalEnv.new(@lenv.file_context, lenv.cref, {}, [], sig_type_params:)
17
23
  ncref = CRef.new(@cpath, :class, nil, lenv.cref)
18
- nlenv = LocalEnv.new(@lenv.file_context, ncref, {}, [])
24
+ nlenv = LocalEnv.new(@lenv.file_context, ncref, {}, [], sig_type_params:)
19
25
  @members = raw_decl.members.map do |member|
20
26
  AST.create_rbs_member(member, nlenv)
21
27
  end.compact
22
- # TODO?: param.variance, param.unchecked, param.upper_bound
23
- @params = raw_decl.type_params.map {|param| param.name }
24
28
  @params_default_types = raw_decl.type_params.map do |param|
25
29
  ty = param.default_type
26
- ty ? AST.create_rbs_type(ty, lenv) : nil
30
+ ty ? AST.create_rbs_type(ty, @header_lenv) : nil
27
31
  end
28
32
  end
29
33
 
@@ -81,7 +85,7 @@ module TypeProf::Core
81
85
  cpath = name.namespace.path + [self_type.name.name]
82
86
  toplevel = name.namespace.absolute?
83
87
  @self_types << [cpath, toplevel]
84
- @self_type_args << self_type.args.map {|arg| AST.create_rbs_type(arg, lenv) }
88
+ @self_type_args << self_type.args.map {|arg| AST.create_rbs_type(arg, @header_lenv) }
85
89
  end
86
90
  end
87
91
 
@@ -138,7 +142,7 @@ module TypeProf::Core
138
142
  name = superclass.name
139
143
  @superclass_cpath = name.namespace.path + [name.name]
140
144
  @superclass_toplevel = name.namespace.absolute?
141
- @superclass_args = superclass.args.map {|arg| AST.create_rbs_type(arg, lenv) }
145
+ @superclass_args = superclass.args.map {|arg| AST.create_rbs_type(arg, @header_lenv) }
142
146
  else
143
147
  @superclass_cpath = nil
144
148
  @superclass_toplevel = nil
@@ -190,7 +194,7 @@ module TypeProf::Core
190
194
  def initialize(raw_decl, lenv)
191
195
  super(raw_decl, lenv)
192
196
  @mid = raw_decl.name
193
- @mid_code_range = lenv.code_range_from_node(raw_decl.location[:name])
197
+ @mid_code_range_loc = raw_decl.location[:name]
194
198
  @singleton = raw_decl.singleton?
195
199
  @instance = raw_decl.instance?
196
200
  @method_types = OverloadSet.new(raw_decl.overloads.map do |overload|
@@ -200,12 +204,16 @@ module TypeProf::Core
200
204
  @overloading = raw_decl.overloading
201
205
  end
202
206
 
203
- attr_reader :mid, :singleton, :instance, :method_types, :overloading, :mid_code_range
207
+ attr_reader :mid, :singleton, :instance, :method_types, :overloading
208
+
209
+ def mid_code_range
210
+ @mid_code_range ||= @lenv.code_range_from_node(@mid_code_range_loc) if @mid_code_range_loc
211
+ end
204
212
 
205
213
  def subnodes = { method_types: @method_types.to_a }
206
- def attrs = { mid:, mid_code_range:, singleton:, instance:, overloading: }
214
+ def attrs = { mid:, singleton:, instance:, overloading: }
207
215
 
208
- def mname_code_range(_name) = @mid_code_range
216
+ def mname_code_range(_name) = mid_code_range
209
217
 
210
218
  def install0(genv)
211
219
  [[@singleton, true], [@instance, false]].each do |enabled, singleton|
@@ -314,6 +322,55 @@ module TypeProf::Core
314
322
  end
315
323
  end
316
324
 
325
+ class SigExtendNode < Node
326
+ def initialize(raw_decl, lenv)
327
+ super(raw_decl, lenv)
328
+ name = raw_decl.name
329
+ @cpath = name.namespace.path + [name.name]
330
+ @toplevel = name.namespace.absolute?
331
+ @args = raw_decl.args.map {|arg| AST.create_rbs_type(arg, lenv) }
332
+ end
333
+
334
+ attr_reader :cpath, :toplevel, :args
335
+ def subnodes = { args: }
336
+ def attrs = { cpath:, toplevel: }
337
+
338
+ def define0(genv)
339
+ @args.each {|arg| arg.define(genv) }
340
+ const_reads = []
341
+ const_read = BaseConstRead.new(genv, @cpath.first, @toplevel ? CRef::Toplevel : @lenv.cref, true)
342
+ const_reads << const_read
343
+ @cpath[1..].each do |cname|
344
+ const_read = ScopedConstRead.new(cname, const_read, true)
345
+ const_reads << const_read
346
+ end
347
+ mod = genv.resolve_cpath(@lenv.cref.cpath)
348
+ const_read.followers << mod
349
+ mod.add_extend_decl(genv, self)
350
+ const_reads
351
+ end
352
+
353
+ def define_copy(genv)
354
+ mod = genv.resolve_cpath(@lenv.cref.cpath)
355
+ mod.add_extend_decl(genv, self)
356
+ mod.remove_extend_decl(genv, @prev_node)
357
+ super(genv)
358
+ end
359
+
360
+ def undefine0(genv)
361
+ mod = genv.resolve_cpath(@lenv.cref.cpath)
362
+ mod.remove_extend_decl(genv, self)
363
+ @static_ret.each do |const_read|
364
+ const_read.destroy(genv)
365
+ end
366
+ @args.each {|arg| arg.undefine(genv) }
367
+ end
368
+
369
+ def install0(genv)
370
+ Source.new
371
+ end
372
+ end
373
+
317
374
  class SigAliasNode < Node
318
375
  def initialize(raw_decl, lenv)
319
376
  super(raw_decl, lenv)
@@ -23,6 +23,9 @@ module TypeProf::Core
23
23
  if f_mod.module?
24
24
  return true if typecheck_for_prepended_modules(genv, changes, ty, f_mod, f_args, subst)
25
25
  return true if typecheck_for_included_modules(genv, changes, ty, f_mod, f_args, subst)
26
+ if ty.is_a?(Type::Singleton)
27
+ return true if typecheck_for_extended_modules(genv, changes, ty, f_mod, f_args, subst)
28
+ end
26
29
  end
27
30
 
28
31
  ty = genv.get_superclass_type(ty, changes, {})
@@ -81,6 +84,32 @@ module TypeProf::Core
81
84
  return false
82
85
  end
83
86
 
87
+ def self.typecheck_for_extended_modules(genv, changes, a_ty, f_mod, f_args, subst)
88
+ a_ty.mod.extended_modules.each do |ext_decl, ext_mod|
89
+ if ext_decl.is_a?(AST::SigExtendNode) && ext_mod.type_params
90
+ ext_ty = genv.get_instance_type(ext_mod, ext_decl.args, changes, {}, a_ty)
91
+ else
92
+ type_params = ext_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
93
+ ext_ty = Type::Instance.new(genv, ext_mod, type_params)
94
+ end
95
+ if ext_ty.mod == f_mod
96
+ args_all_match = true
97
+ f_args.zip(ext_ty.args) do |f_arg_node, a_arg_vtx|
98
+ unless f_arg_node.typecheck(genv, changes, a_arg_vtx, subst)
99
+ args_all_match = false
100
+ break
101
+ end
102
+ end
103
+ return true if args_all_match
104
+ end
105
+ changes.add_depended_superclass(ext_ty.mod)
106
+
107
+ # The extended module may itself include other modules
108
+ return true if typecheck_for_included_modules(genv, changes, ext_ty, f_mod, f_args, subst)
109
+ end
110
+ return false
111
+ end
112
+
84
113
  class SigFuncType < Node
85
114
  def initialize(raw_decl, raw_type_params, raw_block, lenv)
86
115
  super(raw_decl, lenv)
@@ -465,7 +494,13 @@ module TypeProf::Core
465
494
  decl = tae.decls.each {|decl| break decl }
466
495
  subst0 = subst.dup
467
496
  decl.params.zip(@args) do |param, arg|
468
- subst0[param] = arg.covariant_vertex(genv, changes, subst0)
497
+ if arg.is_a?(SigTyVarNode) && subst[arg.var]
498
+ # Share the vertex so that the types inferred in the alias body flow
499
+ # back into the variable, which makes `U` of `(array[U])` inferrable
500
+ subst0[param] = subst[arg.var]
501
+ else
502
+ subst0[param] = arg.covariant_vertex(genv, changes, subst0)
503
+ end
469
504
  end
470
505
  tae.type.typecheck(genv, changes, vtx, subst0)
471
506
  end
@@ -848,18 +883,32 @@ module TypeProf::Core
848
883
 
849
884
  def attrs = { var: }
850
885
 
886
+ # A reopened declaration may rename the type parameters (e.g., `Enumerable[E]`
887
+ # and `Enumerable[Elem]`), but the subst is keyed by the names of the module
888
+ # entity, so fall back to matching them by position
889
+ def resolve_var(genv, subst)
890
+ decl_cpath, decl_params = @lenv.sig_type_params
891
+ return subst[@var] unless decl_params
892
+ idx = decl_params.index(@var)
893
+ return subst[@var] unless idx
894
+ subst[genv.resolve_cpath(decl_cpath).type_params.keys[idx]]
895
+ end
896
+
851
897
  def covariant_vertex0(genv, changes, vtx, subst)
852
- raise "unknown type variable: #{ @var }" unless subst[@var]
853
- changes.add_edge(genv, subst[@var], vtx)
898
+ var_vtx = resolve_var(genv, subst)
899
+ raise "unknown type variable: #{ @var }" unless var_vtx
900
+ changes.add_edge(genv, var_vtx, vtx)
854
901
  end
855
902
 
856
903
  def contravariant_vertex0(genv, changes, vtx, subst)
857
- raise "unknown type variable: #{ @var }" unless subst[@var]
858
- changes.add_edge(genv, Source.new(Type::Var.new(genv, @var, subst[@var])), vtx)
904
+ var_vtx = resolve_var(genv, subst)
905
+ raise "unknown type variable: #{ @var }" unless var_vtx
906
+ changes.add_edge(genv, Source.new(Type::Var.new(genv, @var, var_vtx)), vtx)
859
907
  end
860
908
 
861
909
  def typecheck(genv, changes, vtx, subst)
862
- changes.add_edge(genv, vtx.new_vertex(genv, self), subst[@var]) unless vtx == subst[@var]
910
+ var_vtx = resolve_var(genv, subst)
911
+ changes.add_edge(genv, vtx.new_vertex(genv, self), var_vtx) unless vtx == var_vtx
863
912
  true
864
913
  end
865
914
 
@@ -63,6 +63,12 @@ module TypeProf::Core
63
63
  val
64
64
  end
65
65
 
66
+ def install_pattern0(genv, subject)
67
+ install0(genv)
68
+ @changes.add_edge(genv, subject, @rhs.ret)
69
+ subject
70
+ end
71
+
66
72
  def retrieve_at(pos, &blk)
67
73
  yield self if @var_code_range && @var_code_range.include?(pos)
68
74
  super(pos, &blk)
@@ -1,14 +1,24 @@
1
1
  module TypeProf::Core
2
2
  class AST
3
3
  def self.parse_rb(path, src, position_encoding)
4
- result = Prism.parse(src)
4
+ build_rb(path, Prism.parse(src), position_encoding)
5
+ end
6
+
7
+ # This needs the comments and the Prism::Source, which a ParseResult has but a
8
+ # node does not.
9
+ def self.build_rb(path, result, position_encoding)
10
+ unless result.is_a?(Prism::ParseResult)
11
+ raise ArgumentError, "expected Prism::ParseResult, got #{ result.class }"
12
+ end
5
13
 
6
14
  return nil unless result.errors.empty?
7
15
 
8
16
  # comments, errors, magic_comments
9
17
  raw_scope = result.value
10
18
 
11
- raise unless raw_scope.type == :program_node
19
+ unless raw_scope.is_a?(Prism::ProgramNode)
20
+ raise ArgumentError, "expected Prism::ProgramNode, got #{ raw_scope.class }"
21
+ end
12
22
 
13
23
  prism_source = result.source
14
24
  file_context = FileContext.new(path, position_encoding, prism_source, result.comments)
@@ -283,6 +293,8 @@ module TypeProf::Core
283
293
  case raw_node.name
284
294
  when :include
285
295
  return IncludeMetaNode.new(raw_node, lenv)
296
+ when :extend
297
+ return ExtendMetaNode.new(raw_node, lenv)
286
298
  when :attr_reader
287
299
  return AttrReaderMetaNode.new(raw_node, lenv)
288
300
  when :attr_writer
@@ -460,6 +472,7 @@ module TypeProf::Core
460
472
  when RBS::AST::Members::Prepend
461
473
  SigPrependNode.new(raw_decl, lenv)
462
474
  when RBS::AST::Members::Extend
475
+ SigExtendNode.new(raw_decl, lenv)
463
476
  when RBS::AST::Members::Public
464
477
  when RBS::AST::Members::Private
465
478
  when RBS::AST::Members::Alias