Skip to content

Merge train 182r: #10199, #10203, #10213 - #10216

Merged
proggeramlug merged 5 commits into
mainfrom
train182r
Sep 13, 2026
Merged

proggeramlug merged 5 commits into
mainfrom
train182r

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Merge train 182r: lands #10199 (route const rest exports through the closure spread call; fixes #10197) at f869baa9c5, #10203 (route the traversal-feedback counters through the hot thread-local cache) at 388e83a742 and #10213 (resolve static-getter method calls on call-expression heritage; fixes #10210) at 14126f371a, plus the workspace version bump to 0.5.1559. (Named 182r to stay clear of the other merge lane's train numbers.)

The PR commits were cherry-picked onto 44e78debf9 without conflicts.

Validation (macOS arm64)

Validation ran on the same three PRs over 64f5249ac0. Main has since gained only #10212, which touches none of their files.

  • fmt, changeset fragments for all three, RUSTFLAGS=-Dwarnings cargo check -p perry --bins, raw_handle_debt.py (both invocations), gc_runtime_root_holders.py, check_test_registration.py, check_file_size.sh
  • scripts/check_thread_locals.py: json/traversal_feedback.rs is no longer flagged. The one remaining violation, regex/perex_owner.rs, is identical on main.
  • cargo test --release -p perry-codegen --lib: 1530 passed / 0 failed
  • cargo test --release -p perry --test issue_10210_static_getter_call: 1 / 0; --test source_graph_export_regressions: 25 / 0, including issue_10197
  • Harness filters: test_gap_json 36 pass plus the known JSON.parse lazy array: Object.defineProperty index accessor is bypassed by reads #10097 failure. class 115 pass / 3 fail and static 45 pass / 2 fail: 2159_defineproperty_class_prototype and 2899_2779_2777_static_helpers are main's known reds, and test_issue_7769_thread_class_dispatch, test_three_like_native_class_descriptors and test_ws_static_constants_6117 fail identically with a 9b911855f8 compiler (Node exits 1 on this host).

Confirmation on this exact tree: RUSTFLAGS=-Dwarnings cargo check -p perry --bins; cargo test --release -p perry-runtime: 3765 passed, 1 failed. The failure is gc::tests::heap_generation::a_free_or_move_outside_every_scope_is_caught_in_debug_builds, already on main from #10205 (release-mode assertion test; noted there).

CI attribution (vs main's run at b5a82cfeae)

Review notes

Ralph Küpper added 5 commits September 13, 2026 18:35
#10197)

`ns.member(...spread)` had a fast path (#6475) for namespace members that
are rest-parameter exports: bundle every argument into one array and call
`perry_fn_<src>__<member>` directly. For a `let`/`const`-bound export
(`export const mergeAll = (...ctxs) => …`) that symbol is the export's
zero-arg VALUE getter, not the function body, so the call returned the
closure itself and the expression evaluated to the function. Effect's
`Layer.mergeAll` does exactly `Context.mergeAll(...contexts)` through a
namespace import, which is why every OpenCode command died in its
bootstrap with `Cannot read properties of undefined (reading 'size')`.

Mirror `try_lower_namespace_member_call`: when the member is in
`imported_vars`, skip the fast path so the closure-callee path reads the
value through the getter and applies the spread with
`js_closure_call_apply_with_spread`. Function declarations keep the
direct symbol call.

Claude-Session: https://claude.ai/code/session_01As1fetJAqDFib4n7Wm5Suo
(cherry picked from commit f869baa)
…ad-local cache

The thread-local policy ratchet allows no raw thread_local! in the
runtime; #10150 declared json/traversal_feedback.rs's two counters with
one. Both now use crate::perry_thread_local!, with unchanged call sites.

(cherry picked from commit 091638d)
(cherry picked from commit 388e83a)
…eritage (#10210)

A static getter on a class whose `extends` clause is a call expression
(effect v4 `class Svc extends Context.Service<Svc, Shape>()(id) {}`, i.e. a
plain `function KeyClass(){}` whose [[Prototype]] was swapped with
`Object.setPrototypeOf`) threw `of is not a function` on `this.of(x)` while
the plain read `this.of` returned the function.

Two gaps, both on the miss path only:

- The dynamic method-call dispatcher's class-object arm resolved nothing but
  the static-method vtable. It now mirrors the class-ref arm (#5437): when the
  vtable misses, read the property exactly as the read path does (static
  accessors, the per-evaluation parent class object's statics, the
  function-valued ancestor's swapped prototype) and call the closure with
  `this` bound to the receiver.
- The class-ref read paths (string and symbol keys) looked for the
  function-valued parent edge only on the receiver's own class id. They now
  walk the class chain like `super()` dispatch already did, so a subclass of
  the class that `extends <function>` inherits those statics too.

Unblocks OpenCode v1.18.30's runtime bootstrap (`ConfigService.Service` →
`static get layer()` → `tag.of(config)` while AppRuntime builds RuntimeFlags).

Claude-Session: https://claude.ai/code/session_01As1fetJAqDFib4n7Wm5Suo
(cherry picked from commit 14126f3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment