Repository navigation
Tags: oven-sh/bun
Tags
`bun check`: a long chain of interfaces or classes no longer takes cu… …bic time (#44895) A long chain of interfaces or classes, each of which extends the last, took cubic time. ```ts interface I0 { k0: number } interface I1 extends I0 { k1: number } interface I2 extends I1 { k2: number } // and 1,997 more ``` Twice the interfaces took eight times as long. This is old. Generated typings are written like that. CPU time of `bun check`, and of `tsc` 7.0.2: | Each interface adds | Interfaces | main | this branch | `tsc` | |---|---|---|---|---| | a property | 500 | 0.26 s | 0.04 s | 0.09 s | | a property | 1,000 | 2.00 s | 0.10 s | 0.19 s | | a property | 2,000 | 15.28 s | 0.56 s | 0.68 s | | a method | 500 | 0.28 s | 0.05 s | 0.08 s | | a method | 1,000 | 1.86 s | 0.10 s | 0.18 s | | a method | 2,000 | 15.56 s | 0.53 s | 0.68 s | ## Members that mention `this` or a type parameter The same for a chain with any other kind of member, in classes too. `tsc` is cubic there as well, so it is measured with 500 only. CPU time of the check on one thread, and of `tsc` with `--singleThreaded`: | Each one adds | main, 1,000 | this branch, 1,000 | this branch, 2,000 | `tsc`, 500 | |---|---|---|---|---| | interface, `k: this` | 4.04 s | 0.55 s | 2.18 s | 8.70 s | | interface, a method that returns `this` | 4.03 s | 0.68 s | 3.34 s | 8.75 s | | generic interface, `k: T` | over 25 s | 0.45 s | 2.02 s | 10.04 s | | class, a method without a return type | 4.37 s | 0.63 s | 3.02 s | 8.95 s | | class, a field with an initializer | 3.59 s | 0.31 s | 1.81 s | 9.83 s | | class, a parameter property | 4.02 s | 0.41 s | 1.63 s | 8.92 s | | class, a pair of accessors | 3.66 s | 0.34 s | 1.85 s | 8.26 s | On main each of them takes over 25 s with 2,000. The errors and the types are the same as before. ## How it was found The arrays of #44890 were one shape of generated code that `bun check` was slow on and `tsc` was not. So I ran 61 such shapes at 500, 1,000 and 2,000 lines, both tools on one thread, and compared the time and the number of errors. Seed data, fixtures, tables, long unions with a `switch`, chains of `else if`, spreads, builders, overloads, enums, JavaScript that assigns to `exports`, `this` and prototypes, API clients, mapped and conditional types, tuples, `satisfies`, merged declarations, callbacks with contextual types. This chain was the only one where `bun check` took more than twice as long as `tsc` and more than half a second. In most of the others it takes about half the time of `tsc`. ## How it was verified What changes is when an inherited member counts as the same member. So: 5 kinds of owner, 12 kinds of member with and without `this`, plain, generic, inside a generic function and merged, each in the 12 situations where that decides something. Two interfaces with a common base that are extended together, overriding a member with the same and with another type, assigning both ways, unions and intersections of two heirs, `keyof`, indexed access, spread, a chain of six. 192 programs, 2,527 errors, with the type of the member probed in each. The output is that of `tsc`, before and after, on all threads and on one. 132 more programs try to make the base type of an heir matter to a member from further up. Heirs that rename and wrap their type parameters over four levels, with 10 kinds of member, outer type parameters, mixins, classes inside generic classes and functions, bases that are mapped types, intersections, arrays and tuples, defaults, statics, overriding half way, a common base. Every inherited member is probed through the last heir. 891 errors, the output of `tsc` before and after, on all threads and on one. `check.test.ts` has two tests, one with 2,000 interfaces and one with 1,000 of three of the other kinds. Both run into their timeout on main. | Everything else | Result | |---|---| | TypeScript's own suite, 5 kinds of baseline | 100% of each, as before | | 2,512 small programs that once differed, against `tsc`, on all threads and on one | no change | | 47 real projects, on all threads and on one | the same output as main | | 317 builds with project references | the same output as main | | Instructions for 9 configs, among them vscode, next.js and storybook | +0.2% against main, and main against itself gives +0.5% |
lexer: only treat __PURE__ as an annotation when it starts a // comme… …nt (#41284) ### Problem - A `//` comment that mentions `/*#__PURE__*/` as text marks the next call as pure. Bun removes an unused pure call at runtime and in `bun build`, without minification. So `` // `/*#__PURE__*/` `` followed by `console.log(...)` deletes the `console.log`. In `@angular/build` this deleted `source.appendRight(...)` and corrupted the Angular build output (angular/angular-cli#33973). - The cause is `scan_single_line_comment` in `src/js_parser/lexer.rs:2087`. On any `#` or `@` in a `//` comment it calls `scan_pragma`, which sets `has_pure_comment_before` when `__PURE__` follows. The position in the comment does not matter. Fixes #41275. Fixes #19355. ### Fix - In a `//` comment, `@__PURE__` or `#__PURE__` is an annotation only when it is the first word: only whitespace may sit between `//` and the marker. Text after the marker is still allowed. Block comments are unchanged. - This deviates from esbuild, terser and rollup, which match the marker anywhere in a comment. Those tools only act on it when minifying or tree shaking. Bun acts on it always, so a false match deletes user code. Line directives such as `// @ts-ignore`, `//# sourceMappingURL=` and `// eslint-disable-next-line` use the same first-word rule. Block comments keep the esbuild rule because a `/* */` comment cannot quote a `/*#__PURE__*/`, and `/** @__PURE__ */` must keep working. - Four existing tests in `test/bundler/bundler_comments.test.ts` put text before the marker and asserted removal. They came in with the SIMD lexer change (#19134) to exercise the scanner, and now assert that the call is kept. `test/bundler/transpiler/transpiler.test.js:1589` was a victim of this bug: the `@__PURE__` text in the commented-out lines above it deleted the first `err(...)` call, which asserted a TSX-only error for the `ts` loader. It now asserts the `ts` behavior, as in esbuild's `ts_parser_test.go`. - Verified: `test/bundler/bundler_comments.test.ts` (4 new cases) and `test/cli/install/bun-run.test.ts` (1 new runtime case). Both fail on the release binary. Also ran `test/bundler/esbuild/dce.test.ts`, `default.test.ts`, `tsconfig.test.ts`, `bundler_minify.test.ts`, `bundler_jsx.test.ts`, `transpiler/transpiler.test.js`, `transpiler/react-compiler.test.ts`. ### Background - A pure annotation (`/* @__PURE__ */ f()`) tells a bundler that the call has no side effects. If the result is unused, the call can be removed. - Bun's `dead_code_elimination` parser feature is on by default, also for `bun run`. The SExpr visitor (`src/js_parser/visit/visit_stmt.rs:1430`) calls `SideEffects::simplify_unused_expr` with no minify gate, and `scan_side_effects.rs` drops a call marked `IfUnused` whose arguments have no side effects. The docs describe pure annotation support as "Always active". - `has_pure_comment_before` is reset at the start of `Lexer::next()` and read in `parse_expr_common` (`src/js_parser/parse/mod.rs:75`), which marks the next `ECall` or `ENew` as `CanBeUnwrapped::IfUnused`. <details><summary>Notes</summary> Repro under bun 1.4.1: ``` $ bun -e 'function repro() { // `/*#__PURE__*/` console.log("This should not be deleted"); } console.log(repro.toString());' function repro() {} ``` esbuild 0.21.5 attaches the annotation to the same input but keeps the call unless `--minify-syntax` is passed. Alternative considered: gate the removal of a pure-marked expression statement on `minify_syntax`, as esbuild does. That changes documented runtime behavior and unminified `bun build` output for every correctly annotated call, so this PR narrows what counts as an annotation instead. A `/* see @__PURE__ for details */` block comment before a call still marks it pure. That is the esbuild rule and is not changed here. A quoted `/*#__PURE__*/` cannot occur inside a block comment, so the real-world reports all come from `//` comments. Self-reviewed: the review found the dead `transpiler.test.js` assertion and asked for the esbuild deviation to be stated. Both are addressed above. It also suggested gating `bun test` on `ignore_dce_annotations`. That is a separate change and is not in this PR. Unrelated failures seen locally with the debug build: two `bun-build-api.test.ts` bytecode tests that time out at 5s under the debug build. </details> <!-- robobun:evidence:begin --> --- **no test proof** · iteration 5 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/cli/install/bun-run.test.ts <!-- robobun:evidence:end -->
step 7.sweep-wip2: snapshot before cap-raise resume
step 5.fix0: route bun_s3_signing::error/Error via s3_signing mount path
step 4.fix0: drop package-rename deps; apply 4.2/4.4/4.5/4.6 seds
step 3.fix0: drop package-rename deps; apply 2.4/2.5/3.6 seds
step 1.fix0: regenerate stale build/debug/codegen rust outputs
Bun.serve: rename `h3`/`h1` options to `http3`/`http1` (#30583) ## What Renames the `Bun.serve()` `ServerConfig` HTTP/3 options from the abbreviated `h3` / `h1` to the spelled-out `http3` / `http1`. ```ts // before Bun.serve({ tls, h3: true, h1: false, fetch }) // after Bun.serve({ tls, http3: true, http1: false, fetch }) ``` These options have not shipped in a release yet, so this is a clean rename with no backwards-compat aliases. ## Changes - **`src/runtime/server/ServerConfig.zig` / `server.zig`**: rename the `ServerConfig` struct fields and the JS option lookups (`arg.get(global, "http3")`, etc.); update the validation error messages and the unix-socket warning. - **`packages/bun-types/serve.d.ts`**: rename the type declarations, drop the incorrect "(and HTTP/2)" from the `http1` JSDoc (Bun.serve does not support HTTP/2), and mark both options `@experimental`. - **`docs/runtime/http/server.mdx`**: add an "HTTP/3 (QUIC)" section documenting `http3` / `http1`, Alt-Svc, the unix-socket limitation, and the experimental status. - **Tests**: update `Bun.serve({ http3, http1 })` call sites, test names, and the validation error-message assertion across the HTTP/3 suites (`serve-http3.test.ts`, `serve-protocols.test.ts`, `body-stream.test.ts`, `fetch-http3-client.test.ts`, `fetch-http3-adversarial.test.ts`, `direct-readable-stream.test.tsx`, `fetch-h3.ts`, `packages/h3blast/`). ## Notes - The internal `uws.AnyRequest` union variants (`.h1`/`.h3`) are left as-is — those tag a transport, not a config option. - The `fetch()` `protocol` option (`"http1.1" | "h1" | "http2" | "h2" | "http3" | "h3"`) is unchanged; it already accepts both spellings. - `zig:check` and the `bun-types` `tsc` test pass locally. The full HTTP/3 test suite will run in CI.
PreviousNext