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.
@@ -48,10 +48,33 @@ module TypeProf::Core
48
48
  @positionals + [@keywords],
49
49
  @splat_flags + [false],
50
50
  nil,
51
- @block
51
+ @block,
52
52
  )
53
53
  end
54
54
 
55
+ def prepend_positionals(positionals, splat_flags)
56
+ return self if positionals.empty?
57
+
58
+ ActualArguments.new(positionals + @positionals, splat_flags + @splat_flags, @keywords, @block)
59
+ end
60
+
61
+ def with_keywords(keywords)
62
+ ActualArguments.new(@positionals, @splat_flags, keywords, @block)
63
+ end
64
+
65
+ def with_block(block, omittable: false)
66
+ ActualArguments.new(@positionals, @splat_flags, @keywords, block)
67
+ end
68
+
69
+ def add_box_edges(genv, box)
70
+ @keywords.add_edge(genv, box) if @keywords
71
+ @block.add_edge(genv, box) if @block
72
+ end
73
+
74
+ def normalize_for_method_call(_genv)
75
+ self
76
+ end
77
+
55
78
  def get_rest_args(genv, changes, start_rest, end_rest)
56
79
  vtxs = []
57
80
 
@@ -95,45 +118,175 @@ module TypeProf::Core
95
118
  end
96
119
  end
97
120
 
121
+ class ForwardingActualArguments < ActualArguments
122
+ def initialize(positionals, splat_flags, keywords, block, positionals_omittable, keywords_omittable, block_omittable, activation, activation_required)
123
+ super(positionals, splat_flags, keywords, block)
124
+ @positionals_omittable = positionals_omittable
125
+ @keywords_omittable = keywords_omittable
126
+ @block_omittable = block_omittable
127
+ @activation = activation
128
+ @activation_required = activation_required
129
+ end
130
+
131
+ attr_reader :positionals_omittable, :keywords_omittable, :block_omittable
132
+
133
+ def new_vertexes(genv, node)
134
+ positionals = @positionals.map {|arg| arg.new_vertex(genv, node) }
135
+ splat_flags = @splat_flags
136
+ keywords = @keywords ? @keywords.new_vertex(genv, node) : nil
137
+ block = @block ? @block.new_vertex(genv, node) : nil
138
+ activation = @activation.new_vertex(genv, node)
139
+ ForwardingActualArguments.new(positionals, splat_flags, keywords, block, @positionals_omittable, @keywords_omittable, @block_omittable, activation, @activation_required)
140
+ end
141
+
142
+ def with_keywords_as_last_positional_hash
143
+ return self unless @keywords
144
+
145
+ ForwardingActualArguments.new(
146
+ @positionals + [@keywords],
147
+ @splat_flags + [false],
148
+ nil,
149
+ @block,
150
+ @positionals_omittable + [false],
151
+ false,
152
+ @block_omittable,
153
+ @activation,
154
+ @activation_required,
155
+ )
156
+ end
157
+
158
+ def prepend_positionals(positionals, splat_flags)
159
+ return self if positionals.empty?
160
+
161
+ ForwardingActualArguments.new(
162
+ positionals + @positionals,
163
+ splat_flags + @splat_flags,
164
+ @keywords,
165
+ @block,
166
+ ::Array.new(positionals.size, false) + @positionals_omittable,
167
+ @keywords_omittable,
168
+ @block_omittable,
169
+ @activation,
170
+ @activation_required,
171
+ )
172
+ end
173
+
174
+ def with_keywords(keywords, keywords_omittable: false)
175
+ ForwardingActualArguments.new(
176
+ @positionals,
177
+ @splat_flags,
178
+ keywords,
179
+ @block,
180
+ @positionals_omittable,
181
+ keywords_omittable,
182
+ @block_omittable,
183
+ @activation,
184
+ @activation_required,
185
+ )
186
+ end
187
+
188
+ def with_block(block, omittable: false)
189
+ ForwardingActualArguments.new(
190
+ @positionals,
191
+ @splat_flags,
192
+ @keywords,
193
+ block,
194
+ @positionals_omittable,
195
+ @keywords_omittable,
196
+ omittable,
197
+ @activation,
198
+ @activation_required,
199
+ )
200
+ end
201
+
202
+ def add_box_edges(genv, box)
203
+ @activation.add_edge(genv, box)
204
+ super
205
+ end
206
+
207
+ def normalize_for_method_call(genv)
208
+ if @activation.types.empty?
209
+ return nil if @activation_required
210
+ return self
211
+ end
212
+
213
+ positionals = []
214
+ splat_flags = []
215
+
216
+ @positionals.each_with_index do |arg, i|
217
+ unless @positionals_omittable[i] && @splat_flags[i] && empty_omittable_splat_argument?(genv, arg)
218
+ positionals << arg
219
+ splat_flags << @splat_flags[i]
220
+ end
221
+ end
222
+
223
+ keywords = @keywords
224
+ keywords = nil if @keywords_omittable && keywords && keywords.types.empty?
225
+
226
+ block = @block
227
+ block = nil if @block_omittable && block && block.types.empty?
228
+
229
+ ActualArguments.new(positionals, splat_flags, keywords, block)
230
+ end
231
+
232
+ private
233
+
234
+ def empty_omittable_splat_argument?(genv, arg)
235
+ empty = true
236
+ arg.each_type do |ty|
237
+ ty = ty.base_type(genv)
238
+ unless ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0] && ty.args[0].types.empty?
239
+ empty = false
240
+ break
241
+ end
242
+ end
243
+ empty
244
+ end
245
+ end
246
+
98
247
  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)
