perf(rust): return impl ExactSizeIterator from slice-backed accessors#24144
Merged
Conversation
Member
Author
Merge activity
|
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 4, 2026
…#24144) These slice/`Vec`/`IndexVec`-backed accessors are already `ExactSizeIterator` internally (`slice::iter().map(..)` / `.copied()` / `.rev()`, `iter_enumerated()`, `HashMap::values()`, `(0..len).map(..)`) — the `impl Iterator` return type just erased it. Widening to `impl ExactSizeIterator` lets callers pre-size collections from the known length: ```rust let mut v = Vec::with_capacity(scoping.symbol_ids().len()); v.extend(scoping.symbol_ids().filter_map(..)); ``` instead of growing a `Vec` through reallocs, and lets callers call `.len()` directly. Backward-compatible: `ExactSizeIterator: Iterator`, so existing callers are unaffected. Two ordering details make it compile: - The `multi_index_vec!` `iter_ids` (`(0..len).map(..)`) is widened first so the bound propagates to `SymbolTable`/`ScopeTable`, which is what lets `symbol_ids`/`scope_descendants_from_root` widen. - The delegating `TraverseCtx::ancestors` is widened after its `TraverseAncestry::ancestors` source — an opaque `impl Iterator` only re-exposes `ExactSizeIterator` if the inner signature declares it. Widened accessors: - **oxc_semantic**: `Scoping::{symbol_names, resolved_references, symbol_ids, scope_descendants_from_root, iter_bindings, iter_bindings_in}`, `AstNodes::{iter, iter_enumerated}`, `ClassTable::{iter_enumerated, iter_private_identifiers}`, `multi_index_vec!` `iter_ids` - **oxc_traverse** / **oxc_minifier**: `TraverseAncestry::ancestors`, `TraverseCtx::ancestors` - **oxc_formatter_core**: `SourceText::{bytes_from, bytes_to}` - **oxc_codegen**: `Codegen::current_class_ids`
graphite-app
Bot
force-pushed
the
perf/exact-size-iterator-accessors
branch
from
July 4, 2026 02:44
2d2a9f0 to
2a6564b
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
…#24144) These slice/`Vec`/`IndexVec`-backed accessors are already `ExactSizeIterator` internally (`slice::iter().map(..)` / `.copied()` / `.rev()`, `iter_enumerated()`, `HashMap::values()`, `(0..len).map(..)`) — the `impl Iterator` return type just erased it. Widening to `impl ExactSizeIterator` lets callers pre-size collections from the known length: ```rust let mut v = Vec::with_capacity(scoping.symbol_ids().len()); v.extend(scoping.symbol_ids().filter_map(..)); ``` instead of growing a `Vec` through reallocs, and lets callers call `.len()` directly. Backward-compatible: `ExactSizeIterator: Iterator`, so existing callers are unaffected. Two ordering details make it compile: - The `multi_index_vec!` `iter_ids` (`(0..len).map(..)`) is widened first so the bound propagates to `SymbolTable`/`ScopeTable`, which is what lets `symbol_ids`/`scope_descendants_from_root` widen. - The delegating `TraverseCtx::ancestors` is widened after its `TraverseAncestry::ancestors` source — an opaque `impl Iterator` only re-exposes `ExactSizeIterator` if the inner signature declares it. Widened accessors: - **oxc_semantic**: `Scoping::{symbol_names, resolved_references, symbol_ids, scope_descendants_from_root, iter_bindings, iter_bindings_in}`, `AstNodes::{iter, iter_enumerated}`, `ClassTable::{iter_enumerated, iter_private_identifiers}`, `multi_index_vec!` `iter_ids` - **oxc_traverse** / **oxc_minifier**: `TraverseAncestry::ancestors`, `TraverseCtx::ancestors` - **oxc_formatter_core**: `SourceText::{bytes_from, bytes_to}` - **oxc_codegen**: `Codegen::current_class_ids`
graphite-app
Bot
force-pushed
the
perf/exact-size-iterator-accessors
branch
from
July 4, 2026 02:46
2a6564b to
c59f2fe
Compare
graphite-app Bot
pushed a commit
to rolldown/rolldown
that referenced
this pull request
Jul 4, 2026
These accessors are already `ExactSizeIterator` internally — the `impl Iterator` return type just erased it. Widening to `impl ExactSizeIterator` lets callers pre-size collections from the known length (`Vec::with_capacity(iter.len())`) instead of growing through reallocs, and lets them call `.len()` directly. Backward-compatible: `ExactSizeIterator: Iterator`, so existing callers are unaffected. | accessor | backing | |---|---| | `ChunkGraph::sorted_chunks` | `Vec<ChunkIdx>::iter().map(..)` | | `PluginDriver::iter_plugin_with_context_by_order` | `&[PluginIdx]::iter().copied().map(..)` | | `StmtInfos::iter_enumerated_without_namespace_stmt` | `IndexVec::iter_enumerated().skip(1)` (`Skip` preserves the exact len) | | `HybridIndexVec::iter` | `Either<IndexVec::iter(), FxHashMap::values()>` (both arms `ExactSizeIterator`) | | `ScanMode::iter` | `Either<iter::empty(), slice::iter()>` (both arms `ExactSizeIterator`) | | `DependedRuntimeHelperMap::iter` | `[Vec<_>; N]::iter().enumerate().map(..)` | The rest of the crate's `impl Iterator` accessors are correctly left alone — they use `filter_map` / `flat_map` / custom iterators that erase the length. Same idea as oxc-project/oxc#24144.
This was referenced Jul 6, 2026
Boshen
added a commit
that referenced
this pull request
Jul 6, 2026
# Oxlint ### 🚀 Features - 7db7a29 allocator: Add `ReplaceWith` trait (#24012) (overlookmotel) - a2c97f3 linter/unicorn: Implement `explicit-timer-delay` rule (#23612) (Mikhail Baev) - 85735cb linter/unicorn: Implement `no-confusing-array-with` rule (#23638) (Shekhu☺️ ) - cb4fbb9 linter/eslint: Implement no-unreachable-loop rule (#23975) (Todor Andonov) - dc32112 linter/eslint/no-constant-binary-expression: Check relational comparisons (#24088) (camc314) - 439c344 linter/jsdoc: Added missing options to `jsdoc/require-param` rule (#23364) (kapobajza) - 62af717 linter/unicorn/filename-case: Add `lowercase` and `screamingSnakeCase` (#24045) (Boshen) - d963967 linter/unicorn/no-array-sort: Add `allowAfterSpread` option (#24043) (Boshen) - 0a75682 linter: Add per-rule timings for type-aware linting (#22488) (camchenry) - 743e222 linter/react: Add `disallowedValues` option for `forbid-dom-props` rule (#23970) (Mikhail Baev) ### 🐛 Bug Fixes - 7b80010 linter: Use direct binding symbol ids (#24216) (camc314) - 8f94b49 linter/import/no-duplicates: Don't flag a type-only import beside a side-effect import (#24030) (Boshen) - d8c3fee linter/react/rules-of-hooks: Flag `useEffectEvent` escapes (#23764) (Rayan Salhab) - 0a7312b linter/no-deprecated-functions: Map `require.requireActual` to `jest.requireActual` (#23627) (Jerry Zhao) - d9e3ab3 linter/eslint/no-useless-return: Handle switch case continuation (#23984) (camc314) - 0b25582 ast: Type binding node `typeAnnotation` as `TSTypeAnnotation | null` (#23113) (Boshen) - 122d112 linter/eslint/no-restricted-imports: Flag dynamic import() expressions (#24029) (Boshen) - 59b6b83 linter: Avoid `OnceLock` re-entry on cyclic `export *` re-exports (#23632) (Jerry Zhao) - dd09af0 linter/import/namespace: Avoid panic on destructuring of an unresolvable namespace re-export (#23626) (Jerry Zhao) - bdb51c7 linter/jest/prefer-ending-with-an-expect: Validate config patterns (#24122) (camc314) - e383843 linter/unicorn/prefer-modern-dom-apis: Skip fixer for non identifier arguments (#23630) (Jerry Zhao) - 0ac4c83 linter: Detect circular config extends (#24115) (camc314) - bae1edf linter/import/namespace: Check namespace imports after named imports (#24094) (camc314) - cd8fdfe linter/eslint/no-eval: Recognize Array.from family thisArg (#24091) (camc314) - 851ee43 linter/eslint/no-eval: Resolve this binding for functions returned from an IIFE (#23643) (Jerry Zhao) - 002ab35 linter/unicorn: Avoid prefer-array-find rest destructuring false positive (#23654) (ColemanDunn) - 01c8775 linter/unicorn/filename-case: Keep digits attached in screamingSnakeCase (#24056) (Boshen) - f256941 linter: Recognize `@effect/vitest` as a vitest import source (#24025) (Boshen) - 73eeb1d linter/import/extensions: Honor per-extension `never` for explicit extensions (#24031) (Boshen) - d4ebe1f linter: Reject non-object oxlint config files (#24026) (Boshen) - 45d607d linter/react/forbid-component-props: Make allow/disallow lists optional in schema (#24024) (Boshen) - 54076ad linter/unicorn/no-array-for-each: Suggest entries loop for index callbacks (#24004) (camc314) - d057736 linter/jsdoc: Avoid param root underflow (#23945) (camc314) - 29c76bf linter/unicorn/prefer-at: Skip object numeric-key access (#23909) (Gaurav Dubey) ### ⚡ Performance - 657a8fc linter/oxc/bad-array-method-on-arguments: Only run on member expressions instead of all identifiers (#24164) (camchenry) - 073d9e7 linter/eslint/prefer-rest-params: Run on functions instead of all identifiers (#24163) (camchenry) - e5a4162 linter/jest/no-confusing-set-timeout: Early exit fast path (#24092) (camc314) - bca7ce5 linter: Only run react-perf rules on JSX attribute nodes (#24083) (camchenry) - 6881bf6 linter: Compute `apply_overrides` rule set lazily (#23648) (Jerry Zhao) - 911c106 linter/eslint/no-obj-calls: Use resolved reference instead of scope walk (#23895) (Marius Schulz) - dc8fd9a linter/unicorn/prefer-dom-node-text-content: Change dispatch to run only on less common node types (#23897) (Connor Shea) - fdbd34d linter/eslint/no-useless-call: Fast-path static callees (#24077) (camc314) - b1be114 linter/import/extensions: Skip empty config and borrow extensions (#24075) (camc314) - 4781b2d linter/eslint/no-obj-calls: Use direct global matches (#24076) (camc314) - e6cee89 linter: Avoid node-chain allocation for non-Jest calls (#23907) (Yagiz Nizipli) - 30dc517 linter/typescript/no-restricted-types: O(1) banned-type lookups (#23827) (Yagiz Nizipli) ### 📚 Documentation - 6ca9125 linter/typescript: Clarify consistent-type-imports behavior (#23972) (camc314) # Oxfmt ### 🚀 Features - 4f4313e formatter_css: Update oxc-css-parser 0.0.5 (#24120) (leaysgur) - 0ccd8a1 formatter_graphql: Update oxc-graphql-parser 0.0.5 (#24106) (leaysgur) - 89ec3d9 formatter_core: Add literal line and root indention primitives (#24051) (leaysgur) - 213a96b formatter_core: Add no-expand-parent for multiline text (#24050) (leaysgur) - 0e5bcc9 formatter_graphql: Update oxc-graphql-parser 0.0.4 (#24039) (leaysgur) - e0b35a1 formatter_css: Update `[email protected]` (#23974) (leaysgur) ### 🐛 Bug Fixes - 1fe6546 formatter: Omit unneeded `;` for type members with `no-semi` (#24212) (leaysgur) - 0ad7316 formatter: Print space for `ForStatement`.`update` only if exists (#24211) (leaysgur) - 3abbed5 formatter: Print `;` before jsdoc type-cast parens with no-semi (#24208) (leaysgur) - 9af3833 formatter_css: Make scss formatter consistent (#24207) (leaysgur) - 46d7194 formatter_css: Use fill IR for `@forward` members (#24206) (leaysgur) - e31038f formatter_css: Keep comment inside sass config list (#24205) (leaysgur) - d3b9591 formatter: Add parens around `await/yield` with `<T>` (#24202) (leaysgur) - 2121a55 oxfmt: Reuse tinypool process during the same LSP process (#24197) (leaysgur) - 9bf4b4a formatter_css: Align CSS output to Prettier 3.9.1 (#24100) (leaysgur) - cd2452e formatter_css: Align SCSS output to Prettier 3.9.1 (#24097) (leaysgur) - 4ee8745 formatter_css: Keep selector value contain line-break without breaking line (#24055) (leaysgur) - e1ece97 formatter_graphql: Break `implements` list by print-width (#23997) (leaysgur) - 0a6b16c formatter_json: Preserve key and literal value for json-stringify (#23996) (leaysgur) - 903ab6e formatter_css: Preserve newlines in css-in-js selector list (#23992) (leaysgur) - ea5d095 oxfmt: Update `--migrate prettier` (#23963) (leaysgur) ### ⚡ Performance - 468e1e3 formatter_core: Make printer queues cursor-based (#24098) (Boshen) - c59f2fe rust: Return impl ExactSizeIterator from slice-backed accessors (#24144) (Boshen) - c292fb2 formatter: Inline fits element dispatcher (#23982) (camc314) Co-authored-by: Boshen <[email protected]>
Boshen
added a commit
that referenced
this pull request
Jul 6, 2026
### 🚀 Features - 260425f semantic/examples: Include unresolved references (#24214) (camc314) - 2d9b0b3 minifier: Fold boolean-literal ternary branches in value contexts (#24110) (Dunqing) - 61fbf10 ast: Implement `ReplaceWith` on all AST types (#24013) (overlookmotel) - 7db7a29 allocator: Add `ReplaceWith` trait (#24012) (overlookmotel) - 4eb074e mangler: Add `reserved` option for names that must not be mangled (#24041) (Dunqing) - 2e62012 data_structures: Add `StringExt` trait (#24006) (overlookmotel) - 60e7160 minifier: Drop side-effect-free IIFEs whose result is unused (#23967) (Dunqing) - 26dd9e2 ast: Add method to widen inherited enum ref to parent ref (#23961) (overlookmotel) ### 🐛 Bug Fixes - e8b50ee transformer: Clean up semantics for stripped TypeScript syntax (#24180) (camc314) - d966d0b react_compiler: Remove clippy allows (#24168) (Boshen) - 854ef8d react_compiler: Compile generic functions instead of over-bailing on type-param hoisting (#24158) (Boshen) - 093586c react_compiler: Align memoization cache-slot allocation with Babel (#24157) (Boshen) - 09c8f59 react_compiler: Normalize snapshot fixture paths (#24142) (camc314) - f13df97 react_compiler: Drop stray empty statement from catch bindings (#24133) (Boshen) - cb2a505 react_compiler: Codegen destructuring reassignment targets (#24131) (Boshen) - b82c394 react_compiler: Propagate codegen invariants instead of emitting empty bodies (#24128) (Boshen) - 5771982 react_compiler: Render unchanged programs as source in fixture snapshots (#24129) (Boshen) - 4b16e1a transformer/async-to-generator: Preserve direct eval scope flags (#24136) (camc314) - 4e9194f react_compiler: Lower `delete obj.prop` to Property/ComputedDelete (#24123) (Boshen) - 0b25582 ast: Type binding node `typeAnnotation` as `TSTypeAnnotation | null` (#23113) (Boshen) - 018c0e5 transformer: Hoist lowered async declarations (#22770) (camc314) - 652fbaf mangler: Keep names of destructured exported bindings (#24036) (Dunqing) - e274415 minifier: Don't drop global calls that throw despite pure arguments (#23917) (Dunqing) - 59abb30 minifier: Only merge string literals in `try_fold_add` when the inner operator is `+` (#23622) (Jerry Zhao) ### ⚡ Performance - c5ca77b transformer: Avoid cloning refresh options (#24191) (camc314) - bf1a151 react_compiler: Compile out debug printers (#24184) (Boshen) - abb44a0 transformer: Build fixed object-rest arguments (#24190) (camc314) - a4db731 isolated_declarations: Use `ReplaceWith` instead of `TakeIn` (#24016) (overlookmotel) - ff10855 transformer: Use `ReplaceWith` instead of `TakeIn` (#24015) (overlookmotel) - bd49aff ecmascript: Avoid heap-allocating Math.min/max/imul operands (#23941) (Lawrence Lin) - e4b708b react_compiler: Skip compiled files before prefilters (#24171) (Boshen) - c59f2fe rust: Return impl ExactSizeIterator from slice-backed accessors (#24144) (Boshen) - 5d6d04a codegen: SWAR-skip boring byte runs in sourcemap line/column scan (#24023) (Boshen) - a55e0be traverse: Reduce string operations in `get_var_name_from_node` (#24007) (overlookmotel) - e6d48e1 transformer/nullish_coalescing: Move cold path into separate function (#23989) (overlookmotel) - c4e35b5 transformer/object_rest_spread: Pre-allocate capacity in `Vec` (#23988) (overlookmotel) - 527b8e5 transformer/decorators: Narrow type earlier (#23987) (overlookmotel) ### 📚 Documentation - 30d17f5 allocator: Clarify docs for `TakeIn::take_in_box` (#24093) (overlookmotel) - 675e6a8 ast: Correct doc comment for `PrivateFieldExpression` (#24008) (overlookmotel) - e4c30e6 minifier: Explain what `dce` mode means (#23994) (Dunqing) - 37cbf88 ast_macros: Document fields of `StructDetails` (#23959) (overlookmotel) - 4de3e54 ast: Correct doc comment (#23948) (overlookmotel) Co-authored-by: Boshen <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
These slice/
Vec/IndexVec-backed accessors are alreadyExactSizeIteratorinternally (slice::iter().map(..)/.copied()/.rev(),iter_enumerated(),HashMap::values(),(0..len).map(..)) — theimpl Iteratorreturn type just erased it.Widening to
impl ExactSizeIteratorlets callers pre-size collections from the known length:instead of growing a
Vecthrough reallocs, and lets callers call.len()directly.Backward-compatible:
ExactSizeIterator: Iterator, so existing callers are unaffected.Two ordering details make it compile:
multi_index_vec!iter_ids((0..len).map(..)) is widened first so the bound propagates toSymbolTable/ScopeTable, which is what letssymbol_ids/scope_descendants_from_rootwiden.TraverseCtx::ancestorsis widened after itsTraverseAncestry::ancestorssource — an opaqueimpl Iteratoronly re-exposesExactSizeIteratorif the inner signature declares it.Widened accessors:
Scoping::{symbol_names, resolved_references, symbol_ids, scope_descendants_from_root, iter_bindings, iter_bindings_in},AstNodes::{iter, iter_enumerated},ClassTable::{iter_enumerated, iter_private_identifiers},multi_index_vec!iter_idsTraverseAncestry::ancestors,TraverseCtx::ancestorsSourceText::{bytes_from, bytes_to}Codegen::current_class_ids