rigortype 0.0.2 → 0.0.3

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/data/builtins/ruby_core/array.yml +1470 -0
  3. data/data/builtins/ruby_core/file.yml +501 -0
  4. data/data/builtins/ruby_core/io.yml +1594 -0
  5. data/data/builtins/ruby_core/numeric.yml +1809 -0
  6. data/data/builtins/ruby_core/string.yml +1850 -0
  7. data/lib/rigor/analysis/check_rules.rb +86 -1
  8. data/lib/rigor/analysis/runner.rb +4 -0
  9. data/lib/rigor/builtins/imported_refinements.rb +69 -0
  10. data/lib/rigor/configuration.rb +6 -1
  11. data/lib/rigor/inference/acceptance.rb +149 -0
  12. data/lib/rigor/inference/builtins/array_catalog.rb +46 -0
  13. data/lib/rigor/inference/builtins/method_catalog.rb +90 -0
  14. data/lib/rigor/inference/builtins/numeric_catalog.rb +93 -0
  15. data/lib/rigor/inference/builtins/string_catalog.rb +39 -0
  16. data/lib/rigor/inference/expression_typer.rb +48 -1
  17. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +650 -16
  18. data/lib/rigor/inference/method_dispatcher/file_folding.rb +144 -0
  19. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +113 -0
  20. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +4 -0
  21. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +107 -0
  22. data/lib/rigor/inference/method_dispatcher.rb +28 -21
  23. data/lib/rigor/inference/narrowing.rb +374 -4
  24. data/lib/rigor/inference/scope_indexer.rb +10 -2
  25. data/lib/rigor/inference/statement_evaluator.rb +211 -2
  26. data/lib/rigor/rbs_extended.rb +65 -1
  27. data/lib/rigor/scope.rb +14 -0
  28. data/lib/rigor/type/combinator.rb +69 -1
  29. data/lib/rigor/type/difference.rb +155 -0
  30. data/lib/rigor/type/integer_range.rb +137 -0
  31. data/lib/rigor/type.rb +2 -0
  32. data/lib/rigor/version.rb +1 -1
  33. data/sig/rigor/rbs_extended.rbs +3 -0
  34. data/sig/rigor/scope.rbs +1 -0
  35. data/sig/rigor/type.rbs +51 -1
  36. metadata +15 -1
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `String` and `Symbol` catalog. Singleton — load once,
9
+ # consult during dispatch.
10
+ #
11
+ # The blocklist below is the curated set of catalog `:leaf`
12
+ # entries the C-body classifier mis-attributes (the body of
13
+ # `rb_str_replace` calls `str_modifiable` / `str_discard`
14
+ # which the regex-based classifier does not recognise as
15
+ # mutation primitives). Adding to the blocklist is the
16
+ # corrective surface for false positives until the
17
+ # classifier learns the helper functions.
18
+ STRING_CATALOG = MethodCatalog.new(
19
+ path: File.expand_path(
20
+ "../../../../data/builtins/ruby_core/string.yml",
21
+ __dir__
22
+ ),
23
+ mutating_selectors: {
24
+ "String" => Set[
25
+ :replace, :initialize, :initialize_copy, :clear, :<<, :concat, :insert,
26
+ :prepend, :force_encoding, :encode, :scrub, :unicode_normalize, :"[]=",
27
+ :upto, :each_byte, :each_char, :each_codepoint,
28
+ :each_grapheme_cluster, :each_line, :bytesplice
29
+ ],
30
+ "Symbol" => Set[
31
+ # Symbol is immutable in Ruby; the classifier mis-flags
32
+ # `inspect` because `rb_sym_inspect` builds a temporary
33
+ # mutable buffer. Allow it.
34
+ ]
35
+ }
36
+ )
37
+ end
38
+ end
39
+ end
@@ -744,6 +744,33 @@ module Rigor
744
744
  arg_types = call_arg_types(node)
745
745
  block_type = block_return_type_for(node, receiver, arg_types)
746
746
 
747
+ # v0.0.3 A — implicit-self calls prefer a same-named
748
+ # top-level `def` over RBS dispatch. Without this,
749
+ # a helper like `def select(...)` defined inside an
750
+ # `RSpec.describe ... do ... end` block mis-routes
751
+ # through `Enumerable#select` / `Object#select` and
752
+ # the caller observes `Array[Elem]` instead of the
753
+ # helper's actual return type. The check fires only
754
+ # for `node.receiver.nil?` (true implicit self), so
755
+ # explicit-receiver dispatch is unaffected.
756
+ local_def = node.receiver.nil? ? scope.top_level_def_for(node.name) : nil
757
+ if local_def
758
+ local_inference = infer_top_level_user_method(local_def, receiver, arg_types)
759
+ return local_inference if local_inference
760
+
761
+ # The local def matches by name but the
762
+ # parameter shape is too complex for the first-
763
+ # iteration binder (kwargs / optionals / rest).
764
+ # Returning `Dynamic[Top]` is the safest answer:
765
+ # we know RBS dispatch would be wrong (the
766
+ # method is user-defined and shadows whatever
767
+ # ancestor method the dispatch would find), and
768
+ # `Dynamic[Top]` propagates correctly through
769
+ # downstream call chains without surfacing
770
+ # misleading false-positive diagnostics.
771
+ return dynamic_top
772
+ end
773
+
747
774
  result = MethodDispatcher.dispatch(
748
775
  receiver_type: receiver,
749
776
  method_name: node.name,
@@ -786,6 +813,22 @@ module Rigor
786
813
  # - the inference is already in progress for this
787
814
  # (class, method, signature) tuple — recursion
788
815
  # safety net.
816
+ # v0.0.3 A — re-types a top-level (or DSL-block-nested)
817
+ # `def` discovered by `ScopeIndexer` under the
818
+ # `TOP_LEVEL_DEF_KEY` sentinel. Mirrors the
819
+ # `infer_user_method_return` shape but uses the
820
+ # current `scope.self_type` (or implicit `Object`)
821
+ # as the receiver carrier so the body's own self is
822
+ # consistent with the call site's. Returns nil when
823
+ # the parameter shape disqualifies the def, when the
824
+ # body is empty, or when a recursion cycle is
825
+ # detected.
826
+ def infer_top_level_user_method(def_node, receiver, arg_types)
827
+ infer_user_method_return(def_node, receiver, arg_types)
828
+ rescue StandardError
829
+ nil
830
+ end
831
+
789
832
  def try_user_method_inference(receiver, call_node, arg_types)
790
833
  return nil unless receiver.is_a?(Type::Nominal)
791
834
 
@@ -806,7 +849,11 @@ module Rigor
806
849
  body_scope = build_user_method_body_scope(def_node, receiver, arg_types)
807
850
  return nil if body_scope.nil?
808
851
 
809
- signature = [receiver.class_name, def_node.name, arg_types.map { |t| t.describe(:short) }]
852
+ # Recursion-guard signature. Uses `describe(:short)`
853
+ # so non-Nominal receivers (e.g. the implicit
854
+ # `Object` carrier used for top-level / DSL-block
855
+ # defs in v0.0.3 A) can participate without raising.
856
+ signature = [receiver.describe(:short), def_node.name, arg_types.map { |t| t.describe(:short) }]
810
857
  stack = (Thread.current[INFERENCE_GUARD_KEY] ||= [])
811
858
  return Type::Combinator.untyped if stack.include?(signature)
812
859