Module: Rigor::Inference::Builtins
- Defined in:
- lib/rigor/inference/builtins/set_catalog.rb,
lib/rigor/inference/builtins/hash_catalog.rb,
lib/rigor/inference/builtins/time_catalog.rb,
lib/rigor/inference/builtins/array_catalog.rb,
lib/rigor/inference/builtins/range_catalog.rb,
lib/rigor/inference/builtins/method_catalog.rb,
lib/rigor/inference/builtins/string_catalog.rb,
lib/rigor/inference/builtins/numeric_catalog.rb
Defined Under Namespace
Modules: NumericCatalog Classes: MethodCatalog
Constant Summary collapse
- SET_CATALOG =
‘Set` catalog. Singleton — load once, consult during dispatch.
Set was rewritten in C and folded into CRuby for Ruby 3.2+; the reference branch (‘ruby_4_0`) ships the implementation in `references/ruby/set.c` with `Init_Set` registering every method directly. There is no `set.rb` prelude — the trailing `rb_provide(“set.rb”)` makes `require “set”` a no-op against the built-in.
The blocklist below catches the catalog ‘:leaf` entries the C-body classifier mis-attributes. Set’s iteration helpers (‘set_iter`, `RETURN_SIZED_ENUMERATOR`) and its identity- mode and reset paths drive into helpers the regex classifier does not yet recognise as block-yielding or mutating.
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/set.yml", __dir__ ), mutating_selectors: { "Set" => Set[ # Indirect mutators classified `:leaf` because the C # classifier did not follow the helper functions: # # - `initialize_copy` calls `set_copy` to overwrite the # receiver's table. # - `compare_by_identity` swaps the internal hash type # via `set_reset_table_with_type`. # - `reset` rebuilds the internal table to dedup after # element mutation. :initialize_copy, :compare_by_identity, :reset, # Block-dependent methods classified `:leaf` because the # C body uses `set_iter` / `RETURN_SIZED_ENUMERATOR` # rather than calling `rb_yield` directly: :each, :classify, :divide, # `disjoint?` delegates into `set_i_intersect`, which # for non-Set enumerables uses `rb_funcall(other, # :any?, ...)` — that is user-redefinable dispatch the # classifier missed because the call site is in a # sibling function. :disjoint? ] } )
- HASH_CATALOG =
‘Hash` catalog. Singleton — load once, consult during dispatch.
Hash mirrors Array’s mutation pattern: nearly every iteration method yields through ‘rb_hash_foreach` plus a per-pair static callback (`each_value_i`, `keep_if_i`, …), and the C-body classifier does not follow into the callback so it lands as `:leaf` despite being block-dependent. The blocklist below captures every false-positive `:leaf` we have spotted in the generated YAML — bias toward conservatism so a missed fold is acceptable but a folded mutator/yielder is not.
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/hash.yml", __dir__ ), mutating_selectors: { "Hash" => Set[ # Block-dependent iteration — yields via `rb_hash_foreach` # plus a per-pair callback that the regex classifier does # not follow: :each, :each_pair, :each_key, :each_value, :select, :filter, :reject, :transform_values, # Block-dependent merge — `rb_hash_merge` delegates into # `rb_hash_update`, which yields per conflict when a block # is given: :merge ] } )
- TIME_CATALOG =
‘Time` catalog. Singleton — load once, consult during dispatch.
Time is a pure-C built-in: the Init block in ‘references/ruby/time.c` registers the bulk of the surface, and the Ruby-side prelude `references/ruby/timev.rb` contributes the class-side constructors (`Time.now`, `Time.at`, `Time.new`) through Primitive cexpr stubs.
Time receivers are not lifted to a ‘Constant` carrier today (there is no `Time` literal node — the closest is `Time.now` / `Time.new(…)`, which produce `Nominal`). The catalog wiring therefore mostly governs:
-
The size-projection-equivalent reader surface (‘#year`, `#month`, `#hour`, `#sec`, `#wday`, …) — RBS-declared `Integer` is preserved through dispatch.
-
The blocklist below, which keeps the indirect-mutator methods that the C-body classifier mis-flagged as ‘:leaf` from ever folding through a hypothetical future `Constant<Time>` carrier.
The blocklist captures the false-positive ‘:leaf` entries whose helper functions the regex classifier did not recognise as mutators.
-
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/time.yml", __dir__ ), mutating_selectors: { "Time" => Set[ # `time_init_copy` writes the `timew` and `vtm` slots on # the receiver via `time_set_timew` / `time_set_vtm`. # Classed `:leaf` because those setters are not in the # mutator regex's helper list. Blocked for symmetry with # String / Array / Range / Set initialize_copy entries. :initialize_copy, # `time_localtime_m` -> `time_localtime` calls # `time_modify(time)` to mark the receiver mutable # before rewriting its `vtm` cache and `tzmode`. The # docstring is explicit ("converts time to local time # in place"). The C-body classifier mis-flagged it as # `:leaf` because `time_modify` is not in its mutator # regex. :localtime, # `time_gmtime` (registered as both `gmtime` and `utc` # against `rb_cTime`) follows the same in-place pattern # as `time_localtime`: `time_modify(time)` then a # `time_set_vtm` write and `TZMODE_SET_UTC`. Both # selectors share the cfunc, so both must be blocked. :gmtime, :utc ] } )
- ARRAY_CATALOG =
‘Array` catalog. Singleton — load once, consult during dispatch.
Array has more mutation surface than String: every method that logically reshapes the array tends to call ‘rb_ary_modify` or an internal helper (`ary_replace`, `ary_resize`, `ary_pop`, `ary_push_internal`, …) that the classifier does not yet recognise. The blocklist captures the methods we have specifically observed flowing as `:leaf` despite mutating.
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/array.yml", __dir__ ), mutating_selectors: { "Array" => Set[ # Mutators classified `:leaf` by the C-body heuristic :<<, :push, :replace, :clear, :concat, :insert, :"[]=", :unshift, :prepend, :pop, :shift, :delete_at, :slice!, :compact!, :flatten!, :uniq!, :sort!, :reverse!, :rotate!, :keep_if, :delete_if, :select!, :filter!, :reject!, :collect!, :map!, :assoc, :rassoc, :fill, :delete, :transpose, # Methods that yield (block-dependent) — classifier # may mark them leaf when the block call is gated: :each, :each_with_index, :each_index, :each_slice, :each_cons, :each_with_object, # Identity/comparison methods that take a block too :max, :min, :max_by, :min_by, :minmax, :minmax_by, :sort_by, :group_by, :partition, :all?, :any?, :none?, :one?, :find, :detect, :find_all, :find_index, :reduce, :inject, :flat_map, :collect_concat, :zip, :product, :combination, :permutation, :chunk_while, :slice_when, :tally ] } )
- RANGE_CATALOG =
‘Range` catalog. Singleton — load once, consult during dispatch.
Range is largely immutable: ‘begin`, `end`, and `excl` are set at construction by `range_initialize` and never mutated afterwards. The blocklist below therefore stays small. The entries we DO need are the iteration methods whose C body routes through a helper the block/yield regex does not recognise, so the classifier mis-flags them as `:leaf` despite yielding to a block.
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/range.yml", __dir__ ), mutating_selectors: { "Range" => Set[ # `range_initialize` / `range_initialize_copy` write # `begin`/`end`/`excl` slots on the receiver; classed # `:leaf` because the writes go through the struct # accessor not `rb_check_frozen`. Blocked for symmetry # with String / Array. :initialize, :initialize_copy, # `range_reverse_each` yields to its block via # `range_each_func` -> caller's block; the regex # classifier follows direct `rb_yield*` calls only. :reverse_each, # `range_percent_step` returns an Enumerator unless a # block is supplied, in which case it yields. Treated # as block-dependent so the fold tier never invokes it # against a literal Range and tries to materialise an # Enumerator into a Constant. :% ] } )
- STRING_CATALOG =
‘String` and `Symbol` catalog. Singleton — load once, consult during dispatch.
The blocklist below is the curated set of catalog ‘:leaf` entries the C-body classifier mis-attributes (the body of `rb_str_replace` calls `str_modifiable` / `str_discard` which the regex-based classifier does not recognise as mutation primitives). Adding to the blocklist is the corrective surface for false positives until the classifier learns the helper functions.
MethodCatalog.new( path: File.( "../../../../data/builtins/ruby_core/string.yml", __dir__ ), mutating_selectors: { "String" => Set[ :replace, :initialize, :initialize_copy, :clear, :<<, :concat, :insert, :prepend, :force_encoding, :encode, :scrub, :unicode_normalize, :"[]=", :upto, :each_byte, :each_char, :each_codepoint, :each_grapheme_cluster, :each_line, :bytesplice ], "Symbol" => Set[ # Symbol is immutable in Ruby; the classifier mis-flags # `inspect` because `rb_sym_inspect` builds a temporary # mutable buffer. Allow it. ] } )