rigortype 0.0.4 → 0.0.6

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +215 -134
  3. data/data/builtins/ruby_core/comparable.yml +87 -0
  4. data/data/builtins/ruby_core/complex.yml +505 -0
  5. data/data/builtins/ruby_core/date.yml +1737 -0
  6. data/data/builtins/ruby_core/enumerable.yml +557 -0
  7. data/data/builtins/ruby_core/file.yml +9 -0
  8. data/data/builtins/ruby_core/pathname.yml +1067 -0
  9. data/data/builtins/ruby_core/rational.yml +365 -0
  10. data/data/builtins/ruby_core/string.yml +9 -0
  11. data/data/builtins/ruby_core/time.yml +6 -4
  12. data/lib/rigor/cli.rb +1 -1
  13. data/lib/rigor/inference/builtins/comparable_catalog.rb +27 -0
  14. data/lib/rigor/inference/builtins/complex_catalog.rb +41 -0
  15. data/lib/rigor/inference/builtins/date_catalog.rb +98 -0
  16. data/lib/rigor/inference/builtins/enumerable_catalog.rb +27 -0
  17. data/lib/rigor/inference/builtins/pathname_catalog.rb +35 -0
  18. data/lib/rigor/inference/builtins/rational_catalog.rb +38 -0
  19. data/lib/rigor/inference/expression_typer.rb +285 -23
  20. data/lib/rigor/inference/method_dispatcher/block_folding.rb +322 -0
  21. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +197 -12
  22. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +99 -0
  23. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +95 -0
  24. data/lib/rigor/inference/method_dispatcher.rb +20 -8
  25. data/lib/rigor/inference/narrowing.rb +210 -1
  26. data/lib/rigor/inference/scope_indexer.rb +87 -11
  27. data/lib/rigor/inference/statement_evaluator.rb +5 -1
  28. data/lib/rigor/rbs_extended.rb +11 -6
  29. data/lib/rigor/type/integer_range.rb +4 -2
  30. data/lib/rigor/version.rb +1 -1
  31. data/sig/rigor/environment.rbs +4 -6
  32. data/sig/rigor/inference.rbs +2 -1
  33. data/sig/rigor/type.rbs +41 -41
  34. metadata +15 -1
@@ -241,6 +241,55 @@ module Rigor
241
241
  narrow_class_dispatch(type, class_name, context)
242
242
  end
243
243
 
244
+ # Negation pair for `assert_value is ~refinement` /
245
+ # `predicate-if-* … is ~refinement` directives. Computes
246
+ # the complement of `refinement` within the current
247
+ # local's domain `current_type`.
248
+ #
249
+ # Carrier-by-carrier rules:
250
+ #
251
+ # - `Difference[base, Constant[v]]`. Complement of
252
+ # `base \ {v}` within `current_type`. Walk the current
253
+ # type's union members, keep each part disjoint from
254
+ # `base`, and add the removed-value Constant once when
255
+ # any current member covers it. `assert s is
256
+ # ~non-empty-string` over `s: String | nil` narrows to
257
+ # `Constant[""] | NilClass`.
258
+ # - `IntegerRange[a, b]` (v0.0.5+ slice). Complement is
259
+ # the two open halves `int<min, a-1>` and
260
+ # `int<b+1, max>`, each intersected with the
261
+ # integer-domain parts of `current_type`. Non-integer
262
+ # parts (nil, String, …) of a Union receiver survive
263
+ # unchanged. `assert n is ~int<5, 10>` over `n:
264
+ # Integer | nil` narrows to `int<min, 4> | int<11,
265
+ # max> | NilClass`.
266
+ # - `Type::Intersection[M1, M2, …]` (v0.0.5+ slice). De
267
+ # Morgan: `D \ (M1 ∩ M2) = (D \ M1) ∪ (D \ M2)`. Each
268
+ # member's complement is computed independently within
269
+ # `current_type` and the results are unioned. Members
270
+ # the algebra cannot complement (Refined, non-Constant
271
+ # Difference, …) contribute `current_type` itself, so
272
+ # the union widens the answer to `current_type` —
273
+ # sound but imprecise.
274
+ # - `Refined[base, predicate]`. Predicate complements are
275
+ # not reducible to a finite carrier without a richer
276
+ # shape (e.g. `~lowercase-string` is "uppercase OR
277
+ # mixed-case"); `current_type` is returned unchanged.
278
+ def narrow_not_refinement(current_type, refinement_type)
279
+ case refinement_type
280
+ when Type::Difference
281
+ return current_type unless refinement_type.removed.is_a?(Type::Constant)
282
+
283
+ complement_difference(current_type, refinement_type)
284
+ when Type::IntegerRange
285
+ complement_integer_range(current_type, refinement_type)
286
+ when Type::Intersection
287
+ complement_intersection(current_type, refinement_type)
288
+ else
289
+ current_type
290
+ end
291
+ end
292
+
244
293
  # Public predicate analyser. Returns `[truthy_scope, falsey_scope]`,
245
294
  # always; when no narrowing rule matches the predicate node both
246
295
  # entries are the receiver scope unchanged.
@@ -321,6 +370,162 @@ module Rigor
321
370
  class << self
322
371
  private
323
372
 
373
+ # Complement of `Difference[base, Constant[v]]` within
374
+ # `current_type`. Walks the current type's union members,
375
+ # keeps each member disjoint from `base` (those values
376
+ # were never in the refinement to begin with), and adds
377
+ # the removed-value `Constant[v]` exactly once when any
378
+ # current member covers it. Members that are fully
379
+ # contained in the refinement (i.e. inside `base` and
380
+ # NOT equal to the removed value) are dropped — they are
381
+ # exactly the values the negation excludes.
382
+ def complement_difference(current_type, difference)
383
+ base = difference.base
384
+ removed = difference.removed
385
+ parts = current_type.is_a?(Type::Union) ? current_type.members : [current_type]
386
+
387
+ survivors = []
388
+ add_removed = false
389
+ parts.each do |part|
390
+ if base_disjoint?(base, part)
391
+ survivors << part
392
+ elsif part_covers_constant?(part, removed)
393
+ add_removed = true
394
+ end
395
+ end
396
+ survivors << removed if add_removed
397
+
398
+ return current_type if survivors.empty?
399
+
400
+ Type::Combinator.union(*survivors)
401
+ end
402
+
403
+ def base_disjoint?(base, part)
404
+ base.accepts(part, mode: :gradual).no?
405
+ end
406
+
407
+ def part_covers_constant?(part, constant)
408
+ result = part.accepts(constant, mode: :gradual)
409
+ result.yes? || result.maybe?
410
+ end
411
+
412
+ # Complement of an `IntegerRange[a, b]` within
413
+ # `current_type`. Splits the range complement into the
414
+ # two open halves `int<min, a-1>` and `int<b+1, max>`
415
+ # (skipping a half when its bound is infinity), then
416
+ # intersects each half with the integer-domain parts of
417
+ # `current_type`. Non-integer parts of a Union receiver
418
+ # (nil, String, …) survive unchanged.
419
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
420
+ def complement_integer_range(current_type, range)
421
+ halves = integer_range_complement_halves(range)
422
+ parts = current_type.is_a?(Type::Union) ? current_type.members : [current_type]
423
+
424
+ survivors = []
425
+ parts.each do |part|
426
+ if integer_member?(part)
427
+ halves.each do |half|
428
+ meet = intersect_integer_part(part, half)
429
+ survivors << meet unless meet.nil? || meet.is_a?(Type::Bot)
430
+ end
431
+ else
432
+ survivors << part
433
+ end
434
+ end
435
+
436
+ return current_type if survivors.empty?
437
+
438
+ Type::Combinator.union(*survivors)
439
+ end
440
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
441
+
442
+ # Returns the two open halves of an IntegerRange's
443
+ # complement: the left half `int<-∞, a-1>` (when `a` is
444
+ # finite) and the right half `int<b+1, ∞>` (when `b` is
445
+ # finite). Universal ranges (both bounds infinite) yield
446
+ # an empty array — the complement is empty.
447
+ def integer_range_complement_halves(range)
448
+ halves = []
449
+ left_max = range.min
450
+ right_min = range.max
451
+
452
+ if left_max.is_a?(Integer)
453
+ halves << Type::Combinator.integer_range(Type::IntegerRange::NEG_INFINITY, left_max - 1)
454
+ end
455
+ if right_min.is_a?(Integer)
456
+ halves << Type::Combinator.integer_range(right_min + 1, Type::IntegerRange::POS_INFINITY)
457
+ end
458
+ halves
459
+ end
460
+
461
+ def integer_member?(part)
462
+ case part
463
+ when Type::Constant then part.value.is_a?(Integer)
464
+ when Type::IntegerRange then true
465
+ when Type::Nominal then part.class_name == "Integer"
466
+ else false
467
+ end
468
+ end
469
+
470
+ # Intersect an integer-domain part with a complement
471
+ # half-range. For a Nominal[Integer] receiver the meet
472
+ # is the half itself; for an existing IntegerRange the
473
+ # meet narrows both bounds; for a Constant[Integer] the
474
+ # meet is the constant when the half covers it,
475
+ # otherwise nil.
476
+ def intersect_integer_part(part, half)
477
+ case part
478
+ when Type::Nominal
479
+ half
480
+ when Type::IntegerRange
481
+ integer_range_meet(part, half)
482
+ when Type::Constant
483
+ half.covers?(part.value) ? part : nil
484
+ end
485
+ end
486
+
487
+ def integer_range_meet(left, right)
488
+ low = numeric_to_bound([integer_bound_value(left.min), integer_bound_value(right.min)].max)
489
+ high = numeric_to_bound([integer_bound_value(left.max), integer_bound_value(right.max)].min)
490
+ return nil if integer_range_disjoint?(low, high)
491
+
492
+ Type::Combinator.integer_range(low, high)
493
+ end
494
+
495
+ def integer_bound_value(bound)
496
+ return -Float::INFINITY if bound == Type::IntegerRange::NEG_INFINITY
497
+ return Float::INFINITY if bound == Type::IntegerRange::POS_INFINITY
498
+
499
+ bound
500
+ end
501
+
502
+ def numeric_to_bound(value)
503
+ return Type::IntegerRange::NEG_INFINITY if value == -Float::INFINITY
504
+ return Type::IntegerRange::POS_INFINITY if value == Float::INFINITY
505
+
506
+ value.to_i
507
+ end
508
+
509
+ def integer_range_disjoint?(low, high)
510
+ return false if low == Type::IntegerRange::NEG_INFINITY
511
+ return false if high == Type::IntegerRange::POS_INFINITY
512
+
513
+ low > high
514
+ end
515
+
516
+ # De Morgan: `D \ (M1 ∩ M2 ∩ …) = (D \ M1) ∪ (D \ M2) ∪
517
+ # …`. Each member's complement is computed independently
518
+ # within `current_type` and the results are unioned.
519
+ # Members the algebra cannot complement contribute
520
+ # `current_type` itself, so the union widens to
521
+ # `current_type` overall — sound but imprecise.
522
+ def complement_intersection(current_type, intersection)
523
+ per_member = intersection.members.map do |member|
524
+ Narrowing.narrow_not_refinement(current_type, member)
525
+ end
526
+ Type::Combinator.union(*per_member)
527
+ end
528
+
324
529
  def falsey_value?(value)
325
530
  value.nil? || value == false
326
531
  end
@@ -1029,7 +1234,11 @@ module Rigor
1029
1234
  # the effect's `negative?` flag. Shared between
1030
1235
  # predicate-if-* and assert-if-* application paths.
1031
1236
  def narrow_for_effect(current, effect, environment)
1032
- return effect.refinement_type if effect.respond_to?(:refinement?) && effect.refinement?
1237
+ if effect.respond_to?(:refinement?) && effect.refinement?
1238
+ return narrow_not_refinement(current, effect.refinement_type) if effect.negative?
1239
+
1240
+ return effect.refinement_type
1241
+ end
1033
1242
 
1034
1243
  if effect.negative?
1035
1244
  narrow_not_class(current, effect.class_name, exact: false, environment: environment)
@@ -4,6 +4,7 @@ require "prism"
4
4
 
5
5
  require_relative "../scope"
6
6
  require_relative "../type"
7
+ require_relative "narrowing"
7
8
  require_relative "statement_evaluator"
8
9
 
9
10
  module Rigor
@@ -475,16 +476,9 @@ module Rigor
475
476
 
476
477
  case node
477
478
  when Prism::ModuleNode, Prism::ClassNode
478
- name = qualified_name_for(node.constant_path)
479
- if name
480
- full = (qualified_prefix + [name]).join("::")
481
- singleton = Type::Combinator.singleton_of(full)
482
- identity_table[node.constant_path] = singleton
483
- discovered[full] = singleton
484
- child_prefix = qualified_prefix + [name]
485
- record_declarations(node.body, child_prefix, identity_table, discovered) if node.body
486
- return
487
- end
479
+ return if record_class_or_module?(node, qualified_prefix, identity_table, discovered)
480
+ when Prism::ConstantWriteNode
481
+ return if record_data_define_constant?(node, qualified_prefix, identity_table, discovered)
488
482
  end
489
483
 
490
484
  node.compact_child_nodes.each do |child|
@@ -492,6 +486,60 @@ module Rigor
492
486
  end
493
487
  end
494
488
 
489
+ def record_class_or_module?(node, qualified_prefix, identity_table, discovered)
490
+ name = qualified_name_for(node.constant_path)
491
+ return false unless name
492
+
493
+ full = (qualified_prefix + [name]).join("::")
494
+ singleton = Type::Combinator.singleton_of(full)
495
+ identity_table[node.constant_path] = singleton
496
+ discovered[full] = singleton
497
+ child_prefix = qualified_prefix + [name]
498
+ record_declarations(node.body, child_prefix, identity_table, discovered) if node.body
499
+ true
500
+ end
501
+
502
+ # Recognises `Const = Data.define(*Symbol) [do ... end]` and registers
503
+ # `Const` (qualified by the surrounding class/module path) as a
504
+ # discovered class. `Const.new(...)` then resolves to a fresh
505
+ # `Nominal[Const]` via `meta_new`, instead of the un-narrowed
506
+ # `Dynamic[top]` returned by the default `Class#new` envelope.
507
+ #
508
+ # The Data.define block body, if present, is recursed into so any
509
+ # nested class/module declarations in the override block (rare but
510
+ # legal) still feed the discovered table.
511
+ def record_data_define_constant?(node, qualified_prefix, identity_table, discovered)
512
+ return false unless data_define_call?(node.value)
513
+
514
+ full = (qualified_prefix + [node.name.to_s]).join("::")
515
+ discovered[full] = Type::Combinator.singleton_of(full)
516
+ record_declarations(node.value, qualified_prefix, identity_table, discovered)
517
+ true
518
+ end
519
+
520
+ # Recognises `Data.define(*Symbol)` and `Data.define(*Symbol) do ... end`
521
+ # at constant-write rvalue position. The receiver MUST be the bare
522
+ # `Data` constant (or `::Data`); other receivers (a local variable, a
523
+ # method call return) are rejected because their identity is not
524
+ # statically known.
525
+ def data_define_call?(node)
526
+ return false unless node.is_a?(Prism::CallNode)
527
+ return false unless node.name == :define
528
+ return false unless data_constant_receiver?(node.receiver)
529
+
530
+ args = node.arguments&.arguments || []
531
+ args.all?(Prism::SymbolNode)
532
+ end
533
+
534
+ def data_constant_receiver?(node)
535
+ case node
536
+ when Prism::ConstantReadNode
537
+ node.name == :Data
538
+ when Prism::ConstantPathNode
539
+ node.parent.nil? && node.name == :Data
540
+ end
541
+ end
542
+
495
543
  def qualified_name_for(constant_path_node)
496
544
  case constant_path_node
497
545
  when Prism::ConstantReadNode
@@ -515,6 +563,13 @@ module Rigor
515
563
  # Prism node the StatementEvaluator did not visit (i.e. expression-
516
564
  # interior nodes like the receiver/args of a CallNode). Those
517
565
  # nodes inherit their nearest recorded ancestor's scope.
566
+ #
567
+ # `IfNode` / `UnlessNode` are special-cased: the truthy and falsey
568
+ # branches each get their predicate's narrowed scope before
569
+ # recursing. This handles expression-position conditionals
570
+ # (e.g. `cache[k] = if cond; t; else; e; end` and conditionals
571
+ # nested as call arguments) which are typed by ExpressionTyper
572
+ # without going through `eval_if`'s narrowing path.
518
573
  def propagate(node, table, parent_scope)
519
574
  return unless node.is_a?(Prism::Node)
520
575
 
@@ -526,7 +581,28 @@ module Rigor
526
581
  parent_scope
527
582
  end
528
583
 
529
- node.compact_child_nodes.each { |child| propagate(child, table, current_scope) }
584
+ case node
585
+ when Prism::IfNode
586
+ propagate_if_branches(node, table, current_scope)
587
+ when Prism::UnlessNode
588
+ propagate_unless_branches(node, table, current_scope)
589
+ else
590
+ node.compact_child_nodes.each { |child| propagate(child, table, current_scope) }
591
+ end
592
+ end
593
+
594
+ def propagate_if_branches(node, table, current_scope)
595
+ truthy_scope, falsey_scope = Narrowing.predicate_scopes(node.predicate, current_scope)
596
+ propagate(node.predicate, table, current_scope) if node.predicate
597
+ propagate(node.statements, table, truthy_scope) if node.statements
598
+ propagate(node.subsequent, table, falsey_scope) if node.subsequent
599
+ end
600
+
601
+ def propagate_unless_branches(node, table, current_scope)
602
+ truthy_scope, falsey_scope = Narrowing.predicate_scopes(node.predicate, current_scope)
603
+ propagate(node.predicate, table, current_scope) if node.predicate
604
+ propagate(node.statements, table, falsey_scope) if node.statements
605
+ propagate(node.else_clause, table, truthy_scope) if node.else_clause
530
606
  end
531
607
  end
532
608
  # rubocop:enable Metrics/ModuleLength
@@ -894,7 +894,11 @@ module Rigor
894
894
  end
895
895
 
896
896
  def narrow_for_assert_effect(current_type, effect, environment)
897
- return effect.refinement_type if effect.refinement?
897
+ if effect.refinement?
898
+ return Narrowing.narrow_not_refinement(current_type, effect.refinement_type) if effect.negative?
899
+
900
+ return effect.refinement_type
901
+ end
898
902
 
899
903
  if effect.negative?
900
904
  Narrowing.narrow_not_class(current_type, effect.class_name, exact: false, environment: environment)
@@ -124,8 +124,8 @@ module Rigor
124
124
  \s+
125
125
  (?<target>self|[a-z_][a-zA-Z0-9_]*)
126
126
  \s+is\s+
127
+ (?<negation>~?)
127
128
  (?:
128
- (?<negation>~?)
129
129
  (?<class_name>(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)
130
130
  |
131
131
  (?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])?)
@@ -181,8 +181,8 @@ module Rigor
181
181
  \s+
182
182
  (?<target>self|[a-z_][a-zA-Z0-9_]*)
183
183
  \s+is\s+
184
+ (?<negation>~?)
184
185
  (?:
185
- (?<negation>~?)
186
186
  (?<class_name>(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)
187
187
  |
188
188
  (?<refinement>[a-z][a-z0-9-]*(?:[\[<][^\]>]*[\]>])?)
@@ -231,14 +231,19 @@ module Rigor
231
231
  # nil, `negative` reflects the optional `~` prefix.
232
232
  # - Refinement arm matched: `class_name` is nil,
233
233
  # `refinement_type` is the resolved `Rigor::Type`,
234
- # `negative` is `false` (refinement-form directives do
235
- # not support `~` negation in v0.0.4).
234
+ # `negative` reflects the `~` prefix. v0.0.5 supports
235
+ # refinement-form negation for the `Difference[base,
236
+ # Constant]` shape (the narrowing tier computes the
237
+ # complement decomposition); other refinement carriers
238
+ # under negation fall back to the conservative
239
+ # "current_type unchanged" answer.
236
240
  # - Refinement payload unparseable: returns
237
241
  # `[nil, nil, false]` so callers can drop the directive
238
242
  # silently (fail-soft policy).
239
243
  def resolve_directive_rhs(match)
244
+ negative = match[:negation].to_s == "~"
240
245
  class_capture = match[:class_name]
241
- return [class_capture.to_s.sub(/\A::/, ""), nil, match[:negation].to_s == "~"] if class_capture
246
+ return [class_capture.to_s.sub(/\A::/, ""), nil, negative] if class_capture
242
247
 
243
248
  refinement_capture = match[:refinement]
244
249
  return [nil, nil, false] if refinement_capture.nil?
@@ -246,7 +251,7 @@ module Rigor
246
251
  type = Builtins::ImportedRefinements.parse(refinement_capture)
247
252
  return [nil, nil, false] if type.nil?
248
253
 
249
- [nil, type, false]
254
+ [nil, type, negative]
250
255
  end
251
256
 
252
257
  def target_fields(target)
@@ -65,11 +65,13 @@ module Rigor
65
65
  # `:neg_infinity`). Use this in arithmetic comparisons; never compare
66
66
  # `:neg_infinity` directly with an `Integer`.
67
67
  def lower
68
- min == NEG_INFINITY ? -Float::INFINITY : min
68
+ m = min
69
+ m.is_a?(Symbol) ? -Float::INFINITY : m
69
70
  end
70
71
 
71
72
  def upper
72
- max == POS_INFINITY ? Float::INFINITY : max
73
+ m = max
74
+ m.is_a?(Symbol) ? Float::INFINITY : m
73
75
  end
74
76
 
75
77
  ALIAS_NAMES = {
data/lib/rigor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rigor
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.6"
5
5
  end
@@ -38,15 +38,13 @@ module Rigor
38
38
 
39
39
  def initialize: (?libraries: Array[String], ?signature_paths: Array[String | _ToPath]) -> void
40
40
  def class_known?: (String | Symbol name) -> bool
41
- def instance_definition: (String | Symbol class_name) -> untyped
42
- def instance_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped
43
- def singleton_definition: (String | Symbol class_name) -> untyped
44
- def singleton_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped
41
+ def instance_definition: (String | Symbol class_name) -> untyped?
42
+ def instance_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
43
+ def singleton_definition: (String | Symbol class_name) -> untyped?
44
+ def singleton_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
45
45
  def class_type_param_names: (String | Symbol class_name) -> Array[Symbol]
46
46
  def class_ordering: (String | Symbol lhs, String | Symbol rhs) -> ordering
47
47
  def constant_type: (String name) -> Type::t?
48
- def instance_definition: (String | Symbol class_name) -> untyped?
49
- def singleton_definition: (String | Symbol class_name) -> untyped?
50
48
  end
51
49
 
52
50
  class RbsHierarchy
@@ -85,6 +85,7 @@ module Rigor
85
85
  def self?.narrow_not_equal: (Type::t type, untyped literal) -> Type::t
86
86
  def self?.narrow_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t
87
87
  def self?.narrow_not_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t
88
+ def self?.narrow_not_refinement: (Type::t current_type, Type::t refinement_type) -> Type::t
88
89
  def self?.predicate_scopes: (untyped node, Scope scope) -> [Scope, Scope]
89
90
  def self?.case_when_scopes: (untyped subject, Array[untyped] conditions, Scope scope) -> [Scope, Scope]
90
91
  def self?.analyse: (untyped node, Scope scope) -> untyped
@@ -131,7 +132,7 @@ module Rigor
131
132
  module ScopeIndexer
132
133
  def self?.index: (untyped root, default_scope: Scope) -> Hash[untyped, Scope]
133
134
  def self?.build_declaration_overrides: (untyped root) -> Hash[untyped, Type::t]
134
- def self?.record_declarations: (untyped node, Array[String] qualified_prefix, Hash[untyped, Type::t] table) -> void
135
+ def self?.record_declarations: (untyped node, Array[String] qualified_prefix, Hash[untyped, Type::t] identity_table, Hash[String, Type::t] discovered) -> void
135
136
  def self?.qualified_name_for: (untyped constant_path_node) -> String?
136
137
  def self?.render_constant_path: (untyped node) -> String
137
138
  def self?.propagate: (untyped node, Hash[untyped, Scope] table, Scope parent_scope) -> void
data/sig/rigor/type.rbs CHANGED
@@ -8,9 +8,9 @@ module Rigor
8
8
  def self.instance: () -> Top
9
9
  def describe: (?Symbol verbosity) -> String
10
10
  def erase_to_rbs: () -> String
11
- def top: () -> Top
12
- def bot: () -> Bot
13
- def dynamic: () -> Dynamic
11
+ def top: () -> Trinary
12
+ def bot: () -> Trinary
13
+ def dynamic: () -> Trinary
14
14
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
15
15
  def ==: (untyped other) -> bool
16
16
  def hash: () -> Integer
@@ -21,9 +21,9 @@ module Rigor
21
21
  def self.instance: () -> Bot
22
22
  def describe: (?Symbol verbosity) -> String
23
23
  def erase_to_rbs: () -> String
24
- def top: () -> Top
25
- def bot: () -> Bot
26
- def dynamic: () -> Dynamic
24
+ def top: () -> Trinary
25
+ def bot: () -> Trinary
26
+ def dynamic: () -> Trinary
27
27
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
28
28
  def ==: (untyped other) -> bool
29
29
  def hash: () -> Integer
@@ -35,9 +35,9 @@ module Rigor
35
35
  def initialize: (Type::t static_facet) -> void
36
36
  def describe: (?Symbol verbosity) -> String
37
37
  def erase_to_rbs: () -> String
38
- def top: () -> Top
39
- def bot: () -> Bot
40
- def dynamic: () -> Dynamic
38
+ def top: () -> Trinary
39
+ def bot: () -> Trinary
40
+ def dynamic: () -> Trinary
41
41
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
42
42
  def ==: (untyped other) -> bool
43
43
  def hash: () -> Integer
@@ -49,9 +49,9 @@ module Rigor
49
49
  def initialize: (untyped value) -> void
50
50
  def describe: (?Symbol verbosity) -> String
51
51
  def erase_to_rbs: () -> String
52
- def top: () -> Top
53
- def bot: () -> Bot
54
- def dynamic: () -> Dynamic
52
+ def top: () -> Trinary
53
+ def bot: () -> Trinary
54
+ def dynamic: () -> Trinary
55
55
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
56
56
  def ==: (untyped other) -> bool
57
57
  def hash: () -> Integer
@@ -68,14 +68,14 @@ module Rigor
68
68
  def finite?: () -> bool
69
69
  def cardinality: () -> (Integer | Float)
70
70
  def covers?: (untyped value) -> bool
71
- def lower: () -> Numeric
72
- def upper: () -> Numeric
71
+ def lower: () -> (Integer | Float)
72
+ def upper: () -> (Integer | Float)
73
73
  def describe: (?Symbol verbosity) -> String
74
74
  def generic_description: () -> String
75
75
  def erase_to_rbs: () -> String
76
- def top: () -> Top
77
- def bot: () -> Bot
78
- def dynamic: () -> Dynamic
76
+ def top: () -> Trinary
77
+ def bot: () -> Trinary
78
+ def dynamic: () -> Trinary
79
79
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
80
80
  def ==: (untyped other) -> bool
81
81
  def hash: () -> Integer
@@ -88,9 +88,9 @@ module Rigor
88
88
  def initialize: (String class_name, ?Array[Type::t] type_args) -> void
89
89
  def describe: (?Symbol verbosity) -> String
90
90
  def erase_to_rbs: () -> String
91
- def top: () -> Top
92
- def bot: () -> Bot
93
- def dynamic: () -> Dynamic
91
+ def top: () -> Trinary
92
+ def bot: () -> Trinary
93
+ def dynamic: () -> Trinary
94
94
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
95
95
  def ==: (untyped other) -> bool
96
96
  def hash: () -> Integer
@@ -102,9 +102,9 @@ module Rigor
102
102
  def initialize: (String class_name) -> void
103
103
  def describe: (?Symbol verbosity) -> String
104
104
  def erase_to_rbs: () -> String
105
- def top: () -> Top
106
- def bot: () -> Bot
107
- def dynamic: () -> Dynamic
105
+ def top: () -> Trinary
106
+ def bot: () -> Trinary
107
+ def dynamic: () -> Trinary
108
108
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
109
109
  def ==: (untyped other) -> bool
110
110
  def hash: () -> Integer
@@ -116,9 +116,9 @@ module Rigor
116
116
  def initialize: (Array[Type::t] members) -> void
117
117
  def describe: (?Symbol verbosity) -> String
118
118
  def erase_to_rbs: () -> String
119
- def top: () -> Top
120
- def bot: () -> Bot
121
- def dynamic: () -> Dynamic
119
+ def top: () -> Trinary
120
+ def bot: () -> Trinary
121
+ def dynamic: () -> Trinary
122
122
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
123
123
  def ==: (untyped other) -> bool
124
124
  def hash: () -> Integer
@@ -131,9 +131,9 @@ module Rigor
131
131
  def initialize: (Type::t base, Type::t removed) -> void
132
132
  def describe: (?Symbol verbosity) -> String
133
133
  def erase_to_rbs: () -> String
134
- def top: () -> Top
135
- def bot: () -> Bot
136
- def dynamic: () -> Dynamic
134
+ def top: () -> Trinary
135
+ def bot: () -> Trinary
136
+ def dynamic: () -> Trinary
137
137
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
138
138
  def ==: (untyped other) -> bool
139
139
  def hash: () -> Integer
@@ -146,9 +146,9 @@ module Rigor
146
146
  def initialize: (Type::t base, Symbol predicate_id) -> void
147
147
  def describe: (?Symbol verbosity) -> String
148
148
  def erase_to_rbs: () -> String
149
- def top: () -> Top
150
- def bot: () -> Bot
151
- def dynamic: () -> Dynamic
149
+ def top: () -> Trinary
150
+ def bot: () -> Trinary
151
+ def dynamic: () -> Trinary
152
152
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
153
153
  def matches?: (untyped value) -> bool?
154
154
  def ==: (untyped other) -> bool
@@ -161,9 +161,9 @@ module Rigor
161
161
  def initialize: (Array[Type::t] members) -> void
162
162
  def describe: (?Symbol verbosity) -> String
163
163
  def erase_to_rbs: () -> String
164
- def top: () -> Top
165
- def bot: () -> Bot
166
- def dynamic: () -> Dynamic
164
+ def top: () -> Trinary
165
+ def bot: () -> Trinary
166
+ def dynamic: () -> Trinary
167
167
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
168
168
  def ==: (untyped other) -> bool
169
169
  def hash: () -> Integer
@@ -175,9 +175,9 @@ module Rigor
175
175
  def initialize: (Array[Type::t] elements) -> void
176
176
  def describe: (?Symbol verbosity) -> String
177
177
  def erase_to_rbs: () -> String
178
- def top: () -> Top
179
- def bot: () -> Bot
180
- def dynamic: () -> Dynamic
178
+ def top: () -> Trinary
179
+ def bot: () -> Trinary
180
+ def dynamic: () -> Trinary
181
181
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
182
182
  def ==: (untyped other) -> bool
183
183
  def hash: () -> Integer
@@ -198,9 +198,9 @@ module Rigor
198
198
  def required_key?: (untyped key) -> bool
199
199
  def optional_key?: (untyped key) -> bool
200
200
  def read_only_key?: (untyped key) -> bool
201
- def top: () -> Top
202
- def bot: () -> Bot
203
- def dynamic: () -> Dynamic
201
+ def top: () -> Trinary
202
+ def bot: () -> Trinary
203
+ def dynamic: () -> Trinary
204
204
  def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
205
205
  def ==: (untyped other) -> bool
206
206
  def hash: () -> Integer