diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js index 9f70981205a1..24a696e7d215 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js @@ -35,10 +35,6 @@ export function EachBlock(node, context) { context.state.template.push(''); } - if (each_node_meta.array_name !== null) { - context.state.init.push(b.const(each_node_meta.array_name, b.thunk(collection))); - } - let flags = 0; if (node.metadata.keyed && node.index) { @@ -120,8 +116,21 @@ export function EachBlock(node, context) { return [array, ...transitive_dependencies]; }); - if (each_node_meta.array_name) { - indirect_dependencies.push(b.call(each_node_meta.array_name)); + /** @type {Identifier | null} */ + let collection_id = null; + + // Check if inner scope shadows something from outer scope. + // This is necessary because we need access to the array expression of the each block + // in the inner scope if bindings are used, in order to invalidate the array. + for (const [name] of context.state.scope.declarations) { + if (context.state.scope.parent?.get(name) != null) { + collection_id = context.state.scope.root.unique('$$array'); + break; + } + } + + if (collection_id) { + indirect_dependencies.push(b.call(collection_id)); } else { indirect_dependencies.push(collection); @@ -195,7 +204,7 @@ export function EachBlock(node, context) { // TODO 6.0 this only applies in legacy mode, reassignments are // forbidden in runes mode return b.member( - each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection, + collection_id ? b.call(collection_id) : collection, (flags & EACH_INDEX_REACTIVE) !== 0 ? get_value(index) : index, true ); @@ -207,7 +216,7 @@ export function EachBlock(node, context) { uses_index = true; const left = b.member( - each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection, + collection_id ? b.call(collection_id) : collection, (flags & EACH_INDEX_REACTIVE) !== 0 ? get_value(index) : index, true ); @@ -283,16 +292,17 @@ export function EachBlock(node, context) { ); } + const render_args = [b.id('$$anchor'), item]; + if (uses_index || collection_id) render_args.push(index); + if (collection_id) render_args.push(collection_id); + /** @type {Expression[]} */ const args = [ context.state.node, b.literal(flags), - each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection), + b.thunk(collection), key_function, - b.arrow( - uses_index ? [b.id('$$anchor'), item, index] : [b.id('$$anchor'), item], - b.block(declarations.concat(block.body)) - ) + b.arrow(render_args, b.block(declarations.concat(block.body))) ]; if (node.fallback) { diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index 3536dd6a1865..51e9eb088dc9 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -575,21 +575,10 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { } if (node.fallback) visit(node.fallback, { scope }); - // Check if inner scope shadows something from outer scope. - // This is necessary because we need access to the array expression of the each block - // in the inner scope if bindings are used, in order to invalidate the array. - let needs_array_deduplication = false; - for (const [name] of scope.declarations) { - if (state.scope.get(name) !== null) { - needs_array_deduplication = true; - } - } - node.metadata = { expression: create_expression_metadata(), keyed: false, contains_group_binding: false, - array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null, index: scope.root.unique('$$index'), declarations: scope.declarations, is_controlled: false diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index fb609668957d..1f266c5248ee 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -414,8 +414,6 @@ export namespace AST { expression: ExpressionMetadata; keyed: boolean; contains_group_binding: boolean; - /** Set if something in the array expression is shadowed within the each block */ - array_name: Identifier | null; index: Identifier; declarations: Map; /** diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index b17090948ae7..040e58521548 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -271,7 +271,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f * @param {Array} array * @param {EachState} state * @param {Element | Comment | Text} anchor - * @param {(anchor: Node, item: MaybeSource, index: number | Source) => void} render_fn + * @param {(anchor: Node, item: MaybeSource, index: number | Source, collection: () => V[]) => void} render_fn * @param {number} flags * @param {boolean} is_inert * @param {(value: V, index: number) => any} get_key @@ -510,7 +510,7 @@ function update_item(item, value, index, type) { * @param {V} value * @param {unknown} key * @param {number} index - * @param {(anchor: Node, item: V | Source, index: number | Value) => void} render_fn + * @param {(anchor: Node, item: V | Source, index: number | Value, collection: () => V[]) => void} render_fn * @param {number} flags * @param {() => V[]} get_collection * @returns {EachItem} @@ -559,7 +559,7 @@ function create_item( current_each_item = item; try { - item.e = branch(() => render_fn(anchor, v, i), hydrating); + item.e = branch(() => render_fn(anchor, v, i, get_collection), hydrating); item.e.prev = prev && prev.e; item.e.next = next && next.e;