Repository navigation
Conversation
handle_identifier returned the stored const value with the loc of the declaration. The printer then mapped the literal inside the using function back to the declaration line. Coverage treated that line as part of an uncalled function, and stack traces pointed at the const. Stamp the use site loc, as every other substitution in this function does and as esbuild does. An enum-valued const gets a new inlined enum node so the inner value carries the use loc too.
|
Updated 5:41 PM PT - Oct 17th, 2026
✅ @robobun, your commit 84c7dfcb7abdc40e7f42bc8ea4a0457680fe9660 passed in 🧪 To try this PR locally: bunx bun-pr 45581That installs a local version of the PR into your bun-45581 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughThe parser assigns inlined constant replacements to their identifier use-site locations. The runtime transpiler cache version increases to 36. New regression tests check LCOV coverage and stack-frame source positions. ChangesInlined constant locations
Suggested reviewers: Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
Beyond the inline finding, I also checked for sibling sites: handle_identifier is the only reader of const_values (the bundler/linker consumers in src/bundler are commented out), so the runtime transpiler and Bun.build share this one fix. The printer's EInlinedEnum arm (src/js_printer/lib.rs:4515) maps via print_expr(e.value), which confirms the inner-value re-stamp and the per-use node allocation are both needed; the shared inner E::String StoreRef was already shared across uses before this change, so that is not new.
Extended reasoning...
The change re-stamps the use-site loc onto const-inlined replacement exprs in the parser hot path, bumps the runtime transpiler cache version to 36, and adds a coverage test and a stack-trace sourcemap test. It touches no security-sensitive surface. The one inline finding is a pre-existing gap for macro-valued object/array consts, which the PR description acknowledges; the literal and enum cases are handled in the single consumer of const_values.
Fixes #45218
Problem
bun test --coveragereports 0 hits for every line from an inlinedconstdeclaration down to an uncalled function that uses it. A stack frame forNOT_A_FUNCTION()inside a function points at theconstline too.handle_identifier(src/js_parser/p.rs:2195) returns the stored const value with thelocof the declaration, so the source map points the literal inside the function at that line.generate_report_from_blocks(src/sourcemap_jsc/CodeCoverage.rs:938) takes the min mapped line of the function as its start.Fix
handle_identifierreturns the const value with thelocof the use. An enum-valued const (EInlinedEnum) gets a new node, because the printer maps the inner value.ConstValueToExpr(loc, value)). The printed JavaScript does not change.test/cli/test/coverage.test.tsandtest/js/bun/sourcemap/internal-sourcemap.test.ts, both fail on 1.4.3. Self-reviewed: 3 concerns, 2 addressed (Notes).Background
inliningon.visit_declstores eachconst x = <literal>inconst_values. Each later read ofxbecomes that storedExpr.Expr.locis the position the printer writes into the source map.CodeCoverage.rs. It hides a wrong mapping in one consumer, and stack traces stay wrong. Make line coverage follow the innermost JSC block #41528 also rewrites that code.Downsides
E::InlinedEnumnode in the parser arena. A literal const allocates nothing new.constbound to a macro result object or array still inlines the inner literals with the positions the macro gave them.Notes
Repro from the issue,
bun test --coverage --coverage-reporter=lcov, before:After:
Stack trace probe,
const NOT_A_FUNCTION = null;on line 1 andNOT_A_FUNCTION();on line 5 insidecall():const C = Color.Red; function call() { C(); }prints"red" /* Red */();. Before, the frame pointed at the declaration line. After, at the call line.const B = Number(2),let,var,1n, and"a" + "b"are not inlined, so they never showed the bug.The lcov range of the uncalled function still ends one line early (
DA:6for thereturnline is absent). That is the existingmin_line..max_lineexclusive range ingenerate_report_from_blocks, not touched here.Open PR #41580 (tail-call frames under the runtime's minify-syntax, for #24789) carries the same literal-case hunk in
handle_identifieras a side fix. It does not handle the enum-valued const and has no coverage test. That hunk drops out of #41580 on rebase once this lands.Self-review concerns: (1) cache version not bumped, fixed. (2) #41580 overlap not named, fixed above. (3) Macro-valued object and array consts keep the positions the macro stamped on them (
Macro.rs). That is a separate path and is listed under Downsides.Other suites run:
transpiler.test.js,bundler_minify,bundler_edgecase,bundler_compile,esbuild/ts,esbuild/default,test/js/bun/sourcemap,regression/issue/30887. Pre-existing timeouts on this slow debug machine, with and without the change:bun-build-api.test.tsbytecode tests,esbuild/default TopLevelAwaitForbiddenRequireSourceMap*.