Log in
docs/promote-mode-plan.md 399 lines · 45.6 KB

--int-overflow=promote ๅฎŒๅ…จๅ‹•ไฝœ่จˆ็”ป

ใ‚ดใƒผใƒซ

SPINEL_INT_OVERFLOW=promote (-DSP_INT_OVERFLOW_MODE_PROMOTE) ใง:

  • make test ๅ…จ pass
  • make bench ๅ…จ pass
  • make optcarrot PASS + checksum 59662 (Makefile ใ‹ใ‚‰ --int-overflow=wrap pin ้™คๅŽป)

็พ็Šถ (master HEAD, 2026-06-19 ๅ†่จˆๆธฌ โ€” ๆ—ง bc7e1a1 ่กจใฏ obsolete)

Targetpromote ็ตๆžœ
make test SPINEL_INT_OVERFLOW=promote(front-end ใ‚‚ cc ใ‚‚ promote driven)966/966 pass
make bench ็›ธๅฝ“57/57 pass
optcarrot (-DSP_INT_OVERFLOW_MODE_PROMOTE)ใ‚ณใƒณใƒ‘ใ‚คใƒซๆˆๅŠŸ + checksum 59662

โ†’ 5ๆœˆใฎ error ใƒใ‚ฑใƒƒใƒˆ(bit-ops/index/FFI ็ญ‰ใ€optcarrot 72 errors)ใฏ ๆ—ขใซๅ…จใฆ่งฃๆถˆๆธˆใฟใ€‚ๅขƒ็•Œๅค‰ๆ›ใฏๅฎŸ่ฃ…ๆธˆใฟใ€‚default gate(966 + optcarrot 59662 + bench 57)ใฏ g_promote_mode gate ใซใ‚ˆใ‚Šไธๅค‰ใ€‚

้€ฒๆ— (2026-06-19)

  • bigint **/<</>> ใฎใ‚ณใƒผใƒ‰็”Ÿๆˆใƒใ‚ฐไฟฎๆญฃ(92e8d6dc): ** ใฏ codegen ๆœช้…็ทšใง int path ใซ่ฝใกใ€shift ใฏ TY_BIGINT ๆŽจ่ซ–ใ•ใ‚Œใš "unsupported call"ใ€‚runtime ใฎ sp_bigint_shl/shr ใ‚‚ to_int ใง 64bit ใซ truncate ใ—ใฆใ„ใŸใ€‚3 ๆผ”็ฎ—ใจใ‚‚ไปปๆ„็ฒพๅบฆใซใ€‚
  • ใƒ–ใƒญใƒƒใ‚ฏใƒซใƒผใƒ—่“„็ฉใฎ bigint ๆ˜‡ๆ ผ(9295160d): infer_bigint_loop_locals ใ‚’ times/each/upto/downto/step/loop/each_with_index ใƒ–ใƒญใƒƒใ‚ฏใซๆ‹กๅผต(g_promote_mode gate)ใ€‚f=1; 25.times{|i| f=f*(i+1)} ใŒ promote ใง MRI ไธ€่‡ดใ€‚ไป˜้šใ—ใฆ emit_op_assign ใฎ captured-cell path ใŒ int ๅฐ‚็”จใ ใฃใŸใƒใ‚ฐ(bigint cell ใซ sp_int_mul ใง truncate)ใ‚’ไฟฎๆญฃใ€‚
  • Makefile promote ใƒ†ใ‚นใƒˆ้…็ทš: make test SPINEL_INT_OVERFLOW=promote ใŒ front-end ใซ --int-overflow=promoteใ€cc ใซ -D...PROMOTE ใ‚’ๆธกใ™ใ‚ˆใ†ใซ(ไปฅๅ‰ใฏ test list ใ‚’ filter ใ™ใ‚‹ใ ใ‘=promote codegen path ๆœชๆคœ่จผ)ใ€‚promote-only ใƒ†ใ‚นใƒˆใฏ test/promote_*.rb ๅ‘ฝๅใง raise/wrap ใ‹ใ‚‰้™คๅค–ใ€‚promote ๅ…จ suite 966/0/0ใ€‚

ๆฎ‹ใ‚‹ๆœฌ่ณช็š„ gap (2026-06-19 ๆ›ดๆ–ฐ)

ๆ˜‡ๆ ผๆฉŸๆง‹ใฏ g_promote_mode ไธ‹ใฎ infer_bigint_loop_locals(while + block loop ใฎ self-ref multiply ๆคœๅ‡บ)ใ€‚runtime macro ใซใฏ promote arm ใŒ็„กใ„(sp_int_add ใฏ overflow ใง raise)ใฎใงใ€้™็š„ใซ "็„ก้™ๅข—ๆฎ–" ใจๅˆคๅฎšใงใใ‚‹ local ใ ใ‘ใŒ bigint ๅŒ–ใ•ใ‚Œใ‚‹ใ€‚

