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.
- checksums.yaml +4 -4
- data/data/builtins/ruby_core/array.yml +1470 -0
- data/data/builtins/ruby_core/file.yml +501 -0
- data/data/builtins/ruby_core/io.yml +1594 -0
- data/data/builtins/ruby_core/numeric.yml +1809 -0
- data/data/builtins/ruby_core/string.yml +1850 -0
- data/lib/rigor/analysis/check_rules.rb +86 -1
- data/lib/rigor/analysis/runner.rb +4 -0
- data/lib/rigor/builtins/imported_refinements.rb +69 -0
- data/lib/rigor/configuration.rb +6 -1
- data/lib/rigor/inference/acceptance.rb +149 -0
- data/lib/rigor/inference/builtins/array_catalog.rb +46 -0
- data/lib/rigor/inference/builtins/method_catalog.rb +90 -0
- data/lib/rigor/inference/builtins/numeric_catalog.rb +93 -0
- data/lib/rigor/inference/builtins/string_catalog.rb +39 -0
- data/lib/rigor/inference/expression_typer.rb +48 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +650 -16
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +144 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +113 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +4 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +107 -0
- data/lib/rigor/inference/method_dispatcher.rb +28 -21
- data/lib/rigor/inference/narrowing.rb +374 -4
- data/lib/rigor/inference/scope_indexer.rb +10 -2
- data/lib/rigor/inference/statement_evaluator.rb +211 -2
- data/lib/rigor/rbs_extended.rb +65 -1
- data/lib/rigor/scope.rb +14 -0
- data/lib/rigor/type/combinator.rb +69 -1
- data/lib/rigor/type/difference.rb +155 -0
- data/lib/rigor/type/integer_range.rb +137 -0
- data/lib/rigor/type.rb +2 -0
- data/lib/rigor/version.rb +1 -1
- data/sig/rigor/rbs_extended.rbs +3 -0
- data/sig/rigor/scope.rbs +1 -0
- data/sig/rigor/type.rbs +51 -1
- 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
|
-
|
|
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
|
|