Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions changelog.d/6839-native-proof-uint8array-symbol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### Fixed

- **`native_owned_uint8array_get_fallback_uses_uint8array_helper` has been red
on `main` since #6092.** That PR moved the unproven-bounds JS-value read off
the i32 `js_uint8array_get` accessor — whose out-of-range answer is the `0`
byte-sentinel — onto `js_uint8array_index_get_value`, which reads `undefined`
per IntegerIndexedExotic `[[Get]]` (#6088). The proof still asserted the old
symbol. What the test is about does not change: a disposed native Uint8Array
view must fall back through the Uint8Array-shaped accessor, never the
Buffer-shaped one.

The sibling inline-path test forbade only `js_uint8array_get`, so after #6092
a regression that took the slow path would have gone unnoticed. It now
forbids both helpers.

Integration suites under `crates/*/tests/` don't run per-PR (#5960), which is
why this sat red — it surfaces only when a PR touches perry-codegen and pulls
the suite into `e2e-scoped`.
17 changes: 15 additions & 2 deletions crates/perry-codegen/tests/native_proof_buffer_views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1554,9 +1554,15 @@ fn native_owned_uint8array_get_fallback_uses_uint8array_helper() {
})),
],
);
// #6088/#6092 moved the unproven-bounds JS-value read off the i32
// `js_uint8array_get` accessor, whose out-of-range answer is the `0`
// byte-sentinel, onto `js_uint8array_index_get_value`, which reads
// `undefined` per IntegerIndexedExotic `[[Get]]`. What this test is about
// is unchanged: the fallback must go through the Uint8Array-shaped
// accessor, never the Buffer-shaped one.
assert!(
ir.contains("call i32 @js_uint8array_get"),
"disposed native Uint8Array fallback should call js_uint8array_get:\n{ir}"
ir.contains("call double @js_uint8array_index_get_value"),
"disposed native Uint8Array fallback should call js_uint8array_index_get_value:\n{ir}"
);
assert!(
!ir.contains("call i32 @js_buffer_get"),
Expand Down Expand Up @@ -1642,6 +1648,13 @@ fn uint8array_const_local_length_uses_inline_byte_get_set() {
!ir.contains("call i32 @js_uint8array_get"),
"inline Uint8Array get should not call the runtime helper:\n{ir}"
);
// The JS-value getter is the other way this could fall back after
// #6088/#6092; without naming it here the negative assertion above would
// miss a regression that took the slow path.
assert!(
!ir.contains("call double @js_uint8array_index_get_value"),
"inline Uint8Array get should not call the JS-value runtime helper:\n{ir}"
);
}

#[test]
Expand Down
15 changes: 3 additions & 12 deletions crates/perry-hir/src/lower/builder_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ fn scan_stmt(s: &ast::Stmt) -> bool {
match s {
ast::Stmt::Block(b) => stmts_have_candidate(&b.stmts),
ast::Stmt::If(i) => {
scan_expr(&i.test)
|| scan_stmt(&i.cons)
|| i.alt.as_deref().is_some_and(scan_stmt)
scan_expr(&i.test) || scan_stmt(&i.cons) || i.alt.as_deref().is_some_and(scan_stmt)
}
ast::Stmt::While(w) => scan_expr(&w.test) || scan_stmt(&w.body),
ast::Stmt::DoWhile(d) => scan_stmt(&d.body) || scan_expr(&d.test),
Expand All @@ -115,8 +113,7 @@ fn scan_stmt(s: &ast::Stmt) -> bool {
.is_some_and(|f| stmts_have_candidate(&f.stmts))
}
ast::Stmt::Switch(sw) => {
scan_expr(&sw.discriminant)
|| sw.cases.iter().any(|c| stmts_have_candidate(&c.cons))
scan_expr(&sw.discriminant) || sw.cases.iter().any(|c| stmts_have_candidate(&c.cons))
}
ast::Stmt::Decl(d) => scan_decl(d),
ast::Stmt::Expr(es) => scan_expr(&es.expr),
Expand Down Expand Up @@ -209,13 +206,7 @@ fn scan_expr(e: &ast::Expr) -> bool {
matches!(&c.callee, ast::Callee::Expr(e) if scan_expr(e))
|| c.args.iter().any(|a| scan_expr(&a.expr))
}
E::New(n) => {
scan_expr(&n.callee)
|| n.args
.iter()
.flatten()
.any(|a| scan_expr(&a.expr))
}
E::New(n) => scan_expr(&n.callee) || n.args.iter().flatten().any(|a| scan_expr(&a.expr)),
E::Seq(s) => s.exprs.iter().any(|e| scan_expr(e)),
E::Tpl(t) => t.exprs.iter().any(|e| scan_expr(e)),
E::Paren(p) => scan_expr(&p.expr),
Expand Down
Loading