fix(interpreter): fresh mutable containers get heap identity, like literals - #143
Merged
Conversation
…terals
set()/list()/dict() constructor results (and list(iterable)) returned
bare values, so an in-place mutation reached through a reference mutated
a throwaway copy: `index.setdefault(w, set()).add(name)` left every set
in the dict empty — the classic inverted-index idiom silently produced
no hits. Literals ({...}, []) already heap-allocate; constructors now do
too, via handle_builtin_result, so aliasing and mutation-through-
intermediate-receiver behave like CPython.
Set in-place mutators (add/remove/discard/pop/clear/update/…) move to
the :ok_raw path so their {:mutate, new, ret} writeback reaches the heap
object — the same wiring list.append and dict mutators already had.
json.dumps grows a {:ref} deref in apply_default so default=list (which
now returns a ref) terminates instead of recursing on itself.
Six regression tests cover the setdefault idioms, constructor aliasing,
list(iterable) mutability, and the json.dumps(default=list) fixpoint.
This fix was authored in a parallel working session (its differential
CPython/VM/Wasm harness found the bug); this PR lands it with formatting,
a widened set_method spec for Dialyzer, and the regression tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn
4 tasks
ivarvong
added a commit
that referenced
this pull request
Jul 7, 2026
…rg (#145) * feat: OTel attributes= kwarg, WasmGC target, and the differential harness Three pieces from the wasm working session, extracted onto main (the container-identity fix landed separately as #143): - opentelemetry: start_as_current_span honors the attributes= kwarg, seeding the span at open; merges with set_attribute calls. Two tests. - Pyex.Wasm: the `mix wasm.build` entry point — pyrun/3 runs a program in a fresh Ctx against an in-memory VFS and returns stdout, footprint, final files, and BOTH runtime and app spans as JSON. The beam2wasm compiler is a sibling-checkout dev dep, loaded only when the checkout exists, so CI and consumers resolve deps without it (the wasm: project config is inert without the dep). - test/differential: a three-executor harness (CPython · pyex-VM · pyex-Wasm) that auto-localizes divergences — CPython≠VM is an interpreter bug, VM≠Wasm is a compiler bug — gated by a checked-in LEDGER of known divergences. Aliasing lens (constructor × storage × mutation product) plus a 25-program realistic corpus; 79/79 green at time of extraction. Runs via `mix run test/differential/run.exs` (needs wasm/pyex.wasm and python3), not in `mix test`. Also: span_cm loses a dead default arg (warning), and Wasm.pyrun's rescue clause interpolates type-safely without Exception.message/1 (protocol dispatch the wasm target can't lower). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn * drop the wasm target + harness: moving to the pyex.dev composition repo The ../elixir_wasm path-based dev dep was too fragile to ship, even guarded. The wasm entry point, build config, and differential harness move to a third project that composes pyex + beam2wasm via git deps and owns the pyex.dev site and edge API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
set()/list()/dict()constructor results (andlist(iterable)) returned bare values, so an in-place mutation reached through a reference mutated a throwaway copy. The flagship symptom, straight from the playground's search-index example:Literals (
{...},[]) already heap-allocate for identity; constructors now do too (handle_builtin_resultallocs fresh mutable containers), so aliasing and mutation-through-intermediate-receiver behave like CPython.add/remove/discard/pop/clear/update/difference_update/…) move to the:ok_rawpath so their{:mutate, new, ret}writeback reaches the heap object — the same wiringlist.appendand dict mutators already had.list(...)clauses route through onealloc_listhelper;{:iter_to_list, ...}results heap-alloc on the way out.json.dumpsgrows a{:ref}deref inapply_default, sodefault=list(which now returns a ref) recurses into the concrete-value clauses instead of re-invokingdefaulton the ref forever.set_method's@specwidened for the:ok_rawshape (Dialyzer).Six regression tests: the inverted-index
setdefault(w, set()).add(...)idiom,dict()-via-setdefaultsubscript writes,list()/list(iterable)aliasing + mutability, set mutators through an alias, and thejson.dumps(default=list)fixpoint.Provenance
Authored in a parallel working session, whose differential CPython/VM/Wasm harness surfaced the bug; landed here with formatting, the spec fix, and tests. The harness itself ships separately with the wasm build config.
Test plan
mix format --check-formattedmix compile --warnings-as-errors(modulo the three pre-existing 1.20.2-local warnings on main)mix test— 6518/6519 (the one failure is the known local-OTP zipfile CRC-message artifact, present on main)mix dialyzer— clean🤖 Generated with Claude Code
https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn