fix(hir): keep upgrade-callback wsId tagged ("ws","Client") across its own param binding#5534
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a ChangesNative-param protection against tombstoning
Estimated code review effort🎯 2 (Simple) | ⏱️ ~14 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
4c0b2ca to
21a075d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/perry-hir/src/lower/expr_call/prescans.rs`:
- Around line 82-83: The protect_native_param call is currently unconditional
after register_native_instance, but since register_native_instance can be a
no-op (via compile-package override path in context.rs), calling
protect_native_param without verifying successful registration can preserve
stale native tags and cause mis-dispatch in callback method calls. Guard each
protect_native_param invocation (for res_name and other parameters) behind a
check that its corresponding register_native_instance call actually succeeded.
Apply this fix to all three affected locations: the register_native_instance and
protect_native_param calls around line 82-83, the block around lines 92-96, and
the block around lines 106-107.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b06810ce-e237-4ac4-b800-5f2ff73d9d20
📒 Files selected for processing (4)
crates/perry-hir/src/lower/context.rscrates/perry-hir/src/lower/expr_call/prescans.rscrates/perry-hir/src/lower/lowering_context.rscrates/perry-hir/tests/ws_upgrade_param_native_dispatch.rs
21a075d to
4975ec1
Compare
Review — targeted and sensible; one latent fragilityThe ordering is correct: the pre-scan runs while lowering the Latent fragility — name-keyed, no scope tie. Test asserts over the |
cc8fb18 to
9e05943
Compare
|
Thanks @proggeramlug — addressed the latent fragility in You're right that a name-only key could linger if the expected consumer never fires. self.prescan_protected_native_params
.retain(|_, depth| *depth <= self.scope_depth);So a protection whose consumer never runs (an unusual callback shape, or a binding path that skips (Agreed the |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/perry-hir/src/lower/context.rs`:
- Around line 1271-1279: The protect_native_param method currently anchors the
protection to the current scope_depth, but this is the caller's scope, not the
callback scope where the parameter binding actually occurs. The prescan runs
before entering the callback scope, so storing the current scope_depth means the
entry survives exit_scope and can leak into unrelated bindings with the same
name. Change protect_native_param to store scope_depth + 1 instead (the
callback's scope depth), ensuring the prescan_protected_native_params entry is
cleaned up when exiting the actual callback parameter scope, not the caller's
scope. This prevents stale native tags from incorrectly skipping tombstoning for
later unrelated bindings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dfb28285-7ce3-42c3-b844-af304cf79b66
📒 Files selected for processing (4)
crates/perry-hir/src/lower/context.rscrates/perry-hir/src/lower/expr_call/prescans.rscrates/perry-hir/src/lower/lowering_context.rscrates/perry-hir/tests/ws_upgrade_param_native_dispatch.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/perry-hir/tests/ws_upgrade_param_native_dispatch.rs
- crates/perry-hir/src/lower/expr_call/prescans.rs
…s own param binding
`server.on('upgrade', (req, wsId, head) => …)` pre-scans and registers the second
param `wsId` as a ("ws","Client") native instance (prescans.rs) so wsId.send(...)
/.on(...)/.close() inside the handler dispatch through the Client-class
NATIVE_MODULE_TABLE rows (→ js_ws_send_client_i64 etc.). But the arrow's OWN param
binding then calls shadow_native_instance_if_present("wsId"), which tombstones any
native tag colliding with a param name (the leaked-instance guard for minified
bundles). That erased the FRESH, intended tag, so wsId.send no longer dispatched to
the native fn — wsId.send/.on silently no-opped: the handler calls wsId.send but the
frame never goes out, and inbound frames never reach wsId.on (a dead post-upgrade
WebSocket channel).
Fix: each pre-scan marks the param name it just tagged as protected
(ctx.protect_native_param); shadow_native_instance_if_present consumes that
protection one-shot to skip the tombstone for exactly that param. Covers the
upgrade `wsId`, the http-client-callback `res`, and the request 'socket' `sock`.
Adds a perry-hir test asserting wsId.send/.on lower to ws Client NativeMethodCalls.
Refs PerryTS#577
9e05943 to
5160cdf
Compare
Summary
When lowering an HTTP
'upgrade'handler —server.on('upgrade', (req, wsId, head) => …)— the upgrade pre-scan registers thewsIdparameter as a("ws", "Client")native instance, sowsId.send(...)/wsId.on(...)inside the handler dispatch through the Client-class rows ofNATIVE_MODULE_TABLE.But the arrow's own
wsIdparameter binding then callsshadow_native_instance_if_present, whose job is to tombstone a stale native tag leaked from an outer scope. Here the tag is the fresh, intended one the pre-scan just registered, so that binding wrongly erased it and the method calls degraded to generic dynamic dispatch (.send/.onno longer routed to the ws Client shims).This protects a pre-scan-designated parameter from being tombstoned by its own binding, one-shot per name — so a later, unrelated parameter of the same name still shadows a genuinely stale tag.
Changes
crates/perry-hir/src/lower/lowering_context.rs: add theprescan_protected_native_paramsset.crates/perry-hir/src/lower/context.rs:shadow_native_instance_if_presentconsumes-and-skips the tombstone for a protected name; addprotect_native_param.crates/perry-hir/src/lower/expr_call/prescans.rs: mark the pre-scan-registered upgrade / native-instance params (res,wsId,sock) as protected.crates/perry-hir/tests/ws_upgrade_param_native_dispatch.rs: assert thatwsId.send/wsId.onin the handler lower towsNativeMethodCalls.Related issue
Refs #577
Test plan
The handler arrow lowers to an inline
Expr::Closure(closures here are not lifted intomodule.functions), andwalk_expr_childrenskips closure bodies, so the test asserts over the module'sDebugrendering — onlyNativeMethodCallemits amodule:field. Verified it fails without the protection (the tag is tombstoned, the calls lower as genericExpr::Calls → 0wsdispatches) and passes with it.cargo build --releaseclean (affected crate)cargo test --workspace …passes — the affected crate's targeted tests pass; the full workspace has pre-existing, unrelated failures onmainnot touched by this change.#[test]in the affected cratedocs/src/— n/a (HIR lowering only)Checklist
feat:/fix:/docs:/chore:prefix convention used in the logSummary by CodeRabbit
Bug Fixes
upgradehandlers (wsId), and socket event handlers (sock), preserving expected behavior for methods likesend()andon().Tests
upgradehandler lowering to confirmwsIdretainsClient-class native dispatch for bothsend()andon().