248
+ def initialize(req_positionals, opt_positionals, rest_positionals, post_positionals, req_keyword_pairs, opt_keyword_pairs, rest_keywords, block, activation)
100
249
  @req_positionals = req_positionals
101
250
  @opt_positionals = opt_positionals
102
- @opt_positional_elems = opt_positional_elems
103
251
  @rest_positionals = rest_positionals
104
252
  @post_positionals = post_positionals
105
253
  @req_keyword_pairs = req_keyword_pairs
106
254
  @opt_keyword_pairs = opt_keyword_pairs
107
255
  @rest_keywords = rest_keywords
108
256
  @block = block
257
+ @activation = activation
109
258
  end
110
259
 
111
- attr_reader :block
112
-
113
- def to_actual_arguments(genv, changes, node)
114
- positionals = @req_positionals.dup
260
+ def to_actual_arguments(genv, changes, node, include_leading_positionals: true, activation_required: false)
261
+ positionals = include_leading_positionals ? @req_positionals.dup : []
115
262
  splat_flags = ::Array.new(positionals.size, false)
263
+ positionals_omittable = ::Array.new(positionals.size, false)
116
264
 
117
- @opt_positionals.each do |arg|
118
- positionals << arg
265
+ @opt_positionals.each do |elem_vtx|
266
+ positionals << Source.new(genv.gen_ary_type(elem_vtx))
119
267
  splat_flags << true
268
+ positionals_omittable << true
120
269
  end
121
270
 
122
271
  if @rest_positionals
123
- positionals << @rest_positionals
272
+ positionals << Source.new(genv.gen_ary_type(@rest_positionals))
124
273
  splat_flags << true
274
+ positionals_omittable << true
125
275
  end
126
276
 
127
277
  @post_positionals.each do |arg|
128
278
  positionals << arg
129
279
  splat_flags << false
280
+ positionals_omittable << false
130
281
  end
131
282
 
132
- keywords = build_keyword_args(genv, changes, node)
133
- ActualArguments.new(positionals, splat_flags, keywords, @block)
283
+ keywords, keywords_omittable = build_keyword_args(genv, changes, node)
284
+ ForwardingActualArguments.new(positionals, splat_flags, keywords, @block, positionals_omittable, keywords_omittable, true, @activation, activation_required)
134
285
  end
135
286
 
136
287
  def accept_actual_arguments(genv, changes, a_args)
288
+ changes.add_edge(genv, Source.new(genv.true_type), @activation)
289
+
137
290
  if a_args.splat_flags.any?
138
291
  start_rest = [a_args.splat_flags.index(true), @req_positionals.size + @opt_positionals.size].min
139
292
  end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @post_positionals.size].max
@@ -149,7 +302,7 @@ module TypeProf::Core
149
302
  end
150
303
  end
151
304
 
152
- @opt_positional_elems.each_with_index do |elem_vtx, i|
305
+ @opt_positionals.each_with_index do |elem_vtx, i|
153
306
  i += @req_positionals.size
154
307
  if i < start_rest
155
308
  changes.add_edge(genv, a_args.positionals[i], elem_vtx)
@@ -171,6 +324,12 @@ module TypeProf::Core
171
324
  end
172
325
  end
173
326
 
327
+ if @rest_positionals
328
+ rest_vtxs.each do |vtx|
329
+ changes.add_edge(genv, vtx, @rest_positionals)
330
+ end
331
+ end
332
+
174
333
  else
175
334
  @req_positionals.each_with_index do |f_vtx, i|
176
335
  changes.add_edge(genv, a_args.positionals[i], f_vtx)
@@ -184,11 +343,17 @@ module TypeProf::Core
184
343
  start_rest = @req_positionals.size
185
344
  end_rest = a_args.positionals.size - @post_positionals.size
186
345
  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])
346
+ while i < @opt_positionals.size && start_rest < end_rest
347
+ changes.add_edge(genv, a_args.positionals[start_rest], @opt_positionals[i])
189
348
  i += 1
190
349
  start_rest += 1
191
350
  end
351
+
352
+ if @rest_positionals
353
+ start_rest.upto(end_rest - 1) do |i|
354
+ changes.add_edge(genv, a_args.positionals[i], @rest_positionals)
355
+ end
356
+ end
192
357
  end
193
358
 
194
359
  changes.add_edge(genv, a_args.block, @block) if @block && a_args.block
@@ -222,8 +387,11 @@ module TypeProf::Core
222
387
  private
223
388
 
224
389
  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?
390
+ opt_keyword_pairs = @opt_keyword_pairs
391
+
392
+ if @req_keyword_pairs.empty? && opt_keyword_pairs.empty?
393
+ return @rest_keywords, !!@rest_keywords
394
+ end
227
395
 
228
396
  unified_key = Vertex.new(node)
229
397
  unified_val = Vertex.new(node)
@@ -235,18 +403,22 @@ module TypeProf::Core
235
403
  literal_pairs[name] = vtx
236
404
  end
237
405
 
238
- @opt_keyword_pairs.each do |name, vtx|
406
+ opt_keyword_pairs.each do |name, vtx|
239
407
  changes.add_edge(genv, Source.new(Type::Symbol.new(genv, name)), unified_key)
240
408
  changes.add_edge(genv, vtx, unified_val)
409
+ literal_pairs[name] = vtx
241
410
  end
242
411
 
243
412
  base_hash_type = genv.gen_hash_type(unified_key, unified_val)
244
413
  changes.add_hash_splat_box(genv, @rest_keywords, unified_key, unified_val) if @rest_keywords
245
414
 
246
415
  if literal_pairs.empty?
247
- Source.new(base_hash_type)
416
+ [Source.new(base_hash_type), false]
417
+ elsif @rest_keywords
418
+ fallback = Source.new(Type::Record.new(genv, literal_pairs, base_hash_type))
419
+ [changes.add_keyword_merge_box(genv, @rest_keywords, literal_pairs, fallback).ret, false]
248
420
  else
249
- Source.new(Type::Record.new(genv, literal_pairs, base_hash_type))
421
+ [Source.new(Type::Record.new(genv, literal_pairs, base_hash_type)), false]
250
422
  end
251
423
  end
252
424
  end
@@ -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
- return [] # inherits from Object (Struct < Object)
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|
@@ -80,7 +80,7 @@ module TypeProf::Core
80
80
  # TODO: prepended modules
81
81
  yield mod, singleton
82
82
  if singleton
83
- # TODO: extended modules
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
@@ -352,7 +364,7 @@ module TypeProf::Core
352
364
  end
353
365
 
354
366
  class LocalEnv
355
- def initialize(file_context, cref, locals, return_boxes, forward_args = nil)
367
+ def initialize(file_context, cref, locals, return_boxes, forward_args = nil, sig_type_params: nil)
356
368
  @file_context = file_context
357
369
  @cref = cref
358
370
  @locals = locals
@@ -362,9 +374,11 @@ module TypeProf::Core
362
374
  @ivar_narrowings = {}
363
375
  @strict_const_scope = false
364
376
  @forward_args = forward_args
377
+ # [cpath, names] of the type parameters of the enclosing RBS declaration
378
+ @sig_type_params = sig_type_params
365
379
  end
366
380
 
367
- attr_reader :file_context, :cref, :locals, :return_boxes, :break_vtx, :next_boxes, :strict_const_scope
381
+ attr_reader :file_context, :cref, :locals, :return_boxes, :break_vtx, :next_boxes, :strict_const_scope, :sig_type_params
368
382
  attr_accessor :module_function, :forward_args
369
383
 
370
384
  def path = @file_context&.path