Skip to content

runtime,analyze,codegen: Hash.new{} default block preserves key type#1815

Merged
matz merged 1 commit into
matz:masterfrom
ryanseys:rs-hash-new-block-key-type
Jul 8, 2026
Merged

runtime,analyze,codegen: Hash.new{} default block preserves key type#1815
matz merged 1 commit into
matz:masterfrom
ryanseys:rs-hash-new-block-key-type

Conversation

@ryanseys

@ryanseys ryanseys commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

A Hash.new { |h,k| ... } default-block hash was always compiled to a StrPolyHash, the only poly-valued hash variant that carried a default-proc field. String keys were fine, but symbol keys were coerced to their name string, so p h rendered {"a" => ...} where CRuby prints {a: ...} — the stored value read back correctly, so this was purely a key-type / inspect defect.

This gives SymPolyHash and PolyPolyHash a dproc field too (mirroring StrPolyHash), and compiles a block-default hash as a PolyPolyHash. A default block implies dynamically-populated keys, so the faithful poly hash — which boxes each key by value — is the honest representation: a symbol key round-trips as a symbol and inspects as a:, a string as "a"=>, an integer as 1=>, and mixed keys each render correctly.

Covered by test/hash_new_block_key_type.rb (symbol / string / integer / mixed keys, the accumulator idiom, a method-routed case that defeats constant folding, and default-block value reads), with ruby as the expected-output oracle.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the compiler and runtime to support default-block hashes (Hash.new { |h, k| ... }) using a polymorphic key-value hash (PolyPolyHash) instead of a string-keyed hash. This change ensures that key types (such as symbols, strings, and integers) are preserved faithfully on inspection. Feedback on the changes highlights critical issues in lib/sp_runtime.h where the newly added dproc and dproc_self fields in both sp_SymPolyHash and sp_PolyPolyHash are not initialized to NULL in their respective _new functions, which can lead to segmentation faults. Additionally, if dproc_self references a GC-managed object, it must be marked during GC scanning to prevent premature garbage collection.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread lib/sp_runtime.h
Comment thread lib/sp_runtime.h
A `Hash.new { |h,k| ... }` default-block hash was always compiled to a
`StrPolyHash`, the only poly-valued variant that carried a default-proc
field. String keys were fine, but symbol keys were coerced to their name
string, so `p h` rendered `{"a" => ...}` where CRuby prints `{a: ...}`
(the stored value read back correctly -- purely a key-type/inspect defect).

Give `SymPolyHash` and `PolyPolyHash` a `dproc` field too, mirroring
`StrPolyHash`, and compile a block-default hash as a `PolyPolyHash`. A
default block implies dynamically-populated keys, so the faithful poly
hash -- which boxes each key by value -- is the honest representation: a
symbol key round-trips as a symbol and inspects as `a:`, a string as
`"a"=>`, an integer as `1=>`, and mixed keys each render correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ryanseys ryanseys force-pushed the rs-hash-new-block-key-type branch from 1b08731 to 082eef4 Compare July 8, 2026 07:11
@ryanseys ryanseys marked this pull request as ready for review July 8, 2026 07:12
@matz matz closed this in f1eff35 Jul 8, 2026
@matz matz merged commit f1eff35 into matz:master Jul 8, 2026
3 checks passed
matz added a commit that referenced this pull request Jul 8, 2026
…5% fix)

The dproc dispatch #1815 added to sp_SymPolyHash_get / sp_PolyPolyHash_get sat
inline on the lookup path; the extra branch/code pushed the hot inlined hash
lookup over the inline threshold and cost optcarrot a reproducible 35% fps
(818 -> 530, isolated by swapping only lib/sp_runtime.h under the identical
generated C). Same lesson as the string-hash cache: a hot-path inline branch
regresses; SP_NOINLINE the cold side. Move the whole miss handling (dproc
check + default_v) into cold noinline sp_*Hash_miss helpers, leaving _get's
body smaller than it originally was. fps recovers fully (~828 interleaved,
at-or-above the pre-#1815 baseline); default-block hashes still pass their
reproducers; gate green.

Refs #1815.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ryanseys ryanseys deleted the rs-hash-new-block-key-type branch July 8, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants