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
@@ -0,0 +1,365 @@
1
+ # DO NOT EDIT — generated by tool/extract_builtin_catalog.rb
2
+ ---
3
+ schema_version: 1
4
+ generated_from:
5
+ ruby_init_c: references/ruby/rational.c
6
+ ruby_prelude:
7
+ rbs:
8
+ - references/rbs/core/rational.rbs
9
+ purity_levels:
10
+ leaf: Prelude :leaf marker (VM-enforced) or C body uses no dispatch/yield/mutation.
11
+ trivial: Prelude method body is a literal return (self/true/false/nil/Integer).
12
+ leaf_when_numeric: C body falls through to rb_num_coerce_* only when an operand
13
+ is non-numeric; safe to fold when every argument is a concrete numeric.
14
+ inline_block: Prelude method carries :inline_block or :use_block; block-dependent.
15
+ block_dependent: C body yields or checks rb_block_given_p.
16
+ mutates_self: C body checks rb_check_frozen — typically a prelude to mutation.
17
+ dispatch: C body calls user-redefinable methods (rb_funcall*, rb_equal, rb_Float,
18
+ num_funcall*, etc).
19
+ unknown: C body not located in indexed C files.
20
+ classes:
21
+ Rational:
22
+ parent: Numeric
23
+ defined_at: references/ruby/rational.c:2758
24
+ includes: []
25
+ constants: {}
26
+ aliases: {}
27
+ instance_methods:
28
+ numerator:
29
+ source: c
30
+ cfunc: nurat_numerator
31
+ arity: 0
32
+ defined_at: references/ruby/rational.c:2767
33
+ c_body_at: references/ruby/rational.c:586
34
+ c_effects: []
35
+ purity: leaf
36
+ rbs:
37
+ - "() -> Integer"
38
+ rbs_at: references/rbs/core/rational.rbs:342
39
+ denominator:
40
+ source: c
41
+ cfunc: nurat_denominator
42
+ arity: 0
43
+ defined_at: references/ruby/rational.c:2768
44
+ c_body_at: references/ruby/rational.c:604
45
+ c_effects: []
46
+ purity: leaf
47
+ rbs:
48
+ - "() -> Integer"
49
+ rbs_at: references/rbs/core/rational.rbs:250
50
+ "-@":
51
+ source: c
52
+ cfunc: rb_rational_uminus
53
+ arity: 0
54
+ defined_at: references/ruby/rational.c:2770
55
+ c_body_at: references/ruby/rational.c:621
56
+ c_effects: []
57
+ purity: leaf
58
+ rbs:
59
+ - "() -> Rational"
60
+ rbs_at: references/rbs/core/rational.rbs:138
61
+ "+":
62
+ source: c
63
+ cfunc: rb_rational_plus
64
+ arity: 1
65
+ defined_at: references/ruby/rational.c:2771
66
+ c_body_at: references/ruby/rational.c:745
67
+ c_effects:
68
+ - coerce_fallback
69
+ purity: leaf_when_numeric
70
+ rbs:
71
+ - "(Float) -> Float"
72
+ - "(Complex) -> Complex"
73
+ - "(Numeric) -> Rational"
74
+ rbs_at: references/rbs/core/rational.rbs:109
75
+ "-":
76
+ source: c
77
+ cfunc: rb_rational_minus
78
+ arity: 1
79
+ defined_at: references/ruby/rational.c:2772
80
+ c_body_at: references/ruby/rational.c:786
81
+ c_effects:
82
+ - coerce_fallback
83
+ purity: leaf_when_numeric
84
+ rbs:
85
+ - "(Float) -> Float"
86
+ - "(Complex) -> Complex"
87
+ - "(Numeric) -> Rational"
88
+ rbs_at: references/rbs/core/rational.rbs:125
89
+ "*":
90
+ source: c
91
+ cfunc: rb_rational_mul
92
+ arity: 1
93
+ defined_at: references/ruby/rational.c:2773
94
+ c_body_at: references/ruby/rational.c:884
95
+ c_effects:
96
+ - coerce_fallback
97
+ purity: leaf_when_numeric
98
+ rbs:
99
+ - "(Integer) -> Rational"
100
+ - "(Rational) -> Rational"
101
+ - "[T < Numeric] (T) -> T"
102
+ rbs_at: references/rbs/core/rational.rbs:67
103
+ "/":
104
+ source: c
105
+ cfunc: rb_rational_div
106
+ arity: 1
107
+ defined_at: references/ruby/rational.c:2774
108
+ c_body_at: references/ruby/rational.c:925
109
+ c_effects:
110
+ - coerce_fallback
111
+ - raises
112
+ purity: leaf_when_numeric
113
+ rbs:
114
+ - "(Float) -> Float"
115
+ - "(Complex) -> Complex"
116
+ - "(Numeric) -> Rational"
117
+ rbs_at: references/rbs/core/rational.rbs:152
118
+ quo:
119
+ source: c
120
+ cfunc: rb_rational_div
121
+ arity: 1
122
+ defined_at: references/ruby/rational.c:2775
123
+ c_body_at: references/ruby/rational.c:925
124
+ c_effects:
125
+ - coerce_fallback
126
+ - raises
127
+ purity: leaf_when_numeric
128
+ rbs:
129
+ - "(Float) -> Float"
130
+ - "(Complex) -> Complex"
131
+ - "(Numeric) -> Rational"
132
+ rbs_at: references/rbs/core/rational.rbs:363
133
+ fdiv:
134
+ source: c
135
+ cfunc: nurat_fdiv
136
+ arity: 1
137
+ defined_at: references/ruby/rational.c:2776
138
+ c_body_at: references/ruby/rational.c:973
139
+ c_effects:
140
+ - dispatch
141
+ purity: dispatch
142
+ rbs:
143
+ - "(Numeric) -> Float"
144
+ rbs_at: references/rbs/core/rational.rbs:265
145
+ "**":
146
+ source: c
147
+ cfunc: nurat_expt
148
+ arity: 1
149
+ defined_at: references/ruby/rational.c:2777
150
+ c_body_at: references/ruby/rational.c:1002
151
+ c_effects:
152
+ - coerce_fallback
153
+ - raises
154
+ purity: leaf_when_numeric
155
+ rbs:
156
+ - "(Complex) -> Complex"
157
+ - "(Numeric) -> Numeric"
158
+ rbs_at: references/rbs/core/rational.rbs:84
159
+ "<=>":
160
+ source: c
161
+ cfunc: rb_rational_cmp
162
+ arity: 1
163
+ defined_at: references/ruby/rational.c:2779
164
+ c_body_at: references/ruby/rational.c:1106
165
+ c_effects:
166
+ - coerce_fallback
167
+ purity: leaf_when_numeric
168
+ rbs:
169
+ - "(Integer | Rational) -> Integer"
170
+ - "(untyped) -> Integer?"
171
+ rbs_at: references/rbs/core/rational.rbs:182
172
+ "==":
173
+ source: c
174
+ cfunc: nurat_eqeq_p
175
+ arity: 1
176
+ defined_at: references/ruby/rational.c:2780
177
+ c_body_at: references/ruby/rational.c:1159
178
+ c_effects:
179
+ - dispatch
180
+ purity: dispatch
181
+ rbs:
182
+ - "(untyped) -> bool"
183
+ rbs_at: references/rbs/core/rational.rbs:197
184
+ coerce:
185
+ source: c
186
+ cfunc: nurat_coerce
187
+ arity: 1
188
+ defined_at: references/ruby/rational.c:2781
189
+ c_body_at: references/ruby/rational.c:1201
190
+ c_effects:
191
+ - raises
192
+ purity: leaf
193
+ rbs:
194
+ - "(Numeric) -> [ Numeric, Numeric ]"
195
+ rbs_at: references/rbs/core/rational.rbs:237
196
+ positive?:
197
+ source: c
198
+ cfunc: nurat_positive_p
199
+ arity: 0
200
+ defined_at: references/ruby/rational.c:2783
201
+ c_body_at: references/ruby/rational.c:1238
202
+ c_effects: []
203
+ purity: leaf
204
+ rbs:
205
+ - "() -> bool"
206
+ rbs_at: references/rbs/core/rational.rbs:352
207
+ negative?:
208
+ source: c
209
+ cfunc: nurat_negative_p
210
+ arity: 0
211
+ defined_at: references/ruby/rational.c:2784
212
+ c_body_at: references/ruby/rational.c:1251
213
+ c_effects: []
214
+ purity: leaf
215
+ rbs:
216
+ - "() -> bool"
217
+ rbs_at: references/rbs/core/rational.rbs:329
218
+ abs:
219
+ source: c
220
+ cfunc: rb_rational_abs
221
+ arity: 0
222
+ defined_at: references/ruby/rational.c:2785
223
+ c_body_at: references/ruby/rational.c:1270
224
+ c_effects: []
225
+ purity: leaf
226
+ rbs:
227
+ - "() -> Rational"
228
+ rbs_at: references/rbs/core/rational.rbs:209
229
+ magnitude:
230
+ source: c
231
+ cfunc: rb_rational_abs
232
+ arity: 0
233
+ defined_at: references/ruby/rational.c:2786
234
+ c_body_at: references/ruby/rational.c:1270
235
+ c_effects: []
236
+ purity: leaf
237
+ floor:
238
+ source: c
239
+ cfunc: nurat_floor_n
240
+ arity: -1
241
+ defined_at: references/ruby/rational.c:2788
242
+ c_body_at: references/ruby/rational.c:1466
243
+ c_effects: []
244
+ purity: leaf
245
+ rbs:
246
+ - "() -> Integer"
247
+ - "(Integer digits) -> (Integer | Rational)"
248
+ rbs_at: references/rbs/core/rational.rbs:290
249
+ ceil:
250
+ source: c
251
+ cfunc: nurat_ceil_n
252
+ arity: -1
253
+ defined_at: references/ruby/rational.c:2789
254
+ c_body_at: references/ruby/rational.c:1496
255
+ c_effects: []
256
+ purity: leaf
257
+ rbs:
258
+ - "() -> Integer"
259
+ - "(Integer digits) -> (Integer | Rational)"
260
+ rbs_at: references/rbs/core/rational.rbs:234
261
+ truncate:
262
+ source: c
263
+ cfunc: nurat_truncate_n
264
+ arity: -1
265
+ defined_at: references/ruby/rational.c:2790
266
+ c_body_at: references/ruby/rational.c:1526
267
+ c_effects: []
268
+ purity: leaf
269
+ rbs:
270
+ - "() -> Integer"
271
+ - "(Integer ndigits) -> (Integer | Rational)"
272
+ rbs_at: references/rbs/core/rational.rbs:500
273
+ round:
274
+ source: c
275
+ cfunc: nurat_round_n
276
+ arity: -1
277
+ defined_at: references/ruby/rational.c:2791
278
+ c_body_at: references/ruby/rational.c:1569
279
+ c_effects: []
280
+ purity: leaf
281
+ rbs:
282
+ - "(?half: :up | :down | :even) -> Integer"
283
+ - "(Integer digits, ?half: :up | :down | :even) -> (Integer | Rational)"
284
+ rbs_at: references/rbs/core/rational.rbs:422
285
+ to_i:
286
+ source: c
287
+ cfunc: nurat_truncate
288
+ arity: 0
289
+ defined_at: references/ruby/rational.c:2793
290
+ c_body_at: references/ruby/rational.c:1309
291
+ c_effects: []
292
+ purity: leaf
293
+ rbs:
294
+ - "() -> Integer"
295
+ rbs_at: references/rbs/core/rational.rbs:452
296
+ to_f:
297
+ source: c
298
+ cfunc: nurat_to_f
299
+ arity: 0
300
+ defined_at: references/ruby/rational.c:2794
301
+ c_body_at: references/ruby/rational.c:1607
302
+ c_effects: []
303
+ purity: leaf
304
+ rbs:
305
+ - "() -> Float"
306
+ rbs_at: references/rbs/core/rational.rbs:436
307
+ to_r:
308
+ source: c
309
+ cfunc: nurat_to_r
310
+ arity: 0
311
+ defined_at: references/ruby/rational.c:2795
312
+ c_body_at: references/ruby/rational.c:1622
313
+ c_effects: []
314
+ purity: leaf
315
+ rbs:
316
+ - "() -> Rational"
317
+ rbs_at: references/rbs/core/rational.rbs:463
318
+ rationalize:
319
+ source: c
320
+ cfunc: nurat_rationalize
321
+ arity: -1
322
+ defined_at: references/ruby/rational.c:2796
323
+ c_body_at: references/ruby/rational.c:1756
324
+ c_effects: []
325
+ purity: leaf
326
+ rbs:
327
+ - "(?Numeric eps) -> Rational"
328
+ rbs_at: references/rbs/core/rational.rbs:380
329
+ hash:
330
+ source: c
331
+ cfunc: nurat_hash
332
+ arity: 0
333
+ defined_at: references/ruby/rational.c:2798
334
+ c_body_at: references/ruby/rational.c:1803
335
+ c_effects: []
336
+ purity: leaf
337
+ rbs:
338
+ - "() -> Integer"
339
+ rbs_at: references/rbs/core/rational.rbs:298
340
+ to_s:
341
+ source: c
342
+ cfunc: nurat_to_s
343
+ arity: 0
344
+ defined_at: references/ruby/rational.c:2800
345
+ c_body_at: references/ruby/rational.c:1833
346
+ c_effects: []
347
+ purity: leaf
348
+ rbs:
349
+ - "() -> String"
350
+ rbs_at: references/rbs/core/rational.rbs:475
351
+ inspect:
352
+ source: c
353
+ cfunc: nurat_inspect
354
+ arity: 0
355
+ defined_at: references/ruby/rational.c:2801
356
+ c_body_at: references/ruby/rational.c:1849
357
+ c_effects: []
358
+ purity: leaf
359
+ rbs:
360
+ - "() -> String"
361
+ rbs_at: references/rbs/core/rational.rbs:310
362
+ singleton_methods: {}
363
+ undefined:
364
+ - allocate
365
+ - new
@@ -1556,6 +1556,15 @@ classes:
1556
1556
  - "(untyped object) -> String?"
1557
1557
  rbs_at: references/rbs/core/string.rbs:980
1558
1558
  undefined: []
1559
+ UnicodeNormalize:
1560
+ parent: Module
1561
+ defined_at: references/ruby/string.c:12943
1562
+ includes: []
1563
+ constants: {}
1564
+ aliases: {}
1565
+ instance_methods: {}
1566
+ singleton_methods: {}
1567
+ undefined: []
1559
1568
  Symbol:
1560
1569
  parent: Object
1561
1570
  defined_at: references/ruby/string.c:12956
@@ -125,8 +125,9 @@ classes:
125
125
  arity: 0
126
126
  defined_at: references/ruby/time.c:5997
127
127
  c_body_at: references/ruby/time.c:4196
128
- c_effects: []
129
- purity: leaf
128
+ c_effects:
129
+ - mutate
130
+ purity: mutates_self
130
131
  rbs:
131
132
  - "() -> Time"
132
133
  rbs_at: references/rbs/core/time.rbs:1037
@@ -136,8 +137,9 @@ classes:
136
137
  arity: 0
137
138
  defined_at: references/ruby/time.c:5998
138
139
  c_body_at: references/ruby/time.c:4196
139
- c_effects: []
140
- purity: leaf
140
+ c_effects:
141
+ - mutate
142
+ purity: mutates_self
141
143
  rbs:
142
144
  - "() -> Time"
143
145
  rbs_at: references/rbs/core/time.rbs:1573
data/lib/rigor/cli.rb CHANGED
@@ -28,7 +28,7 @@ module Rigor
28
28
  new(argv.dup, out: out, err: err).run
29
29
  end
30
30
 
31
- def initialize(argv, out:, err:)
31
+ def initialize(argv = ARGV.dup, out: $stdout, err: $stderr)
32
32
  @argv = argv
33
33
  @out = out
34
34
  @err = err
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `Comparable` module catalog. Singleton — load once.
9
+ #
10
+ # `Comparable` is a Ruby module, not a class, so the
11
+ # catalog is NOT routed through
12
+ # `MethodDispatcher::ConstantFolding::CATALOG_BY_CLASS`
13
+ # (which dispatches on the receiver's concrete class).
14
+ # The data is consumed by future include-aware lookup —
15
+ # see `docs/CURRENT_WORK.md` for the planned slice.
16
+ COMPARABLE_CATALOG = MethodCatalog.new(
17
+ path: File.expand_path(
18
+ "../../../../data/builtins/ruby_core/comparable.yml",
19
+ __dir__
20
+ ),
21
+ mutating_selectors: {
22
+ "Comparable" => Set[]
23
+ }
24
+ )
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `Complex` catalog. Singleton — load once, consult during
9
+ # dispatch.
10
+ #
11
+ # `Complex` is a fully-immutable value type in Ruby: once a
12
+ # complex number is constructed (via `Complex(real, imag)` or
13
+ # `Complex.rect` / `Complex.polar`) its `real` and `imag` slots
14
+ # are never rewritten. Every public instance method either
15
+ # returns `self` unchanged or builds a fresh `Complex` /
16
+ # `Numeric`. The C-body classifier already correctly flags the
17
+ # four `:dispatch` methods (`<=>`, `to_s`, `inspect`,
18
+ # `rationalize`) so there are no false-positive `:leaf`
19
+ # entries to override. The blocklist therefore carries only
20
+ # the conventional `:initialize_copy` defence-in-depth entry
21
+ # so a hypothetical future `Constant<Complex>` carrier cannot
22
+ # fold an aliasing copy through the catalog (mirrors
23
+ # `range_catalog.rb`, `time_catalog.rb`, `date_catalog.rb`).
24
+ COMPLEX_CATALOG = MethodCatalog.new(
25
+ path: File.expand_path(
26
+ "../../../../data/builtins/ruby_core/complex.yml",
27
+ __dir__
28
+ ),
29
+ mutating_selectors: {
30
+ "Complex" => Set[
31
+ # Defence in depth: `Complex` does not currently expose
32
+ # a public `initialize_copy`, but blocking it keeps the
33
+ # convention identical to every other catalog so future
34
+ # CRuby additions cannot leak a copy-mutator through.
35
+ :initialize_copy
36
+ ]
37
+ }
38
+ )
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `Date` and `DateTime` live in CRuby's bundled `date` gem, which
4
+ # is stdlib rather than core — so the constants are not visible
5
+ # until `date` is required. The dispatcher's `CATALOG_BY_CLASS`
6
+ # table references `Date` and `DateTime` at load time, so requiring
7
+ # the gem here (alongside the loader file that exports the catalog)
8
+ # keeps the wiring self-contained: a consumer that pulls in the
9
+ # constant-folding rule book gets the Date constants for free.
10
+ require "date"
11
+
12
+ require_relative "method_catalog"
13
+
14
+ module Rigor
15
+ module Inference
16
+ module Builtins
17
+ # `Date` / `DateTime` catalog. Singleton — load once, consult
18
+ # during dispatch.
19
+ #
20
+ # `Date` and `DateTime` both come from CRuby's bundled `date`
21
+ # gem (`references/ruby/ext/date/date_core.c`). A single
22
+ # `Init_date_core` function registers them, so the catalog
23
+ # carries both classes — `Date` plus the `DateTime` subclass
24
+ # whose own Init block extends with `hour` / `min` /
25
+ # `strftime` / `iso8601` etc. The Ruby-side prelude
26
+ # (`lib/date.rb`) only contributes `Date#infinite?` and the
27
+ # nested `Date::Infinity` class; the bulk of the surface is
28
+ # in C.
29
+ #
30
+ # Date / DateTime receivers are not lifted to a `Constant`
31
+ # carrier today (there is no Date literal node — the closest
32
+ # is `Date.today` / `Date.parse(...)`, which produce
33
+ # `Nominal[Date]`). The catalog wiring therefore mostly
34
+ # governs:
35
+ #
36
+ # 1. The Integer-typed reader surface (`#year`, `#month`,
37
+ # `#day`, `#wday`, `#hour`, `#min`, `#sec`) — RBS-declared
38
+ # `Integer` is preserved through dispatch.
39
+ # 2. The blocklist below, which keeps mutator-style methods
40
+ # that the C-body classifier already flagged
41
+ # (`mutates_self`) from being missed by a future
42
+ # `Constant<Date>` carrier, plus a defensive
43
+ # `:initialize_copy` entry for symmetry with the other
44
+ # catalogs.
45
+ #
46
+ # The non-bang `#next_day` / `#prev_day` / `#next_month` /
47
+ # `#prev_month` / `#next_year` / `#prev_year` / `#>>` / `#<<`
48
+ # selectors all RETURN brand-new `Date` objects rather than
49
+ # mutating the receiver — they intentionally stay
50
+ # catalog-eligible. The two real mutators
51
+ # (`#initialize_copy`, `#marshal_load`) are already classified
52
+ # `:mutates_self` by the C-body regex, so they fall out of
53
+ # `MethodCatalog#safe_for_folding?` without an explicit
54
+ # blocklist entry; the entries below are defense-in-depth
55
+ # against indirect mutators the regex might miss in a future
56
+ # CRuby bump.
57
+ DATE_CATALOG = MethodCatalog.new(
58
+ path: File.expand_path(
59
+ "../../../../data/builtins/ruby_core/date.yml",
60
+ __dir__
61
+ ),
62
+ mutating_selectors: {
63
+ "Date" => Set[
64
+ # `d_lite_initialize_copy` is already classed
65
+ # `:mutates_self` by the regex (it calls
66
+ # `rb_check_frozen` and rewrites the receiver's
67
+ # internal `dat` slots). Listed here for symmetry with
68
+ # String / Array / Range / Set / Time and to keep the
69
+ # blocklist self-documenting.
70
+ :initialize_copy,
71
+ # `d_lite_fill` is a `#ifndef NDEBUG` debug method that
72
+ # warms the receiver's cached `simple` / `complex`
73
+ # fields via the `get_s_*` / `get_c_*` macros. The
74
+ # macros perform in-place writes on the receiver's
75
+ # internal `dat` struct but use no helper the C-body
76
+ # regex recognises, so the classifier mis-flags it
77
+ # `:leaf`. Blocked so a future `Constant<Date>` carrier
78
+ # never folds it.
79
+ :fill
80
+ ],
81
+ "DateTime" => Set[
82
+ # `DateTime` inherits the bulk of its surface from
83
+ # `Date`. The dedicated DateTime-side methods are all
84
+ # readers (`hour`, `min`, …) plus formatting
85
+ # converters (`strftime`, `iso8601`, …); none mutate
86
+ # the receiver. The single defensive entry mirrors the
87
+ # Date side so that the inherited
88
+ # `Date#initialize_copy` (registered against
89
+ # `cDateTime` through subclassing) cannot fold through
90
+ # the catalog if a future `Constant<DateTime>` carrier
91
+ # ever lands.
92
+ :initialize_copy
93
+ ]
94
+ }
95
+ )
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `Enumerable` module catalog. Singleton — load once.
9
+ #
10
+ # `Enumerable` is a Ruby module, not a class, so the
11
+ # catalog is NOT routed through
12
+ # `MethodDispatcher::ConstantFolding::CATALOG_BY_CLASS`
13
+ # (which dispatches on the receiver's concrete class).
14
+ # The data is consumed by future include-aware lookup —
15
+ # see `docs/CURRENT_WORK.md` for the planned slice.
16
+ ENUMERABLE_CATALOG = MethodCatalog.new(
17
+ path: File.expand_path(
18
+ "../../../../data/builtins/ruby_core/enumerable.yml",
19
+ __dir__
20
+ ),
21
+ mutating_selectors: {
22
+ "Enumerable" => Set[]
23
+ }
24
+ )
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `Pathname` catalog. Singleton — load once, consult during
9
+ # dispatch.
10
+ #
11
+ # TODO(blocklist curation): read
12
+ # `data/builtins/ruby_core/pathname.yml` and add per-method
13
+ # blocklist entries for any `:leaf` classifications that are
14
+ # actually mutators or otherwise unsafe to fold. Each entry
15
+ # SHOULD carry a one-line comment naming the indirect mutator
16
+ # helper that triggered the false positive (see
17
+ # `string_catalog.rb`, `array_catalog.rb`, `time_catalog.rb`
18
+ # for the canonical shape).
19
+ PATHNAME_CATALOG = MethodCatalog.new(
20
+ path: File.expand_path(
21
+ "../../../../data/builtins/ruby_core/pathname.yml",
22
+ __dir__
23
+ ),
24
+ mutating_selectors: {
25
+ "Pathname" => Set[
26
+ # initialize_copy is blocklisted by convention so a
27
+ # hypothetical future `Constant<Pathname>` carrier
28
+ # cannot fold an aliasing copy through the catalog.
29
+ :initialize_copy
30
+ ]
31
+ }
32
+ )
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_catalog"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module Builtins
8
+ # `Rational` catalog. Singleton — load once, consult during
9
+ # dispatch.
10
+ #
11
+ # Rational is fully immutable: numerator / denominator slots
12
+ # are written once during `nurat_s_new_internal` and the C
13
+ # body never reaches for `rb_check_frozen`. Every catalog
14
+ # entry classifies cleanly (`:leaf`, `:leaf_when_numeric`,
15
+ # or `:dispatch` for the two methods that delegate into
16
+ # user-redefinable `==` / `Float()` — `nurat_eqeq_p` and
17
+ # `nurat_fdiv`). Bang-suffixed mutators do not exist on
18
+ # Rational.
19
+ #
20
+ # The blocklist therefore stays minimal. `initialize_copy`
21
+ # is added defensively (mirrors Range / Set) so a
22
+ # hypothetical future `Constant<Rational>` carrier cannot
23
+ # fold an aliasing copy through the catalog and surface a
24
+ # shared mutable handle.
25
+ RATIONAL_CATALOG = MethodCatalog.new(
26
+ path: File.expand_path(
27
+ "../../../../data/builtins/ruby_core/rational.yml",
28
+ __dir__
29
+ ),
30
+ mutating_selectors: {
31
+ "Rational" => Set[
32
+ :initialize_copy
33
+ ]
34
+ }
35
+ )
36
+ end
37
+ end
38
+ end