ๆฎ‹ใ‚Š raise ใซใชใ‚‹ใƒ‘ใ‚ฟใƒผใƒณ:

  • ้–ขๆ•ฐๅผ•ๆ•ฐ็ตŒ็”ฑ(def mul(x,y)=x*y; mul(10**15,10**15))= ้™็š„ๆคœๅ‡บใฏๅŽŸ็†็š„ใซไธๅฏ่ƒฝใ€‚runtime promote ใŒ่ฆใ‚‹=legacy ใฎๅ…จ intโ†’bigint widen(ไธ‹่จ˜ใ€ŒๅฎŒๆˆ่ทฏใ€)ใ€‚ใ“ใ‚ŒใŒๆœ€ๅพŒใฎๆœฌไธธใ€‚
  • ใƒชใƒ†ใƒฉใƒซ็ดฏไน— / bigint ใƒชใƒ†ใƒฉใƒซ(10**30, 100000000000000000000)โ†’ INT_MAX ใซ้ฃฝๅ’Œใ€‚AST ใŒ int64 ๅ€คใ—ใ‹ไฟๆŒใ—ใชใ„(IntegerNode "value" ใŒ int)ใฎใง parser ๆฎตใง decimal ๆ–‡ๅญ—ๅˆ—ใ‚’ไฟๆŒใ™ใ‚‹ๅˆฅ feature ใŒ่ฆใ‚‹ใ€‚promote ๆฉŸๆง‹ใจใฏ็‹ฌ็ซ‹ใ€‚
  • +/<< ใฎๅ˜็ด”่“„็ฉ(*/** ใฎใฟ self-ref ๆคœๅ‡บๅฏพ่ฑก)ใ€‚

ๆ—ข็Ÿฅใฎๅ‘จ่พบใƒใ‚ฐ(promote ็„ก้–ขไฟ‚ใƒปdefault ใงใ‚‚ๅ†็พ): 1.upto(N){ ... } ใฎ no-block-param ใƒ–ใƒญใƒƒใ‚ฏใŒ body ใ‚’ drop(h=0; 1.upto(5){h+=1}; puts h โ†’ 0)ใ€‚upto codegen ใฎๅˆฅไปถใ€‚

ๆŽก็”จๆ–น้‡: poly-based(SP_TAG_BIGINT)โ€” 2026-06-19 matz ๆฑบๅฎš

legacy ใฎใ€Œๅ…จ int โ†’ bigint widenใ€ใงใฏใชใใ€poly ๅ€ค(sp_RbVal)ใซ bigint ใ‚’่ผ‰ใ›ใ‚‹ๆ–นๅ‘ใ‚’ๆŽก็”จ(matz ๅˆคๆ–ญ)ใ€‚็†็”ฑ: (a) SP_TAG_BIGINT ่ฟฝๅŠ ใฏ promote ใจ็„ก้–ขไฟ‚ใซ็•ฐ็จฎใ‚ณใƒณใƒ†ใƒŠ/ใƒชใƒ†ใƒฉใƒซ bug ใ‚’็›ดใ™็‹ฌ็ซ‹ไพกๅ€คใŒใ‚ใ‚‹ใ€(b) ๅฐใ•ใ„ int ใฏ unbox ใฎใพใพ=Ruby ใฎ fixnumโ†’bignum ใจๅŒใ˜ใง legacy ๅ…จ bigint ใ‚ˆใ‚ŠๅฎŸ็”จ็š„ใ€(c) ใ‚ณใ‚ขๆŠ•่ณ‡ใ‚’ bug ไฟฎๆญฃใจๅ…ฑๆœ‰ใ€‚

้€ฒๆ—(landed)

  • Increment 1 (ce6995c8): SP_TAG_BIGINT(v.p=GC bigint)ใ€‚sp_box_bigint + emit_boxed/unbox ใฎ TY_BIGINT arm + GC mark + poly consumer ๅ…จ arm(puts/to_s/inspect/class_name/to_i/to_f/numeric_p/eq/cmp/hash-key)+ codegen emit_bigint_operand(poly operand ใ‚’ sp_poly_as_bigint ใง narrow)ใ€‚โ†’ [1,"x",big] / {k:big} / bigint hash-key ๅ‹•ไฝœใ€‚clang+ASAN ๆคœ่จผใ€‚
  • Increment 2a (48863f34): sp_poly_add/sub/mul ใŒ bigint operand ใ‚’ bigint ๆผ”็ฎ—ใธ(ๅ…จใƒขใƒผใƒ‰ใ€bigint+intโ†’0 bug ไฟฎๆญฃ)+ promote ใง int+int overflowโ†’bigint ๆ˜‡ๆ ผ(SP_INT_OVERFLOW_MODE_PROMOTE #ifdef gateใ€default/wrap ใฏ wrap ็ถญๆŒ)ใ€‚โ†’ ๆ—ขใซ poly ๅž‹ใฎๅ€คใฏ promote ใง runtime ๆ˜‡ๆ ผใ™ใ‚‹ใ€‚

ๆฎ‹: Increment 2b(ๆœฌไธธ big-bang)= intโ†’poly widen under promote

ๆ—ขใซ poly ใชๅ€คใฏ 2a ใงๆ˜‡ๆ ผใ™ใ‚‹ใŒใ€้–ขๆ•ฐๅผ•ๆ•ฐใชใฉ้™็š„ใซ int ใช slot ใฏ poly ใงใชใ„ใฎใง overflow ใ—ใฆใ‚‚ๆ˜‡ๆ ผใงใใชใ„ใ€‚ๆœ€ๅพŒใฎๅฑฑใฏ promote ใƒขใƒผใƒ‰ใง่ฉฒๅฝ“ int slot ใ‚’ poly ใซ widenใ™ใ‚‹ analyze ๅค‰ๆ›ดใ€‚widen ๅ…ˆใŒ bigint(legacy)ใงใชใ poly ใช็‚นใŒ้•ใ„: ๅฐใ•ใ„ๅ€คใฏ unbox ใฎใพใพใ€overflow ๆ™‚ใ ใ‘ 2a ใฎๆฉŸๆง‹ใง boxใ€‚

2026-06-19 ่ฉฆ่กŒใฎ็Ÿฅ่ฆ‹(revert ๆธˆใ€master ใฏ 2a ใฎ promote 972 ใฎใพใพ):

  • promote_widen_arith_params(analyze.c ใฎ re-narrow ๅพŒ hook): def ใƒกใ‚ฝใƒƒใƒ‰ param ใฎใ†ใก +/-/*/** ใฎ็›ดๆŽฅ operand ใ‚’ poly ๅŒ–(block paramใƒป้ž DefNode scope ใฏ้™คๅค–)โ†’ c2 = def mul(x,y)=x*y; mul(10^12,10^12) ใŒ 1e24 ใงๅ‹•ใ„ใŸ(MRI ไธ€่‡ด)ใ€‚
  • ใ—ใ‹ใ— promote suite ใŒ **972โ†’947(25 err/3 fail)**ใซ้€€่กŒใ€‚้€€่กŒใฎๆœฌ่ณช: codegen ใฏๅž‹ไธ€่‡ดใ‚’ๅ‰ๆใซ coercion ใ‚’ๆŒฟๅ…ฅใ—ใชใ„ใฎใงใ€widen ใ—ใŸ poly param ใŒ int slot ใซๅ‡บไผšใ†ๆ‰€ใŒๅ…จ้ƒจๅขƒ็•ŒๅŒ–:
    • mrb_int = sp_RbVal(poly param โ†’ int local / cvar ไปฃๅ…ฅใ€ไธกๆ–นๅ‘)
    • yield x ใง poly ใ‚’ int block param ใธ(n = poly)
    • sp_double(poly)(ๅˆฅใƒกใ‚ฝใƒƒใƒ‰ๅ‘ผใณใฎ int param ใธ coercion ็„กใ—)
    • mrb_int == sp_RbVal(ๆฏ”่ผƒ)/ cvar init ใŒ้žๅฎšๆ•ฐ
  • ไผๆ’ญ pass ใ‚’ๅข—ใ‚„ใ™(infer_block_params/ivar/cvar/param/return ใ‚’ post-widen ใงๅ›žใ™)ใจๅขƒ็•ŒใŒใšใ‚Œใ‚‹ใ ใ‘(whack-a-mole)ใ€‚
  • ็ต่ซ–: 2b ใฏใ€Œๅ…จ polyโ†”int ๅขƒ็•Œ site ใง coercion ใ‚’ๆŒฟๅ…ฅใ™ใ‚‹ codegen sweepใ€(ไปฃๅ…ฅไธกๆ–นๅ‘ / yield / call-arg / ๆฏ”่ผƒ / cvar)ใ‚’่ฆใ™ใ‚‹็œŸใฎ big-bangใ€‚ๅฐ‚็”จใ‚ปใƒƒใ‚ทใƒงใƒณใงๅขƒ็•Œใƒใ‚ฑใƒ„ใ‚’ 1 ใคใšใคใ€‚ใ‚ใ‚‹ใ„ใฏ sound ใช uniform widen(ๅ…จ intโ†’poly + ๅขƒ็•Œ coercion ๅฎŒๅ‚™)ใ€‚c2 ใŒๅ‹•ใไบ‹ใฏ็ขบ่ชๆธˆใฟใชใฎใงๆ–นๅผ่‡ชไฝ“ใฏๆญฃใ—ใ„ใ€ๆฎ‹ใ‚Šใฏๅขƒ็•Œ็ถฒ็พ…ใ€‚

2026-06-19 ็ฌฌ2่ฉฆ่กŒ(ไฟๅฎˆ gate ๆ–นๅผใƒปrevert ๆธˆใ€master=2a ใฎ 972): ไฟๅฎˆ gate ใ‚’้‡ใญใฆ้ž้€€่กŒใ‚’็‹™ใฃใŸใŒๅŽๆŸใ›ใšใ€ๆ นๆœฌ ripple ใ‚’็‰นๅฎš:

  • ๅฎŸ่ฃ…ใ—ใŸ gate: (1) DefNode ใƒกใ‚ฝใƒƒใƒ‰ใฎใฟใƒปblock param ้™คๅค–ใ€(2)scan_param_use=param ใฎๅ…จ read ใŒ +/-/*/** ใฎ็›ดๆŽฅ operandใฎๆ™‚ใฎใฟ widen(yield/call-arg/index/ๆฏ”่ผƒ/ไปฃๅ…ฅใซ1ใคใงใ‚‚ๅ‡บใŸใ‚‰ไธๅฏ)ใ€(3)method(:sym) ใง address-taken ใชใƒกใ‚ฝใƒƒใƒ‰ใฏ้™คๅค–ใ€(4)ไผๆ’ญใฏ infer_write_types+infer_return_types ใฎใฟ(full re-run ใฏ็„ก้–ขไฟ‚ slot ใ‚’ๆ’นไนฑ)ใ€‚
  • ใ“ใ‚Œใง block2/method/i960/bound_method ็ณปใฏ็ท‘ใ€c2 ็ถญๆŒใ€‚ใ ใŒ pattern_pin/class_var_read/proc ็ญ‰ใŒๆฎ‹ๅญ˜ใ€‚
  • ๆ นๆœฌๅŽŸๅ›  = return-type ripple: param ใ‚’ poly ๅŒ–ใ™ใ‚‹ใจ arith ็ตๆžœ=ใƒกใ‚ฝใƒƒใƒ‰ๆˆปใ‚Šๅ€คใŒ poly ๅŒ–ใ—ใ€ใใฎๆˆปใ‚Šๅ€คใ‚’ int ๆ–‡่„ˆใงๆถˆ่ฒปใ™ใ‚‹ๅ…จ caller ใŒๅฃŠใ‚Œใ‚‹:
    • ^(double(7)) pin ๆฏ”่ผƒ(mrb_int == sp_RbVal)
    • x = double(7)(int local ใธ)/ @@total = @@total + n(int cvar ใธใ€static init ้žๅฎšๆ•ฐใ‚‚)
    • &blk ใƒกใ‚ฝใƒƒใƒ‰ใฎ signature ไธไธ€่‡ด(undefined reference to sp_with_logging)
  • polyโ†’int coercion ใงๆถˆใ™ๆกˆใฏ promote ใ‚’ๅฐ็„กใ—(ๆ˜‡ๆ ผๅ€คใ‚’ truncate)ใ€‚ๆญฃ่งฃใฏๆถˆ่ฒป slot ๅดใ‚‚ poly ใซ widen(=full propagation)+ codegen ใŒ poly ้žๅฏพๅฟœใช site(cvar static init / pin)ใ‚’ coerceใ€‚
  • = caller call-site ใฎ tolerance ่งฃๆž ใ‹ whole-program coercion sweep ใŒๅฟ…้ ˆใ€‚gate ใ ใ‘ใงใฏใ€Œ็ตๆžœใŒ puts ็ญ‰ poly-tolerant ๆ–‡่„ˆใงใ—ใ‹ๆถˆ่ฒปใ•ใ‚Œใชใ„ใƒกใ‚ฝใƒƒใƒ‰ใ€ใพใง็ตžใ‚‰ใชใ„ใจ้ž้€€่กŒใซใงใใšใ€ใใ‚Œใฏ c2 ็ดšใ—ใ‹ๆฎ‹ใ‚‰ใชใ„ใ€‚
  • ๆฌกใ‚ปใƒƒใ‚ทใƒงใƒณๆŒ‡้‡: (A) full propagation ใ‚’ๅ…ฅใ‚Œใ€sur้ขๅŒ–ใ™ใ‚‹ codegen site ใ‚’ 1 ใคใšใค coerce(cvar poly init / pin poly ๆฏ”่ผƒ / ๅ„ int-consume ใ‚’ poly widen)ใ€‚(B) ใพใŸใฏ call-site tolerance gate(ๆˆปใ‚Šๅ€คใŒ int ๆ–‡่„ˆใงๆถˆ่ฒปใ•ใ‚Œใ‚‹ใƒกใ‚ฝใƒƒใƒ‰ใฏ widen ใ—ใชใ„)ใ‚’ๅฎŸ่ฃ…ใ€‚่ฉฆ่กŒใ‚ณใƒผใƒ‰ใฏ git ๅฑฅๆญด(ๆœฌ commit ็›ดๅ‰)ใซ็„กใ—=revert ๆธˆใ€ๆœฌ็ฏ€ใŒๅฎŒๅ…จใชๅ†็พๆ‰‹้ †ใ€‚

2026-06-20 ็ฌฌ3่ฉฆ่กŒ ็ถš่กŒ = ๅขƒ็•Œ site ใฎๆจชๅฑ•้–‹ใง 831โ†’859(+28)ใ€4 commitใ€default 992/0/0 ็ถญๆŒ: full intโ†’poly widen pass(79709207)ใ‚’ๅœŸๅฐใซใ€ERR(=C compile fail ใฎๅขƒ็•Œ coercion gap)ใ‚’ emission-site ๅ˜ไฝใงๆฝฐใ—ใŸใ€‚ๅ„ fix ใฏ poly slot ใ‚’ๆคœๅ‡บใ—ใŸใ‚‰ rvalue ใ‚’ emit_boxed(node ็‰ˆ)/emit_boxed_text(ๅž‹+ใƒ†ใ‚ญใ‚นใƒˆ็‰ˆ)ใง box ใ™ใ‚‹ๅ˜ไธ€ใƒ‘ใ‚ฟใƒผใƒณใ€‚ใ€Œ้€ๆฌก commit ใฏ็ท‘ใ‚’ๅข—ใ‚„ใ•ใชใ„ใ€ใจใ„ใ†ๅ‰ๅ›žใฎๆ‚ฒ่ฆณใฏ่ชคใ‚Šใงใ€ๅ˜ไธ€ site ใฎใƒใ‚ฑใƒ„(cvar static / instance_exec / range.each)ใฏ็›ดๆŽฅ่ค‡ๆ•ฐใƒ†ใ‚นใƒˆใ‚’ๅ›žๅพฉใ—ใŸ(ใƒžใƒซใƒๅขƒ็•Œใƒ†ใ‚นใƒˆใ ใ‘ใŒๆจชไธฆใณไพๅญ˜)ใ€‚

  • cvar static init(298a0e56, +2): static sp_RbVal cvar = default_value(TY_POLY) ใŒ sp_box_nil()(้–ขๆ•ฐๅ‘ผใณ=้žๅฎšๆ•ฐๅˆๆœŸๅŒ–ๅญ)ใ€‚{SP_TAG_NIL,0,{0}} ๅฎšๆ•ฐ aggregate ใ‚’ emit(civ ใจๅŒใƒ‘ใ‚ฟใƒผใƒณ)ใ€‚default ใฎ genuine-poly cvar ใฎ latent bug ใ‚‚่งฃๆถˆใ€‚codegen.c:2742ใ€‚

  • instance_exec/instance_eval block-param(dbc46864, +16): lifted block ใฎ lv_<param> = <arg> ๆŸ็ธ›ใŒ int arg ใ‚’ poly slot ใธใ€‚numbered/requireds(็›ดๆŽฅ argใƒปauto-splat ่ฆ็ด ใƒปtrampoline arg)/keyword ใฎ 4 ็ตŒ่ทฏใง slot poly ใชใ‚‰ emit_boxedใ€‚codegen_call.c:5268+ใ€‚

  • (a..b).each fusion(07e55f26, +3): loop var ใ‚’ int ็›ด้ง†ๅ‹•ใ€‚poly counter ใฏ fresh mrb_int ใง้ง†ๅ‹•ใ—ๆฏŽ iter lv_i=sp_box_int(_tc)(emit_for ใจๅŒใƒ‘ใ‚ฟใƒผใƒณ)ใ€‚codegen_call.c:10749ใ€‚

  • masgn target boxing(694f3f89, +7): scalar-RHS local(+typed-zero rest default)/tuple-element localใƒปcvar/typed-array destructure get/trailing rights get ใ‚’ boxใ€‚codegen_stmt.cใ€‚

  • leading-splat masgn(91c022ce, +1): *xs, last=[..] ใฎ post-splat fixed target ใ‚’ temp ็ตŒ็”ฑ boxใ€‚splat_destructure ็ท‘ใ€‚codegen_stmt.c:3672ใ€‚(promote 860 ๅˆฐ้”)

  • โ˜…ๆฑบๅฎš็š„ๆดžๅฏŸ: widen pass ใฏ scope->locals[].type/ivar_types/cvar_types ใ ใ‘ๆ›ธใๆ›ใˆใ€node-type cache ใฏๆ›ดๆ–ฐใ—ใชใ„ใ€‚ใ‚†ใˆใซ comp_ntype(c, target_node) ใฏ widen ๅ‰ใฎใ‚นใ‚ซใƒฉๅž‹(int ็ญ‰)ใ‚’่ฟ”ใ™ใ€‚slot ใŒ poly ใ‹ใฏๅฟ…ใš scope_local(scope, name)->type(or ivar/cvar ใฎ type ้…ๅˆ—)ใงๅˆคๅฎšใ™ใ‚‹ใ“ใจใ€‚rvalue ใ‚’ box ใ™ใ‚‹ๅž‹ใฏ comp_ntype(value)(็œŸใฎๅ€คๅž‹)ใงๅ–ใ‚‹ใ€‚ใ“ใฎ non-update ใฎใŠใ‹ใ’ใง rest default ใฎ typed-zero(default_value(int)="0")ใ‚‚ๅพฉๅ…ƒใงใใ€emit_boxed_text(int,"0")=sp_box_int(0) ใง quirk ไธ€่‡ดใ€‚

  • โ˜…block-param widen ้™คๅค–(0ed24068, 860โ†’901ใ€+41!)= ๆœฌใ‚ปใƒƒใ‚ทใƒงใƒณๆœ€ๅคงใฎๅ‹ๅ› : block-param ๅๅพฉ([1,2,3,4].filter_map{|x| x*2 if x.even?})ใฏๆœ€ๅคงใ‚ฐใƒซใƒผใƒ—ใ ใฃใŸใ€‚็œŸๅ› : widen ใฏ block-param ใฎ scope local ใ‚’ poly ๅŒ–ใ™ใ‚‹ใŒใ€block emitter ใฏ use_shadow ใง param ใ‚’ element ๅž‹(int)ใซ retype ใ—ใฆ body ใ‚’ๅ† infer ใ™ใ‚‹ใ€‚ใ ใŒ even? ็ญ‰ใƒกใ‚ฝใƒƒใƒ‰ๅ‘ผใณใฎ inference ใฏ receiver ใ‚’ cache ใ‹ใ‚‰่ชญใ‚€ใ ใ‘ใงๅ† infer ใ—ใชใ„(* ๆผ”็ฎ—ๅญใฏ operand ใ‚’ infer_type ใงๆ›ดๆ–ฐใ™ใ‚‹)ใฎใงใ€x*2=int / x.even?=poly ใซๆททๅœจใ—ใ€mrb_int lv_x shadow ใŒๅค–ๅด sp_RbVal lv_x(widen)ใ‚’ไบŒ้‡ๅฎฃ่จ€ใ€‚่งฃ=block-param ใ‚’ widen ใ‹ใ‚‰้™คๅค–(is_block_param skipใ€analyze.c:2275)ใ€‚block-param ใฏๅๅพฉใ‚ณใƒฌใ‚ฏใ‚ทใƒงใƒณใฎ element ๅž‹ใงๅž‹ไป˜ใในใใงใ€widen ใฏๅฎณใ ใ‘ใ€‚method param ใฏๅผ•ใ็ถšใ widen(promote ใฎๆœฌๆ—จ)ใ€‚compile error ใจไธ€่‡ดใ™ใ‚‹ output-mismatch FAIL ใ‚‚ไธ€ๆŽƒใ€‚ๅฝ“ๅˆใฏใ€Œanalyze ใงๅž‹ใ‚’ไธ€่ฒซ poly ๅŒ–ใ€ใ‚’ๆƒณๅฎšใ—ใŸใŒใ€้€†ใซใ€Œblock-param ใฏ widen ใ—ใชใ„ใ€ใŒๆญฃ่งฃใ ใฃใŸใ€‚

  • polyโ†’scalar unbox(29dbedea, 901โ†’909): block-param ใ‚’ int ใซไฟใฃใŸใ“ใจใงใ€poly source(widen ใ•ใ‚ŒใŸ yield ๅ€คใƒปivarใƒปtrampoline temp)ใ‚’ int block-param ใธๆŸ็ธ›ใ™ใ‚‹้€†ๆ–นๅ‘ใŒๅฟ…่ฆใซใ€‚emit_block_invoke ใฎ yield ๆŸ็ธ› + instance_exec ใฎ is_exec/tramp ๆŸ็ธ›ใซ bt scalar && at poly โ†’ emit_unbox_text arm ใ‚’่ฟฝๅŠ (box arm ใฎๅฏพ็งฐ)ใ€‚yield/forward_args_block/block_forward_*/inlined_yield_self_locals/instance_exec_mixed_args ็ท‘ใ€‚

  • ๆฎ‹ ERR=64 / FAIL=20(/tmp/perr2.txt ใฎๆ‰‹ๆณ•ใงๅ†ๅ–ๅพ—): B4 builtin-arg coerce(~19)= poly arg ใ‚’ builtin ใฎ int/typed param ใธ(sp_bigint_new_int/sp_range_include/sp_str_sub_range(_r)/user <=>=_lt_set_gt/sp_collect_s ็ญ‰ใ€call-arg site ใงๆ•ฃๅœจ coerce)ใ€‚B6 ๆฎ‹(polyโ†’int ไปฃๅ…ฅ)= ใพใ ๆ‹พใ„ๅˆ‡ใ‚Œใฆใชใ„ๆŸ็ธ› siteใ€‚B1 ๆฎ‹(intโ†’poly ไปฃๅ…ฅใ€8)ใ€‚closure capture(front-end, 5)=unsupported closure capturing a non-integer variable(widen ใง capture ๅค‰ๆ•ฐใŒ poly ๅŒ–โ†’closure ใŒ้ž int capture ้žๅฏพๅฟœใ€front-end ๅˆถ้™)ใ€‚ไป–ใซ return mismatch(3)/invalid binary operands(4)/invalid initializer(2)/unsupported p argument(clamp)็ญ‰ใ€‚FAIL=20 ใฏใ‚ณใƒณใƒ‘ใ‚คใƒซ้€šใ‚‹ใŒๅ‡บๅŠ›ๅทฎ(ไพ‹: proc ใŒ proc ๆˆปใ‚Šๅ€คใง 6โ†’0)ใ€ๅˆฅ้€”่ชฟๆŸปใ€‚

  • range/string builtin ใฎ poly arg coerce(17fa2d32, 909โ†’912): sp_range_include(include?/case-as-value/when range-membership ใฎ 3 site)ใจ string slice/index(sp_str_sub_range[_r]/sp_str_char_at_or_nil)ใฎ int ๅผ•ๆ•ฐใ‚’ poly ใฎใจใ sp_poly_to_i(string ๅดใฏ emit_int_expr ใงไธ€ๅพ‹ coerce)ใ€‚range/case/truncate_module_method ็ท‘ใ€‚poly ็ตŒ่ทฏใฎใฟๅค‰ๅŒ–ใ€default ไธๅค‰ใ€‚

  • ่‡ช่ตฐใƒใƒƒใƒ(912โ†’927ใ€+15): masgn/pattern ็ณปใฎ box(pattern-match destructure+captureใ€leading-splatใ€cvar op-assignโ†’sp_poly_<op>+inference ไฟฎๆญฃใ€begin/rescue tail box)+ index/count ๅผ•ๆ•ฐใฎไธ€ๆ‹ฌ emit_int_expr ๅŒ–(array/string indexใƒปfetchใƒปcountใƒปop-assign ใฎ mrb_int _t=<idx> ็ด„25 siteใ€poly ใฎใฟ coerce ใง default ไธๅค‰)+ bigint slot poly ไปฃๅ…ฅโ†’sp_poly_as_bigint + range/string-index builtin ใฎ poly arg coerceใ€‚ๅ„ commit ใฏ g_promote_mode ็ตŒ่ทฏใฎใฟๅค‰ๅŒ–ใ€default 992/0/0 + optcarrot 59662 ็ถญๆŒใ€‚

  • โ˜…็ฝ (่จ˜้Œฒ): emit_tail_value ใฎ g_ret_type==POLY ็„กๆกไปถ box ใฏ explicit-return ็ตŒ่ทฏใจไบŒ้‡ box ใง begin_rescue/forward_args_block ใ‚’ๅ›žๅธฐ(spot-test ใงใฏ PASS ใ ใŒ full-suite ใง็™บ่ฆš)โ†’ revertใ€‚ๅ…ฑๆœ‰ tail/return ็ตŒ่ทฏใฎๅค‰ๆ›ดใฏ full-suite ๅฟ…้ ˆ(spot-test ไธๅฏ)ใ€‚

  • ๆฎ‹ ERR=44 / FAIL=22 ใฎๆง‹้€ ็š„ใƒ–ใƒญใƒƒใ‚ซใƒผ:

    1. proc/closure ใฎ poly ๅฏพๅฟœ(closure-capture ~5 ERR + proc 6โ†’0 ็ญ‰ FAIL)โ€” โ˜…(A) ๅ˜็‹ฌ land ไธๅฏใ‚’ๅฎŸ่จผ(2026-06-21):
      • proc ABI ใฏ่กจ้ข mrb_int ใ ใŒ poly side-channel ใ‚’ๆ—ขใซๆŒใค: _sp_proc_poly_args[16](poly ๅผ•ๆ•ฐ)/_sp_proc_poly_ret(poly ๆˆปใ‚Šๅ€ค)ใ€‚proc ๆœฌไฝ“ใฏ _proc_N(void*_cap, mrb_int argc, mrb_int *args)ใ€‚
      • (A) ใ‚’ๅฎŸ่ฃ…ใƒป่จˆๆธฌ: โ‘ poly capture cell(sp_RbVal *_cell_x + sp_cell_scan_rbval + cap-struct ใƒ•ใ‚ฃใƒผใƒซใƒ‰ sp_RbVal* + proc-capture ๅˆถ้™ใซ poly ่จฑๅฏ)โ‘กproc local ใฎ proc_ret ใ‚‚ widen(ๆœฌไฝ“ scope ใฎ ret ใฏ widen ๆธˆใ ใŒ caller ๅด lv->proc_ret ใŒๆœช widen โ†’ .call ใŒ side-channel ใ‚’่ชญใพใš raw mrb_int=0 ใ‚’่ฟ”ใ™)โ‘ขemit_proc_call_args ใฎ int slot ใซ sp_poly_to_i ๅ…ฌ้–‹(int proc param ใŒ args[k] ใ‚’่ชญใ‚€ใŸใ‚)ใ€‚
      • ๅ€‹ๅˆฅใซใฏ proc_closure / case_local_in_lambda ใŒ PASSใซใชใฃใŸใŒใ€full-suite ใง 927โ†’920(PASS -7, FAIL +9)ใซ็ด”ๆธ›ใ€‚
      • โ˜…็œŸๅ› ใ‚’็ขบๅฎš(2026-06-21 ็ฌฌ2ๆฌก่ชฟๆŸป)= proc_ret ใฎ post-widen fixpoint ไผๆ’ญไธๆ•ดๅˆ(ๅฝ“ๅˆใ€Œside-channel ้žๅ†ๅ…ฅใ€ใจๆŽจๆธฌใ—ใŸใŒ่ชคใ‚Š):
        • .call ใฎ return ่ชญใฟๅ‡บใ—ใฏ proc ใฎ caller-side proc_ret ใง int slot vs _sp_proc_poly_ret ใ‚’ๅˆ†ๅฒใ€‚ใ“ใ‚ŒใŒ proc ๆœฌไฝ“ใฎๅฎŸ emit ret ใจไธ€่‡ดใ—ใชใ„ใจ 0 ใ‚’่ฟ”ใ™ใ€‚
        • ๅคฑๆ•—ๆ–นๅ‘โ‘ (naive widen=ๅ…จ proc_retโ†’poly): ->(a,b){a+b}(a,b ใฏ block-param ้™คๅค–ใง intใ€ๆœฌไฝ“ใฏ return sp_int_add=int return)ใง caller ใŒ side-channel(ๆœช่จญๅฎš)ใ‚’่ชญใฟ 0ใ€‚multi_arg_lambda ็ญ‰ 11 lambda ใŒ้€€่กŒใ€‚
        • ๅคฑๆ•—ๆ–นๅ‘โ‘ก(literal ้™ๅฎšใง proc_ret ๅ†่จˆ็ฎ—=proc_ret_of): multi_arg ใฏ็›ดใ‚‹(ๆœฌไฝ“ intโ†’proc_ret int)ใŒใ€c = make_counter()(ใƒกใ‚ฝใƒƒใƒ‰ใŒ่ฟ”ใ™ proc) ใฏ proc_ret ใŒ make_counter ใฎ ret_proc_ret(ๆœช widen=int)็”ฑๆฅใงใ€literal ใƒซใƒผใƒ—ใŒๅ–ใ‚Šใ“ใผใ— โ†’ proc_closure ใŒๅ†้€€่กŒใ€‚
        • = proc_ret ใฏ่ค‡ๆ•ฐใ‚ตใ‚คใƒˆใฎ fixpoint(x=proc{} analyze_pass.c:1124 / proc param :1218 / method ret_proc_ret :3719 / composeใƒปto_proc)ใ€‚widen ๅพŒใซใ“ใฎ fixpoint ๅ…จไฝ“ใ‚’ๅ†ๅŽๆŸใ•ใ›ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใ€naive widen ใ‚‚้ƒจๅˆ†ๅ†่จˆ็ฎ—ใ‚‚ไธๅฏใ€‚proc_node_ret=ๆœฌไฝ“ๆœ€็ต‚ๅผใฎ infer(analyze_util.c:334)ใ€‚
      • โ˜…โ˜…่งฃๆฑบๆธˆใฟ(ed0c0d68, 927โ†’932, ๅ›žๅธฐ0)= option 1(ABI ๅค‰ๆ›ดไธ่ฆ):
        • โ‘ poly capture cell: sp_RbVal *_cell_x + sp_cell_scan_rbval(sp_gc.h)+ cap-struct ใƒ•ใ‚ฃใƒผใƒซใƒ‰ sp_RbVal*(codegen.c)+ proc-capture ๅˆถ้™ใซ TY_POLY ่จฑๅฏใ€‚read/write ๆ—ขๅญ˜็ตŒ่ทฏใง OK(lvalue deref + emit_assign ใฎ poly box arm)ใ€‚
        • โ‘กargs int-slot ๅ…ฌ้–‹: emit_proc_call_args ใง poly arg ใ‚’ sp_poly_to_i ใง int slot ใซใ‚‚็ฝฎใ(int proc param=block-param ้™คๅค– ใŒ args[k] ใ‚’่ชญใ‚€ใŸใ‚)ใ€‚
        • โ‘ขproc_ret/ret_proc_ret ใฎ post-widen focused fixpoint(analyze.c, finalize infer ใฎๅพŒ):method scope ret_proc_ret(proc_ret_of ใงๆœฌไฝ“ใ‹ใ‚‰)+ x=proc{}/x=factory() ใฎ proc_ret ใ‚’ๅŽๆŸใƒซใƒผใƒ—ใงๅ†ๅฐŽๅ‡บใ€‚proc-return metadata ใฎใฟๆ›ดๆ–ฐใ€widen slot ๅž‹ใฏไธๅค‰ใ€‚
        • โ˜…ๆฑบใ‚ๆ‰‹ = fixpoint ๅพŒใซ for id: infer_type(c,id) ใง node-type cache ใ‚’ๅ†ๆง‹็ฏ‰ใ€‚codegen ใฎ .call ใฏ comp_ntype(call node)(node cache)ใ‚’่ชญใ‚€ใฎใงใ€proc_ret ใ‚’ๆ›ดๆ–ฐใ—ใฆใ‚‚ cache ใŒ stale ใ ใจ .call ใŒๅคใ„ int slot ็ตŒ่ทฏใ‚’ๅ‡บใ™ใ€‚ๅ† infer ใฏ scope local ๅž‹ใ‚’่ชญใ‚€ใ ใ‘ใงๅค‰ใˆใชใ„ใฎใง widen ไธๅค‰ใ€‚
        • ็ตๆžœ: proc / proc_closure / case_local_in_lambda / enum_for_each / lowered_block_given ใŒ็ท‘ใ€proc ใฎ 6โ†’0 FAIL ใ‚‚่งฃๆถˆใ€‚ๅฝ“ๅˆๆŽจๆธฌใฎใ€Œside-channel ้žๅ†ๅ…ฅใ€ใ€ŒABI ๅ…จ้ขๆ”นไฟฎใ€ใฏใ„ใšใ‚Œใ‚‚ไธ่ฆใ ใฃใŸ(็œŸๅ› ใฏ node-cache ใฎ refresh ๆผใ‚Œ)ใ€‚
    2. node-cache stale: emit_hash_key ็ญ‰ใŒ comp_ntype(key) ใฎ widen ๅ‰ int ใ‚’่ชญใฟ coerce ใ‚’้ฃ›ใฐใ™(int-keyed hash ใฎ poly key=bundle_class_06)ใ€‚local read ใฏ scope_local()->type ใŒๆญฃใ€generic ใƒ˜ใƒซใƒ‘ใƒผใฏ node ๅž‹ไพๅญ˜ใ€‚ไธญๅคฎ่งฃๆฑบ่ฆใ€‚
    3. 932โ†’939 ใฎๅฎ‰ๅ…จใ‚ฐใƒซใƒผใƒ— landed(ๅ…จ g_promote_mode gate ๅ†…ใ€default 992/0/0+optcarrot 59662 ็ถญๆŒ): bound-method ็›ดๆŽฅ .call ใฎ arg ใ‚’ emit_arg_or_default ใง param ๅž‹ coerce(method/i960)/ ClassVariableWriteNode ๆŽจ่ซ–ใ‚’ cvar ๅž‹่ฟ”ใ—=ไบŒ้‡ box ่งฃๆถˆ(cvar_method_first_assign)/ poly-receiver dispatch ใฎ poly argโ†’scalar param unbox(8313, <=> ๅ‰้€ฒ)/ splat ๅฑ•้–‹่ฆ็ด ใ‚’ poly param ใธ box(splat_call)/ <=> ใ‚’ ret widen ้™คๅค–(ๅฐ int ใ—ใ‹่ฟ”ใ•ใš overflow ็„กใ—โ†’caller ใฎ (a<=>b)<cmp>0 ใŒ int ๆฏ”่ผƒใง้€šใ‚‹ใ€lrama_features)/ typed-array ret ใ‚’ body ใฎ PolyArray ใซ่ฟฝๅพ“(post-widen fixpoint ใฎ loop3=method ret ใ‚’ body ๆœซๅฐพ/return ใฎ PolyArray ใ‹ใ‚‰ๅ†ๅฐŽๅ‡บใ€multi_return)ใ€‚ ๆฎ‹ ERR=34(939 ๆ™‚็‚น)ใฎๆ•ฃๅœจ one-off / ๆทฑใ„ codegen ใƒใ‚ฐ:
      • ptr_array: method ret ใฏ PolyArray ๅŒ–ใ—ใŸใŒ caller ใฎ local = method() ใฎ local slot ๅž‹ใŒ IntArray ใฎใพใพ(infer_write_types ใฏ widen ๅ‰็ขบๅฎš)= method-retโ†’local ๅž‹ใฎไผๆ’ญ cascade ่ฆใ€‚
      • poly-receiver dispatch ใฎ arg coerce ๅŒๆ–นๅ‘: 8313 ใง poly argโ†’scalar param ใฎ unbox arm ่ฟฝๅŠ ๆธˆ(<=> ็ญ‰ใ€ๅ›žๅธฐ0)ใ€‚ใ ใŒ user <=>(comparable_between_user_type ็ญ‰ 3)ใฏ็ฌฌ2ใƒ–ใƒญใƒƒใ‚ซใƒผ = between?/clamp ใฎ arg-hoist g_pre ๅ†ๅ…ฅใƒใ‚ฐใงๆฎ‹ใ‚‹:sp_Temp * _t7 = sp_RbVal _t10 = ...(Temp.new(5) ใฎ boxed arg hoist ใŒๅค–ๅด arg-temp decl ใฎๅˆๆœŸๅŒ–ๅญๅ†…ใซๆททๅ…ฅ)ใ€‚emit_dispatch(codegen_fold.c:3389)ใง arg ใ‚’ๅด buffer ่ฉ•ไพกโ†’prelude flush ๅพŒใซ temp declใ€ใฎ้ †ๅบไฟฎๆญฃใŒ่ฆใ‚‹ใ€‚
      • closure_capture_float ็ณป(3, sp_runtime.h:187 mrb_int=sp_RbVal): poly cell ๅฐŽๅ…ฅใง capture ใŒ้€šใ‚‹ใ‚ˆใ†ใซใชใฃใŸใŒใ€proc ๆœฌไฝ“ใฎ captured ๅค‰ๆ•ฐใฎ็ฎ—่ก“ใŒ sp_int_add(poly cell, 1)(comp_ntype ใŒ intใ€cell ใฏ poly)ใ€‚proc ๆœฌไฝ“ scope ใฎ captured-var ๅž‹ไธ€่‡ดใŒ่ฆใ‚‹ใ€‚
      • bound-method .call ็›ดๆŽฅ dispatch ใฎ raw arg(method=sp_double / i960=sp_dbl / splat_call=sp_mix / bound_method_single_eval=sp_poly_puts / cvar_method_first_assign=sp_box_int): poly param ใธ int arg ใ‚’ box ใ›ใšใ€‚
      • B6 polyโ†’int(bm_instance_eval=ivar-write-as-expr / poly_dispatch_* / instance_exec break/next/trampoline_result / bundle_class_10 ็ญ‰)ใ€B1 intโ†’poly(instance_eval_block_params/bundle_misc_b/block2/bundle_classd_04)ใ€binary op(pattern_pin ==/bundle_class_05 <</lrama_features <)ใ€return mismatch(compile_time_define_method_int / multi_returnใƒปptr_array=PolyArray vs IntArray)ใ€invalid init(i916/op_assign_user_operator)ใ€hash key(bundle_class_06=emit_hash_key ใฎ comp_ntype stale)ใ€sp_box_str int-conv(recursive_implicit_yield_value)ใ€sp_Integer undeclared(class_method_open_class_call)ใ€float aggregate(float_round_nonliteral)ใ€ld error(fiber_capture_no_leak_to_sibling/i1007)ใ€front-end(clamp_bounds/integer_div_by_zero)ใ€‚ๅ„ใ€… 1-2 ใƒ†ใ‚นใƒˆใ€ๅ€‹ๅˆฅ่จบๆ–ญ่ฆใ€‚
      • FAIL=19 ใฏใ‚ณใƒณใƒ‘ใ‚คใƒซ้€šใ‚‹ใŒๅ‡บๅŠ›ๅทฎใ€ๅˆฅ้€”ใ€‚
  • ๆ‰‹ๆณ•: /tmp/ptest.sh <name>(ๅ˜ไฝ“)ใ€/tmp/perragg.shโ†’/tmp/perr4.txt(ๅ…จ ERR first-error)ใ€/tmp/ptest_lastc(ๆœ€ๅพŒใฎ cfile)ใ€‚ไธญๅคฎ coerce=emit_int_expr(polyโ†’int)/emit_float_expr/sp_poly_as_bigint/emit_boxed+emit_boxed_text(โ†’poly)/emit_unbox_text(polyโ†’scalar)ใ€‚

  • ๆฌกใฎไธ€ๆ‰‹: (1) ๆฎ‹ B4 one-off ใ‚’ emit_int_expr/sp_poly_as_bigint ใงๅ€‹ๅˆฅ coerce(ไธญๅคฎๅŒ–ใงใใ‚‹ site ใฏ emit_int_expr ใซๅฏ„ใ›ใ‚‹)ใ€‚(2) closure-capture front-end(capture ๅค‰ๆ•ฐ poly ๅฏพๅฟœ or widen ้™คๅค–)ใ€‚(3) FAIL=21 ใฎๅ‡บๅŠ›ๅทฎ(proc ็ญ‰)ใ€‚ๆ‰‹ๆณ•=/tmp/ptest.sh <name>ใ€/tmp/perragg.shโ†’/tmp/perr2.txtใ€/tmp/ptest_lastc ใซๆœ€ๅพŒใฎ cfileใ€‚polyโ†’int ใฏ emit_int_exprใ€polyโ†’float ใฏ emit_float_exprใ€polyโ†’bigint ใฏ sp_poly_as_bigint ใŒๆ—ขๅญ˜ใฎไธญๅคฎใƒ˜ใƒซใƒ‘ใƒผใ€‚

  • 2026-06-21 ็ถš่กŒ(939โ†’959ใ€ERR 34โ†’15ใ€12 commitใ€ๅ…จ g_promote_mode gate ๅ†…ใง default 992/0/0 + optcarrot 59662 ็ถญๆŒ):

    • pattern_pin(22d351d2): scalar scrutinee ใซๅฏพใ™ใ‚‹ pinned poly ๅ€ค(in ^xใ€x widen)ใ‚’ emit_unbox_text ใง unboxใ€‚
    • poly cell op-assign(f5..): captured poly cell(sp_RbVal *nใ€proc ๅ†… n += 1)ใฎ compound-assign ใ‚’ sp_poly_<op>/bitwise re-box ใธใ€‚closure_capture_float/block_forward_value_callable/bundle_classd_13ใ€‚
    • array-local cascade(78872692)= post-widen fixpoint step (4): map ใƒกใ‚ฝใƒƒใƒ‰ ret ใ‚„ array literal ใŒ PolyArray ๅŒ–ใ—ใŸใจใ local = value ใฎ IntArray/StrArray/FloatArray slot ใ‚’ TY_POLY_ARRAY ใซ่ฟฝๅพ“ใ€‚ptr_arrayใ€‚
    • poly <=>(e34530e2): poly operand ใฎ <=> ใ‚’ sp_poly_cmp ใธ(user class ใฎ <=> ใซ่ชค dispatch ใ—ใฆ boxed-int payload ใ‚’ user-ptr cast โ†’ recursion segfault ใ‚’ๅ›ž้ฟ)ใ€‚bundle_classd_50ใ€‚
    • between? arg-hoist(f447..): Comparable#between? ใฎ self/lo/hi temp ใ‚’ใ€ๅ„ operand ใ‚’ local buffer ใงๅ…ˆใซ emit ใ—ใฆใ‹ใ‚‰ decl prefix ใ‚’ๆ›ธใ(operand ่‡ช่บซใฎ g_pre hoist ใŒ decl ่กŒใ‚’ๅ‰ฒใ‚‰ใชใ„ใ‚ˆใ†้ †ๅบๅ…ฅๆ›ฟ)ใ€‚comparable_between_user_typeใ€‚
    • unary -@/+@/~ on poly(analyze_infer): poly receiver ใฎ unary ใ‚’ poly/int ใซ่งฃๆฑบ(method-dispatch unify ใŒ user class ใฎ -@ ใซ bind ใ—ใฆ obj ๅž‹ใ‚’ cascade ใ™ใ‚‹ใฎใ‚’้˜ฒใ)ใ€‚unary_operator_methodsใ€‚
    • poly-dispatch scalar slot unbox(8217): length-like poly dispatch ใฎ int slot ใซใ€widen ใ•ใ‚ŒใŸ user method ret(poly)ใ‚’ emit_unbox_text ใงไธ‹ใ’ใ‚‹(box ๆ–นๅ‘ใฎ้€†)ใ€‚poly_dispatch_builtin_all/poly_dispatch_ptr_array/bundle_class_10/bundle_classd_28ใ€‚
    • instance_exec result slot ใ‚’ break/next ๅ€คใง sizing(codegen+analyze): next val+1(poly)ใŒ trailing 999(int)ใ‚ˆใ‚Šๅบƒใ„ใจใ result temp ใ‚’ union ๅž‹ใซใ€‚ie_splice_value_ty(codegen)/ie_block_break_next_ty(analyze)ใง break/next ๅ€คๅž‹ใ‚’ unifyใ€g_ie_res_poly flag ใง scalar break/next/last ใ‚’ boxใ€‚instance_exec_next/instance_exec_breakใ€‚
    • nested destructure box(codegen_stmt): a, (b, c), d = 1, [2,3], 4 ใฎ inner array element ใ‚’ poly target slot ใซ boxใ€‚bundle_misc_bใ€‚
    • obj op-assign user-operator arg box(codegen_stmt): slot OP= rhs(obj slot + user OP)ใฎ rhs temp ใ‚’ OP param ใŒ poly ใฎใจใ boxใ€‚op_assign_user_operator + siblingใ€‚
    • loop{} poly result(codegen_call): expression-position loop{ break v } ใฎ result temp ใ‚’ default_value() ใง init(NULLโ†’sp_box_nil())+ g_ie_res_poly ใง scalar break ใ‚’ boxใ€‚i916ใ€‚
    • constant cascade(analyze)= step (5): COUNT = obj.m ใงใƒกใ‚ฝใƒƒใƒ‰ ret ใŒ widen ใ—ใŸใจใ int ๅฎšๆ•ฐ slot ใ‚’ poly ใซ่ฟฝๅพ“ใ€‚bare_module_body_cmethod_callใ€‚
    • 959โ†’965+ ็ถš่กŒ(ใ•ใ‚‰ใซ 9 commitใ€default 992/0/0+optcarrot 59662 ็ถญๆŒ):
      • define_method subst literal ใ‚’ poly-return tail ใง box: define_method("m_#{n}"){ n } ๅˆๆˆใƒกใ‚ฝใƒƒใƒ‰ใฎ ret ใŒ widen โ†’ subst literal(int)ใ‚’ boxใ€‚tail box ๅˆคๅฎšใ‚’ subst node ใฎๅž‹ใง sizingใ€‚compile_time_define_method_intใ€‚
      • poly-ivar attr-writer infer=poly: obj.attr = v ใฎๅ€คใฏ C ไปฃๅ…ฅ็ตๆžœ=boxed polyใ€‚infer ใŒ rhs(int)ๅž‹ใ‚’่ฟ”ใ—ใฆใ„ใŸ โ†’ ivar poly ใชใ‚‰ poly ่ฟ”ใ—ใ€‚instance_eval ๆœซๅฐพ setter ใฎ result temp sizing ไธ€่‡ดใ€‚bm_instance_evalใ€‚
      • instance_eval ivar-write ใ‚’ rebound class ใง่งฃๆฑบ: splice ๅ†… block scope ใฏ class_id ็„กใ— โ†’ @v=42 ใฎ ivar ๅž‹ UNKNOWN(box skip + infer rhs ๅž‹)ใ€‚g_ie_class_id(codegen)/an_ie_class_id(analyze)ใง่งฃๆฑบใ€‚instance_eval_block_paramsใ€‚
      • instance_eval/exec call node ่‡ช่บซใ‚’ rebound scope ใงๅ† infer: post-fixpoint ๅ† infer ใฏ body ใ ใ‘ๆ›ดๆ–ฐใ€call node ๅž‹ใฏ stale โ†’ truthiness consumer ใŒ int-nil form ใ‚’ poly ใซใ€‚infer_type(c,id) ่ฟฝๅŠ ใ€‚bundle_classd_04ใ€‚
      • value-form hash []= ใฎ poly key ใ‚’ unbox: h[k]=v(ๅผ)ใฎ key ใŒ emit_expr ็”Ÿ โ†’ typed-key hash setter ใซ polyใ€‚emit_hash_key ็ตŒ็”ฑๅŒ–ใ€‚bundle_class_06(-Werror ๆคœๅ‡บใ€make test ใฏ lenient ใง่ฆ‹้€ƒใ™)ใ€‚
      • Float#round/ceil/floor/truncate ใฎ poly ndigits unbox: (double)(poly) aggregate error โ†’ emit_int_exprใ€‚float_round_nonliteralใ€‚
    • โ˜… make-test promote count ใฏ -Werror ็„กใ—ใง lenient + ไธฆๅˆ— compile timeout ใง flaky(ๅŒไธ€ binary ๅ†ๅฎŸ่กŒใง ยฑ1 ๆบใ‚Œใ‚‹)ใ€‚ๅ„ fix ใฎ็ขบ่จผใฏ /tmp/ptest.sh(-Werror, deterministic)ใ€‚default 992/0/0 + optcarrot 59662 ใŒ hard gateใ€ไธก่€…ใฏๅ…จ commit ใง็ท‘็ถญๆŒใ€‚
    • 965โ†’971 ็ถš่กŒ(ใ•ใ‚‰ใซ 6 commitใ€ERR 9โ†’3ใ€default 992/0/0+optcarrot 59662 ็ถญๆŒ):
      • instance_exec block param ใ‚’่‡ช block scope ใง่งฃๆฑบ: forward-block(&b ใŒๅˆฅ site ใฎ literal ใซ่งฃๆฑบ)ใฎ param ใŒ call site scope ใฎ็„ก้–ขไฟ‚ใช a ใ‚’่ชญใฟ slot ๅž‹่ชค่ช โ†’ comp_scope_of(reqs[p])(param node ใฎ scope)ใง่งฃๆฑบใ€‚is_exec/tramp ใฎ polyโ†’int unbox ใŒ็™บ็ซใ€‚instance_exec_trampoline_resultใ€‚
      • reopened-primitive ใฎ poly dispatch receiver unbox: (sp_Integer*)_t.v.p ใฏ้ž struct โ†’ .v.i/.v.f/.v.s/(sp_sym) ใง union field ่ชญใฟใ€‚class_method_open_class_callใ€‚
      • poly local %= โ†’ sp_poly_mod: op-assign arm ใŒ +,-,*,/ ใฎใฟ โ†’ % ่ฟฝๅŠ ใ€‚integer_div_by_zeroใ€‚
      • poly clamp: sp_poly_clamp(runtime, tag-dispatch int/float + NaN/order check ๆ—ขๅญ˜ helper ๅ†ๅˆฉ็”จ)+ infer poly.clampโ†’poly + codegen ใฎ 2-arg/range formใ€‚clamp_boundsใ€‚
      • sp_gc_mark_rbval typo โ†’ sp_mark_rbval: fiber poly-capture scan ใŒๆœชๅฎš็พฉใ‚ทใƒณใƒœใƒซๅ‚็…ง = ld errorใ€‚promote ใฎ poly fiber capture ใงๅˆ้œฒ่ฆ‹ใ€‚i1007 / fiber_capture_no_leak_to_siblingใ€‚
    • โ˜…ๆฎ‹ ERR=3(971 ๆ™‚็‚นใ€deterministicใ€ๅ…จใฆ raw mrb_int carrier ABI family = ๆง‹้€ ็š„ใƒ–ใƒญใƒƒใ‚ซใƒผ):
      • block2: no-block ใฎ inline yield ใŒ poly value-if ใฎ then ๅˆ†ๅฒใง _t2 = 0(int)ใ‚’ poly slot ใธใ€‚yield emit ใ‚’ sp_box_nil() ๅŒ–ใ—ใฆใ‚‚ value-if/inline ็ตŒ่ทฏใŒ 0 ใ‚’ๅ‡บใ™๏ผˆemit ใจ value-if ใฎไบŒๆฎตใ€‚yield emit ๅ˜็‹ฌไฟฎๆญฃใงใฏไธๅฏใ€inline+value-if ใฎ branch-default ใ‚’่ฟฝใ†่ฆ๏ผ‰ใ€‚
      • bound_method_single_eval: object-bound .call ใฎ ABI ใŒ mrb_int(*)(void*, mrb_int...) ๅ›บๅฎšใ€‚promote ใง target method ใฏ poly param/ret ใซ widen โ†’ args ใ‚’ param ๅž‹ใซ box + ret cast ใ‚’ target ๅž‹ใซใ™ใ‚‹ๅ”่ชฟไฟฎๆญฃ่ฆ(return cast ๅ˜็‹ฌใฏ ERRโ†’FAIL ๆ‚ชๅŒ–ใ€revert ๆธˆ)ใ€‚
      • recursive_implicit_yield_value: lowered-yield ใฎ raw mrb_int carrier ใŒ string/int ไธก็”จ block ใงๅž‹ๅˆคๅˆฅไธ่ƒฝ โ†’ sp_box_str(mrb_int) ่ชค้ธๆŠžใ€‚carrier ใซๅž‹ tag ใ‚’ๆŒใŸใ›ใ‚‹ ABI ๅค‰ๆ›ด่ฆใ€‚
      • FAIL=19 ใฏใ‚ณใƒณใƒ‘ใ‚คใƒซ้€šใ‚‹ใŒๅ‡บๅŠ›ๅทฎ(attr=promote-mode crash ็ญ‰ใ€ๅˆฅ้€”)ใ€‚

    โ˜…ใ‚ปใƒƒใ‚ทใƒงใƒณ็ทๆ‹ฌ(940โ†’971ใ€ERR 33โ†’3): emission-site ใฎ box/unbox coercion + post-widen fixpoint ใฎ cascade(array-local step4 / ๅฎšๆ•ฐ step5)+ instance_exec/eval ใฎ rebound-scope ่งฃๆฑบ(ivar-write/call-node ๅ† infer/forward-block param scope)+ poly dispatch ใฎๅŒๆ–นๅ‘ coerce + runtime helper ่ฟฝๅŠ (sp_poly_clamp)ใง็ณป็ตฑ็š„ใซๆฝฐใ—ใŸใ€‚hard gate(default 992/0/0 + optcarrot 59662)ใฏๅ…จ commit ใง็ท‘ใ€‚make-test promote count ใฏ -Werror ็„กใ— + ไธฆๅˆ— timeout ใง flakyใ€็ขบ่จผใฏ /tmp/ptest.shใ€‚

  • 971โ†’973 ็ถš่กŒ(ERR 3โ†’1ใ€ๆฎ‹ 1 = recursive_implicit_yield_value ใฎใฟ):

    • block2 CLOSED: no-block ใฎ inline yield ใŒ poly value-if/inline tail ใง 0(int)ใ‚’ poly slot ใธใ€‚็œŸๅ›  = emit_tail_value ใŒๆ–‡ๅญ—ๅˆ— "sp_box_nil()" ใ‚’ emit_ret_nil(g_ret_type)(=scalar)ใซๆ›ธใๆ›ใˆใ‚‹็‰นไพ‹(g_result_var ใฎ poly ใ‚’็„ก่ฆ–)ใ€‚2 ๆฎตไฟฎๆญฃ: yield emit ใ‚’ comp_ntype==POLY ใง sp_box_nil() ๅŒ– + emit_tail_value ใ‚’ g_result_poly ๆ™‚ใฏ as-is pass-throughใ€‚
    • bound_method_single_eval CLOSED: object-bound .call ใŒ mrb_int(*)(void*, mrb_int...) ๅ›บๅฎš ABI ใงใ€widen ๅพŒใฎ poly param/ret ใ‚’ truncate(0 ่ฟ”ใ—)ใ€‚target ใŒ้™็š„่งฃๆฑบใงใใ‚‹ๆ™‚ใฏใใฎๅฎŸ return/param C ๅž‹ใง fn pointer ใ‚’ cast + emit_arg_or_default ใง arg coerceใ€‚default mode ใฏ้ž widen ใงๅŒไธ€ใ‚ณใƒผใƒ‰(ๅ›žๅธฐใชใ—)ใ€‚
    • โ˜…ๆฎ‹ ERR=1 = recursive_implicit_yield_value(ๆทฑใ„ multi-pass ABIใ€ๆœฌใ‚ปใƒƒใ‚ทใƒงใƒณใง root cause ็ขบๅฎšใƒปไฟฎๆญฃใฏ scope ๅค–ใจๅˆคๆ–ญ):
      • ็—‡็Šถ: countdown ใŒ string block({"done"})ใจ int block({42})ไธกๆ–นใ‹ใ‚‰ๅ‘ผใฐใ‚Œใ€return ๅž‹ใฏ poly ใซ unifyใ€‚ใ ใŒ lowered-yield ใฎ yield=sp_proc_call(__yblk__) ใฏ raw mrb_int ใ‚’่ฟ”ใ—ใ€call-site block proc(_proc_N)ใ‚‚ raw ๅ€ค(int ใฏ็ด ใƒปstring ใฏ ptrโ†’mrb_int cast)ใ‚’่ฟ”ใ™ใŸใ‚ใ€return yield ใฎ box ใง string/int ใ‚’ๅˆคๅˆฅใงใใš sp_box_str(mrb_int) ่ชค้ธๆŠžใ€‚
      • ไฟฎๆญฃใฎๅฟ…่ฆ 3 ็‚น(ๅ€‹ๅˆฅใซใฏๅฎŸ่ฃ…ใ€ใ—ใ‹ใ— pass ้ †ๅบใงไธๆˆ็ซ‹): โ‘ method_call_ret/yield_value_type ใ‚’ lowered-yield ใงๅ…จ call-site unify(็พ็Šถใฏใ€Œper-call-site ็‰นๆฎŠๅŒ–ใ€ๅ‰ๆใง first block ๅž‹ใ‚’ break-ๆŽก็”จ โ†’ ๅ˜ไธ€ใ‚ณใƒณใƒ‘ใ‚คใƒซใฎๅฎŸๆ…‹ใจไธไธ€่‡ด)โ‘กcall-site block proc ใ‚’ poly-ret ๅŒ–(_sp_proc_poly_ret ใซ boxใ€codegen.c:1084 ใฎ blk_ret==POLY ๆฉŸๆง‹ใŒๆ—ขๅญ˜)โ‘ขlowered yield emit ใŒ _sp_proc_poly_ret ใ‚’่ชญใ‚€ใ€‚
      • โ˜…ใƒ–ใƒญใƒƒใ‚ซใƒผ = pass ้ †ๅบ: blk_ret ใ‚’่จˆ็ฎ—ใ™ใ‚‹ infer_return_types(analyze_pass.c:3699)ๆ™‚็‚นใง lowered-yield ๅŒ–(blk_param="__yblk__" ่จญๅฎšใ€analyze.c:1992+)ใŒใพใ ่ตฐใฃใฆใŠใ‚‰ใšใ€countdown ใฎ blk_param ใŒ NULL โ†’ blk_ret ่จˆ็ฎ—่‡ชไฝ“ใŒ lowered-yield scope ใ‚’ไธ€ๅˆ‡่ฆ‹ใชใ„(debug ็ขบ่ช: ่ฉฒๅฝ“ pass ใง blk_param ไป˜ใ scope ใŒ 0 ไปถ)ใ€‚ใ‚ˆใฃใฆ โ‘กใฎๅ‰ๆ(blk_ret==POLY)ใŒๆˆ็ซ‹ใ—ใชใ„ใ€‚็œŸใฎไฟฎๆญฃใฏ blk_ret ่จˆ็ฎ—ใ‚’ lowering ๅพŒใซๅ‹•ใ‹ใ™(or lowering pass ๅ†…ใง่จˆ็ฎ—)+ โ‘กโ‘ข ใฎๅ”่ชฟใงใ€analyzer ใฎ pass ้ †ๅบใซ่ธใฟ่พผใ‚€ๆง‹้€ ๅค‰ๆ›ดใ€‚siblings(proc/block2/forward_args_block ็ญ‰)ใฏๆœฌ่ฉฆ่กŒใงๅ›žๅธฐใชใ—ใ‚’็ขบ่ชๆธˆใ ใŒใ€ๆœฌไธธใฏๆœชๅŽๆŸใฎใŸใ‚ revertใƒปclean ็ถญๆŒใ€‚
      • FAIL=19 ใฏใ‚ณใƒณใƒ‘ใ‚คใƒซ้€šใ‚‹ใŒๅ‡บๅŠ›ๅทฎ(attr=promote-mode crash ็ญ‰ใ€ๅˆฅ้€”)ใ€‚

2026-06-20 ็ฌฌ3่ฉฆ่กŒ = ๆ–น้‡ (A) full uniform widen ใ‚’ๅฎŸ่กŒ(branch promote-full-widen-experiment ใซไฟๅ…จ): matz ๆดžๅฏŸใ€Œpoly ใฏ int(inline)ใจ bigint(heap)ไธกๆ–นใ‚’ 1 ๅ€คใงไฟๆŒใ™ใ‚‹ใฎใงใ€legacy ใฎๅ…จ bigint(ๅ…จ heap)ใ‚ˆใ‚ŠๅŠน็އ็Š ็‰ฒใ‚’ๆŠ‘ใˆใฆๅ…จ widen ใงใใ‚‹ใ€ใ‚’ๅ—ใ‘ใ€ๅ…จ int slot โ†’ poly ใ‚’ๅฎŸ่ฃ…(analyze.c ใฎ fixpoint ๅพŒใƒปnode-type cache ๅ‰ใ€g_promote_mode gateใ€24 ่กŒ)ใ€‚param/return/local/ivar/cvar ใฎ TY_INTโ†’TY_POLYใ€‚

  • ๆœฌไธธ #1 ใŒๅ‹•ใ„ใŸ: def mul(x,y)=x*y; mul(10**15,10**15) = 10**30ใ€mul(3,4)=12(ๅฐ int ใฏ inline poly)ใ€‚MRI ไธ€่‡ดใ€‚approach ๅฎŸ่จผๅฎŒไบ†ใ€‚
  • default gate ็„กๅ‚ท(992/0/0ใ€g_promote_mode gate)ใ€‚
  • promote suite 993โ†’831(32 fail / 130 error)= ๅขƒ็•Œใƒใ‚ฑใƒ„ใŒ่กจ้ขๅŒ–ใ€‚ๅ…จใ‚จใƒฉใƒผใฏ polyโ†”int ๅขƒ็•Œใฎ coercion ๆฌ ๅฆ‚(codegen ใŒๅž‹ไธ€่‡ดๅ‰ๆ)ใ€‚
  • ๅ˜็ด”ไปฃๅ…ฅๅขƒ็•Œใฏ emit_assign ใซๆ—ขใซ poly-box arm ใ‚ใ‚Š(codegen_stmt.c:512 lv->type==TY_POLY โ†’ emit_boxed)ใ€‚ๆฎ‹ใ‚‹ใฏไปฅไธ‹ใฎ ๅขƒ็•Œใƒใ‚ฑใƒ„(C error ้ ปๅบฆ้ †ใ€/tmp/promerr.txt ้›†่จˆ):
    1. ไปฃๅ…ฅ sp_RbVal = mrb_int/long(265)= op_assign(x+=1)ใƒปivar/cvar writeใƒปๅฎฃ่จ€ๅˆๆœŸๅŒ–ใชใฉ emit_assign ไปฅๅค–ใฎไปฃๅ…ฅ็ตŒ่ทฏใ€‚ๅ„ write emit ใซ poly-boxใ€‚
    2. ๆฏ”่ผƒ sp_RbVal <= / >= / < / > / == mrb_int(~60)= poly recv ใฎๆฏ”่ผƒใ‚’ sp_poly_lt/cmp/eq ใซๅ›žใ™(scalar ๆฏ”่ผƒ codegen ใŒ int ๅ‰ๆ)ใ€‚
    3. increment wrong type argument to increment(28)= lv_x++(loop counter ็ญ‰)ใŒ poly slotใ€‚lv_x = sp_poly_add(lv_x, sp_box_int(1)) ๅŒ–ใ€‚
    4. builtin arg coerce(~40): sp_IntArray_push(14)/sp_poly_to_s(11)/sp_poly_lt(9)/sp_bigint_new_int(5)/sp_poly_to_i(4)/sp_range_include(4)/sp_str_sub_range_r(4)= poly arg ใ‚’ builtin ใฎ int param ใธใ€‚call-arg coerceใ€‚
    5. const/cvar static init ้žๅฎšๆ•ฐ(21)= static ... = sp_box_int(...)(้žๅฎšๆ•ฐๅผ)ใ€‚cvar/const ใฎ poly ๅˆๆœŸๅŒ–ใ‚’ runtime init ใธ็งปใ™ใ‹ใ€int ไฟๆŒใ—ใฆ read ๆ™‚ boxใ€‚
    6. mrb_int = sp_RbVal(22)/ return mismatch(~10)= builtin ๆˆปใ‚Š(int)ใ‚’ poly slot ใธใ€ใพใŸใฏ poly ๅ€คใ‚’ int return ๅž‹ใธใ€‚widen ใ—ๆฎ‹ใ—ใŸๅขƒ็•Œใ€‚
    7. float aggregate where floating-point expected(10)= poly ใ‚’ float ๆ–‡่„ˆใธใ€‚sp_poly_to_f coerceใ€‚
  • ๆฌกใฎไธ€ๆ‰‹: ใƒใ‚ฑใƒ„ 1(op_assign/ivar/cvar write ใฎ poly-box)โ†’ 2(ๆฏ”่ผƒ)โ†’ 3(increment)ใฎ้ †ใงใ€ๅ„ใƒใ‚ฑใƒ„ๅพŒใซ promote suite ใ‚’ๅ†่จˆๆธฌ(rm -rf build/test-results && make test SPINEL_INT_OVERFLOW=promote OPT=-O1)ใ€‚emit_assign ใฎ poly arm ใƒ‘ใ‚ฟใƒผใƒณใ‚’ๅ„ write/compare/return site ใซๆจชๅฑ•้–‹ใ™ใ‚‹ไฝœๆฅญใ€‚branch ใ‹ใ‚‰ cherry-pick ใ—ใฆๅ†้–‹ใ€‚
  • ๅˆคๆ–ญ: ใ“ใ‚Œใฏ่จˆ็”ป้€šใ‚Š่ค‡ๆ•ฐใ‚ปใƒƒใ‚ทใƒงใƒณใฎ big-bangใ€‚master ใฏ clean(2a ใฎ 993)็ถญๆŒใ€ๅฎŒ้‚ๅพŒใซใพใจใ‚ใฆๆ˜‡ๆ ผใ€‚approach ใฏ็ขบๅฎš(ๆœฌไธธๅ‹•ไฝœใƒปๅŠน็އๅ„ชไฝ)ใ€‚

2026-06-21 ใƒใ‚ฑใƒ„1(for-range loop counter)ๅฎŸ่ฃ…ใฎๆฑบๅฎš็š„็Ÿฅ่ฆ‹: emit_for ใฎ TY_RANGE arm ใซไฟฎๆญฃ(็ซฏ็‚นใ‚’็‹ฌ็ซ‹ใซ sp_poly_to_i coerce + poly counter ใฏ fresh mrb_int temp ้ง†ๅ‹•&ๆฏŽ iter lv_<vn>=sp_box_int(_tc) ใง boxใ€early return ใง else ๅ›ž้ฟ)ใ€‚branch promote-full-widen-experiment ใฎ commit bda23978 ใซไฟๅ…จใ€‚

  • ไฟฎๆญฃใฏ correct: for i in 1..10(=55)+ poly ็ซฏ็‚น็‰ˆ for i in 1..f(=55)ใจใ‚‚ MRI ไธ€่‡ดใ€BUILD_OKใ€‚็ซฏ็‚น coerce ใฏ counter ใฎ poly ๆ€งใจ็‹ฌ็ซ‹ใซๅฟ…่ฆ(concrete int counter + poly ็ซฏ็‚น n ใงใ‚‚ mrb_int _t=lv_n ใŒๅฃŠใ‚Œใ‚‹)ใ€‚
  • ใ ใŒ promote pass ใฏ 831 ๆจชใฐใ„(errorโ†’fail 1ไปถใฎใฟ็งปๅ‹•)ใ€‚โˆตๅ„ failing ใƒ†ใ‚นใƒˆใซ่ค‡ๆ•ฐใฎ polyโ†”int ๅขƒ็•ŒใŒ้‡ใชใ‚‹โ†’1ใƒใ‚ฑใƒ„ๅ˜็‹ฌใงใฏ็ท‘ใซใชใ‚‰ใชใ„(for-range ใ‚’็›ดใ—ใฆใ‚‚ๅŒใƒ†ใ‚นใƒˆๅ†…ใฎๆฌกใฎๅขƒ็•Œ=ไปฃๅ…ฅ/ๆฏ”่ผƒ/builtin-arg ็ญ‰ใงใ‚ณใƒณใƒ‘ใ‚คใƒซ็ถš่กŒไธ่ƒฝ)ใ€‚
  • ๆˆฆ็•ฅ็š„็ต่ซ–: ใƒใ‚ฑใƒ„้€ๆฌก commit ใฏไธญ้–“ใง pass ใ‚’ๅข—ใ‚„ใ•ใชใ„ใ€‚็ท‘ใซใ™ใ‚‹ใซใฏ (1) 1ใƒ†ใ‚นใƒˆใ‚’็ธฆใซๅ…จๅขƒ็•ŒๅฎŒ้‚(pass+1ใ€ๅขƒ็•Œใ‚ซใ‚ฟใƒญใ‚ฐ็ขบ่จผ)ใ‹ (2) ๅ…จๅขƒ็•Œ(ไปฃๅ…ฅไธกๆ–นๅ‘/ๆฏ”่ผƒ/increment/builtin-arg/const-init/return/float)ใ‚’ไธ€ๆ‹ฌใงๆฝฐใ™็œŸใฎ big-bangใ€‚ๆฌกใ‚ปใƒƒใ‚ทใƒงใƒณใฏ for-range fix(bda23978)ใ‚’ๅœŸๅฐใซใ€ใพใš 1 ใƒ†ใ‚นใƒˆ็ธฆๅฎŒ้‚ใงๅ…จๅขƒ็•ŒใฎๅฎŸ่ฃ…ใƒ‘ใ‚ฟใƒผใƒณใ‚’็ขบ็ซ‹ใ—ใฆใ‹ใ‚‰ๆจชๅฑ•้–‹ใŒๅฎ‰ๅ…จใ€‚

(ๅ‚่€ƒ)legacy ๆ–นๅผ

legacy backend(legacy/spinel_codegen.rb L55, L3037-3203)ใฏ promote ใงๅ…จ int slot ใ‚’ sp_Bigint* ใซ widen(method ABI = (void*, sp_Bigint*...) -> sp_Bigint*)ใ€‚ๆŽก็”จใ›ใš(ไธŠ่จ˜็†็”ฑ)ใ€‚

ๅฎŸ่ฃ…ใฎ้›ฃๆ‰€:

  1. mode ไผ้”: C ็‰ˆใฏ codegen_program(nt) ใซ overflow mode ใŒๆธกใ‚‰ใชใ„(main.c:355ใ€็พ็Šถ -D ใฎใฟ)ใ€‚g_promote_mode global ใ‚’ main.c ใง่จญๅฎšใ— analyze/codegen ใŒ่ชญใ‚€ๅฟ…่ฆใ€‚
  2. big-bang ๆ€ง: ๅ…จ int ใ‚’ bigint ๅŒ–ใ™ใ‚‹ใจใ€ๅŸ‹ใพใฃใฆใ„ใชใ„ๅขƒ็•ŒใŒๆ–ฐใŸใซ่กจ้ขๅŒ–ใ—ใ†ใ‚‹ใ€‚้ƒจๅˆ† widen ใฏ promote ใ‚ณใƒณใƒ‘ใ‚คใƒซใ‚’ๅฃŠใ™ใฎใงใ€ๅ…จๅขƒ็•Œใ‚’ๅŒๆ™‚ใซ้€šใ™ๅฟ…่ฆ(=็พ optcarrot ใŒ้€šใ‚‹็ฏ„ๅ›ฒใ‚’่ถ…ใˆใŸ path ใงๅ†ๅบฆใƒใ‚ฑใƒ„ๆฝฐใ—)ใ€‚
  3. optcarrot perf ้€€่กŒใƒชใ‚นใ‚ฏ: ใƒ–ใƒญใƒƒใ‚ฏใƒซใƒผใƒ—ๆคœๅ‡บใ‚’็ด ๆœดใซ่ถณใ™ใจ optcarrot ใฎ .times ๅ†… x=x*y ใŒๅคง้‡ bigint ๅŒ–ใ—ๅฃŠๆป…็š„ใซ้…ใใชใ‚‹(while ้™ๅฎšใฏใ“ใฎๅ›ž้ฟใŒ็†็”ฑใจๆ€ใ‚ใ‚Œใ‚‹)ใ€‚ๅ…จ int widen ใงใ‚‚ promote optcarrot ใฏๅคงๅน…ๆธ›้€Ÿ(opt-in ใชใฎใง่จฑๅฎนใ€gate ใฏ wrap pin ใงไธๅค‰)ใ€‚

ๆŽจๅฅจ: ๅฐ‚็”จใฎ้›†ไธญไฝœๆฅญใจใ—ใฆ (1) mode ไผ้” โ†’(2) ๅ…จ intโ†’bigint widen pass(promote gate)โ†’(3) ่กจ้ขๅŒ–ใ™ใ‚‹ๅขƒ็•Œใ‚’ๆฝฐใ™ โ†’ promote ใง test/bench/optcarrot ๅ†็ขบ่ชใ€ใฎ้ †ใ€‚default/wrap ใฏ promote gate ใซใ‚ˆใ‚Šไธๅค‰ใชใฎใง gate ๅ›žๅธฐใƒชใ‚นใ‚ฏใฏ promote ็ตŒ่ทฏใซ้™ๅฎšใ€‚

(ไปฅไธ‹ใ€2026-05 ๅฝ“ๆ™‚ใฎ Error ใƒใ‚ฑใƒƒใƒˆๅˆ†้กž โ€” ๅคšใใฏ่งฃๆถˆๆธˆใฟใ€ๅ‚่€ƒ)

Error ใƒใ‚ฑใƒƒใƒˆๅˆ†้กž

Bucket A: Bit operators on sp_Bigint * (LARGEST โ€” optcarrot ใฎ 80%)

error: invalid operands to binary & (have 'sp_Bigint *' and 'long long int')
error: wrong type argument to bit-complement

Ruby ใฎ a & b, a | b, a ^ b, a << n, a >> n, ~a ใง operands ใŒ bigint ใฎๆ™‚ C ๆผ”็ฎ—ๅญใŒไฝฟใˆใชใ„ใ€‚ optcarrot ใฏ CPU emulator ใชใฎใง bit-op ใŒๅคง้‡ใ€‚

ไฟฎๆญฃ: runtime helpers + codegen ๅˆ†ๅฒ:

  • sp_bigint_and(a, b), _or, _xor, _shl, _shr, _not, _inv
  • compile_operator_expr / compile_bitop_expr ใง bigint operands ใ‚’ๆคœๅ‡บ โ†’ helper call emit
  • ๆททๅœจ (bigint + int_literal) โ†’ ไธ€ๆ–นใ‚’ unbox / box ใ—ใฆๆƒใˆใ‚‹

Bucket B: Builtin container helpers with bigint args

sp_IntArray_push(a, bigint_lv)   โ† needs sp_bigint_to_int
sp_IntArray_get(a, bigint_idx)
sp_FloatArray_set(a, idx, bigint_val)  โ† unbox + cast to mrb_float
sp_IntStrHash_set(h, bigint_key, val)

memory ใซ partial fix ่จ€ๅŠใ‚ใ‚Šใ€‚ ๆฎ‹ใ‚‹ใฎใฏ _push / _get / _set ใฎ็‰นๅฎš site ใจ FloatArray ใฎ bigintโ†’float castใ€‚

Bucket C: ๅๅพฉ / index ใง bigint

range.each { |i| arr[i] = ... }   โ† i bigintใ€ arr[i] ใง unbox ๅฟ…่ฆ
n.times { |i| ... }

block param ใŒ bigint ใง IntArray index ็ญ‰ใซไฝฟใ‚ใ‚Œใ‚‹ shapeใ€‚ ๆ—ขใซ้ƒจๅˆ†ๅฏพๅฟœๆธˆใฟใ ใŒๅ–ใ‚Šใ“ใผใ—ใ€‚

Bucket D: FFI / typed user method call ใฎ poly โ†’ bigint coerce

sp_Counter_cls_double(poly_val)   โ† param bigintใ€ arg poly
sp_mandelbrot(bigint, bigint)     โ† FFI param floatใ€ arg bigint

compile_typed_call_args ใง poly arg โ†’ bigint param ใฎ coerce ใ‚’่ฟฝๅŠ  (mirror of #639 IVW unbox)ใ€‚ FFI :float / :int arg ใฏ bigint ใง sp_bigint_to_int โ†’ castใ€‚

Bucket E: Bigint slot init / return from poly

sp_Bigint * x = poly_expr          โ† .v.p extract ๅฟ…่ฆ
return poly_expr                   (function return bigint)

compile_expr_for_expected_type ใฎ polyโ†’bigint arm ใŒ็„กใ„ / ไธๅฎŒๅ…จใ€‚

Bucket F: Bigint โ†’ string ๅค‰ๆ›ๆผใ‚Œ

puts bigint_val
"prefix" + bigint_val
sp_int_to_s(bigint_val)            โ† should be sp_bigint_to_s

memory ใซใ€Œๆ–‡ๅญ—ๅˆ—่ฃœ้–“ / str_concat / str << ใฎ bigintโ†’string ๅค‰ๆ› (sp_bigint_to_s)ใ€ใจใ‚ใ‚Š partial fix ๆธˆใฟใ€‚ ๆฎ‹ใ‚Šใฎ emit site ใ‚’ๆŽขใ™ใ€‚

Bucket G: Test/bench infrastructure issues

promote ใจ็„ก้–ขไฟ‚ใซ่กจ้ขๅŒ–ใ™ใ‚‹ shape:

  • int_eq_nil_strict โ€” int slot ใŒ bigint ๅŒ–ใ—ใŸใฎใง nil check ใฎๆŒ™ๅ‹•ใŒๅค‰ใ‚ใ‚‹
  • pattern_pin โ€” pin pattern ใŒ int ใ‚’ๆœŸๅพ…ใ—ใฆใ‚‹ใŒ bigint ใงๅž‹ไธไธ€่‡ด
  • const_self_ref_init_warns โ€” ๅ‡บๅŠ› format ๅค‰ๅŒ– (0 vs 0LL?)

ใ“ใ‚Œใ‚‰ใฏๅ€‹ๅˆฅ่ชฟๆŸปใ€‚

Phases (ๅฎŸ่ฃ…้ †)

Phase 1 โ€” Bit-op support for bigint (ๅคงใƒ–ใƒญใƒƒใ‚ซใƒผ่งฃๆถˆ)

ๆœ€ๅคงใฎๅกŠใ€‚ ใ“ใ‚Œใง optcarrot ใฎ 80% errors ใŒๆถˆใˆใ‚‹ใ€‚

1.1 lib/sp_runtime.h: ๆ–ฐ helpers

  • sp_bigint_and(a, b), _or(a, b), _xor(a, b) โ€” ๆ—ขๅญ˜ GMP wrapper ็ตŒ็”ฑ
  • sp_bigint_shl(a, n), _shr(a, n) โ€” n ใฏ mrb_int
  • sp_bigint_not(a) โ€” 1's complement (็ฌฆๅทๅ่ปข + 1 ใง signed ใจๅŒใ˜)

1.2 lib/sp_bigint.c: GMP mpz_and / mpz_ior / mpz_xor / mpz_mul_2exp / mpz_fdiv_q_2exp / mpz_com ใƒฉใƒƒใƒ—

1.3 spinel_codegen.rb:

  • compile_operator_expr ใง op in {"&", "|", "^", "<<", ">>"} && (lt == bigint || rt == bigint) โ†’ helper
  • ~ ใฎๅ˜้ … (compile_call_expr ใง recv bigint mname ~) โ†’ sp_bigint_not
  • mixed (bigint + int literal): literal ใ‚’ sp_bigint_new_int ใง box ใ—ใฆ helperใ€ OR ไธกๆ–น unbox ใ—ใฆ C ๆผ”็ฎ—ๅญ โ†’ re-box

1.4 optcarrot ใงๅ‹•ไฝœ็ขบ่ชใ€ checksum 59662 ็ถญๆŒ็ขบ่ช

ๆœŸๅพ…: optcarrot promote PASSใ€ test promote +20ใ€œ30 cases

Phase 2 โ€” Builtin container helpers ใฎ bigint unbox ๅ–ใ‚Šใ“ใผใ—

2.1 sp_IntArray_push emit site: arg ใŒ bigint ใชใ‚‰ sp_bigint_to_int ใ‚’ wrap 2.2 sp_IntArray_get / _set / _index ๅŒๆง˜ 2.3 sp_FloatArray_set ใฎ val ใŒ bigint ใชใ‚‰ (mrb_float)sp_bigint_to_int(...) ใง cast 2.4 sp_*IntHash_* ใง key/val bigint ใฎ unbox

ๆœŸๅพ…: bench bm_loops_times / bm_matmul / bm_fannkuch PASSใ€‚ test promote +10ใ€œ15 cases

Phase 3 โ€” Typed user method call ใฎ polyโ†’bigint coerce

3.1 compile_typed_call_args (positional + kwarg):

  • ๅผ•ๆ•ฐใฎ static type ใŒ poly ใง param expected ใŒ bigint โ†’ (arg).v.p ็ตŒ็”ฑ
  • mirror of #639 ใฎ IVW unbox path

3.2 FFI :float / :int arg with bigint:

  • compile_ffi_func_call ใง arg ใŒ bigint ใชใ‚‰ sp_bigint_to_int โ†’ cast

ๆœŸๅพ…: nullable_poly_hash_arg_unbox ็ญ‰ +5 testsใ€ bm_mandel_term / bm_so_mandelbrot ็ณป PASS

Phase 4 โ€” Bigint slot init / return from poly

4.1 compile_expr_for_expected_type: at == "poly" && expected == "bigint" โ†’ (... ).v.p 4.2 compile_return_stmt: rt == "poly" && method return == "bigint" โ†’ ๅŒๆง˜ unbox

ๆœŸๅพ…: ๆฎ‹ test promote errors +5

Phase 5 โ€” Bigint โ†’ string ๅค‰ๆ›ๅ–ใ‚Šใ“ใผใ—

5.1 puts bigint, string interpolation "x=#{bigint}", << chain ใฎ emit site ใง bigint operand โ†’ sp_bigint_to_s ็ตŒ็”ฑ

ๆœŸๅพ…: bench bm_csv_process / bm_jekyll_lite ็ณป PASS

Phase 6 โ€” ๅ€‹ๅˆฅ test failure ่ชฟๆŸป

ๆฎ‹ test failures ใ‚’ๅ€‹ๅˆฅใซๆฝฐใ™ใ€‚ ๅ„ใ€…ๅฐใ•ใช shape:

  • int_eq_nil_strict โ€” bigint slot ใง nil compare ๆŒ™ๅ‹•
  • pattern_pin โ€” pattern matching ใฎ bigint scrutinee
  • const_self_ref_init_warns โ€” output format ๅพฎๅทฎ

ๆœŸๅพ…: test promote 100% pass

Phase 7 โ€” Bench ๆฎ‹ใ‚Š + Makefile ๆ•ด็†

7.1 ๆฎ‹ bench failures ๅ€‹ๅˆฅใซๆฝฐใ™ 7.2 Makefile ใ‹ใ‚‰ optcarrot ็”จ --int-overflow=wrap pin ้™คๅŽป (or --int-overflow=$(SPINEL_INT_OVERFLOW) defaulting to wrap ใ ใŒ promote ใงใ‚‚้€šใ‚‹)

ๆœŸๅพ…: bench promote 100% pass

ๆคœ่จผใƒ•ใƒญใƒผ (ๅ„ phase ใง)

# default mode ใฏๅฃŠใ•ใชใ„
rm -rf build/test-results/
make -j8 test 2>&1 | tail -2   # 631/0/0 ็ถญๆŒ
make optcarrot 2>&1 | tail -3  # checksum 59662 ็ถญๆŒ

# promote mode ้€ฒๆ—
rm -rf build/test-results/
SPINEL_INT_OVERFLOW=promote make \
  CFLAGS="-O2 -Wno-all -Wno-unknown-warning-option -Wno-alloc-size-larger-than -DSP_INT_OVERFLOW_MODE_PROMOTE" \
  -j8 test 2>&1 | tail -2

SPINEL_INT_OVERFLOW=promote make \
  CFLAGS="-O2 -Wno-all -Wno-unknown-warning-option -Wno-alloc-size-larger-than -DSP_INT_OVERFLOW_MODE_PROMOTE" \
  -j8 bench 2>&1 | tail -2

# optcarrot single
SPINEL_INT_OVERFLOW=promote ./spinel --int-overflow=promote build/optcarrot-single.rb -o /tmp/op_p
/tmp/op_p

ๅŠนๆžœ้‡ไบˆๆƒณ (็ดฏ็ฉ)

Phasetestbenchoptcarrot
็พ็Šถ557/52/2236/7/14C compile fail
1ๅฎŒไบ†~580/45/15~45/5/7PASS (checksum 59662)
2ๅฎŒไบ†~595/40/8~52/3/2PASS
3ๅฎŒไบ†~610/15/4~55/2/0PASS
4ๅฎŒไบ†~620/8/2~56/1/0PASS
5ๅฎŒไบ†~625/5/0~57/0/0PASS
6ๅฎŒไบ†631/0/057/0/0PASS
7ๅฎŒไบ†631/0/057/0/0PASS (Makefile clean)

ๅทฅๆ•ฐๆฆ‚็ฎ—

  • Phase 1 (bit-ops): 2-4 hours
  • Phase 2 (containers): 1-2 hours
  • Phase 3 (call args): 1-2 hours
  • Phase 4 (return/slot): 0.5-1 hour
  • Phase 5 (string conv): 0.5-1 hour
  • Phase 6 (ๅ€‹ๅˆฅ test): 2-4 hours (varies)
  • Phase 7 (bench + Makefile): 1-2 hours

ๅˆ่จˆ: 8-16 hours focused work

้€ฒใ‚ๆ–นใฎๆณจๆ„

  • default ใ‚’ๅฃŠใ•ใชใ„: ๅ„ commit ็›ดๅพŒใซ make test (default 631/0/0) + make optcarrot (wrap pinใ€ checksum 59662) ใ‚’ๅ›žใ™
  • commit ใ‚’ๅฐๅˆปใฟใซ: bucket 1 ใค โ‰’ 1 commit (memory feedback_commit_often)
  • inline ้–ขๆ•ฐ vs macro: sp_int_* ใฏ macroใ€‚ ๆ–ฐ่ฆ helper ใ‚‚ๅŒใ˜ pattern ใง (memory feedback_promote_mode_inline_pitfall)
  • stale cache ๆณจๆ„: promote_int_to_bigint_globally ๅพŒใฎ cache invalidation ๆผใ‚Œใซ่ญฆๆˆ’
  • ่จ˜้Œฒ: ๅ„ phase ใฎ commit ๅพŒใ€ ๆฎ‹ใ‚Š errors / fails ใฎๆ•ฐใ‚’ memo ใ—ใฆ้€ฒๆ—ใƒˆใƒฉใƒƒใ‚ฏ

Risks

  1. optcarrot ใฏ --int-overflow=wrap ใŒๆœ€้€Ÿ: promote ใ ใจ bigint helper call overhead ใง fps ไฝŽไธ‹ใŒไบˆๆƒณใ•ใ‚Œใ‚‹ใ€‚ Makefile ใฎใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใฏ wrap ใฎใพใพใซใ™ใ‚‹ (promote ใฏ opt-in mode ใจใ„ใ†่จญ่จˆใซๆฒฟใ†)
  2. bigint memory pressure: ๅ…จ int slot ใŒ heap-allocated bigint ใซใชใ‚‹ โ†’ GC ๅœงใจ allocator churnใ€‚ ๆ—ขๅญ˜ GC ใงๅฏพๅฟœใงใใ‚‹ใ‹ๆธฌๅฎš่ฆ
  3. ๆ—ขๅญ˜ default test ใฎ non-determinism: ไธๅค‰ใชใฏใšใ ใŒใ€ stale cache invalidation ็ตŒ็”ฑใง็จ€ใซ regression ใŒๅ‡บใ‚‹ๅฏ่ƒฝๆ€งใ‚ใ‚Šใ€‚ ๆฏŽ commit ใง default test ๅฟ…้ ˆ
  4. ๆ–ฐ helper ใฎ signedness: GMP ใฎ mpz_and ็ญ‰ใฏ arbitrary-precision ใง signed ่‡ช็„ถใ‚ตใƒใƒผใƒˆใ€‚ spinel ๅดใง signedness ็ถญๆŒ็ขบ่ช

้–‹ๅง‹ phase

Phase 1 (bit-ops) ใ‚’ๆœ€ๅ„ชๅ…ˆใ€‚ optcarrot ใ‚’ unblock ใ—ใ€ ๅฝฑ้ŸฟใŒๆœ€ใ‚‚ๅคงใใ„ใ€‚ ็€ๆ‰‹ๅพŒใ€ ๅ„ helper ใ‚’ 1 ใคใšใค่ฟฝๅŠ  โ†’ optcarrot ใงๅ‹•ไฝœ็ขบ่ช โ†’ commitใ€‚