diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index 95d7d00677..0eb98c27e8 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -706,7 +706,7 @@ function special(parser) { expression: /** @type {AST.RenderTag['expression']} */ (expression), metadata: { dynamic: false, - args_with_call_expression: new Set(), + arguments: [], path: [], snippets: new Set() } diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index c65eb5f955..bce6672505 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -605,7 +605,6 @@ export function analyze_component(root, source, options) { has_props_rune: false, component_slots: new Set(), expression: null, - render_tag: null, private_derived_state: [], function_depth: scope.function_depth, instance_scope: instance.scope, @@ -677,7 +676,6 @@ export function analyze_component(root, source, options) { reactive_statements: analysis.reactive_statements, component_slots: new Set(), expression: null, - render_tag: null, private_derived_state: [], function_depth: scope.function_depth }; diff --git a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts index b4ca4dc262..1e71accb9f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts +++ b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts @@ -19,8 +19,6 @@ export interface AnalysisState { component_slots: Set; /** Information about the current expression/directive/block value */ expression: ExpressionMetadata | null; - /** The current {@render ...} tag, if any */ - render_tag: null | AST.RenderTag; private_derived_state: string[]; function_depth: number; diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js index 9f51cd61de..96788d9f93 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js @@ -186,18 +186,6 @@ export function CallExpression(node, context) { break; } - if (context.state.render_tag) { - // Find out which of the render tag arguments contains this call expression - const arg_idx = unwrap_optional(context.state.render_tag.expression).arguments.findIndex( - (arg) => arg === node || context.path.includes(arg) - ); - - // -1 if this is the call expression of the render tag itself - if (arg_idx !== -1) { - context.state.render_tag.metadata.args_with_call_expression.add(arg_idx); - } - } - if (node.callee.type === 'Identifier') { const binding = context.state.scope.get(node.callee.name); diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/RenderTag.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/RenderTag.js index 045224276a..a8c9d408bd 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/RenderTag.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/RenderTag.js @@ -5,6 +5,7 @@ import * as e from '../../../errors.js'; import { validate_opening_tag } from './shared/utils.js'; import { mark_subtree_dynamic } from './shared/fragment.js'; import { is_resolved_snippet } from './shared/snippets.js'; +import { create_expression_metadata } from '../../nodes.js'; /** * @param {AST.RenderTag} node @@ -15,7 +16,8 @@ export function RenderTag(node, context) { node.metadata.path = [...context.path]; - const callee = unwrap_optional(node.expression).callee; + const expression = unwrap_optional(node.expression); + const callee = expression.callee; const binding = callee.type === 'Identifier' ? context.state.scope.get(callee.name) : null; @@ -52,5 +54,15 @@ export function RenderTag(node, context) { mark_subtree_dynamic(context.path); - context.next({ ...context.state, render_tag: node }); + context.visit(callee); + + for (const arg of expression.arguments) { + const metadata = create_expression_metadata(); + node.metadata.arguments.push(metadata); + + context.visit(arg, { + ...context.state, + expression: metadata + }); + } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js index 7da987f6cc..33ae6d4d2b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js @@ -10,20 +10,24 @@ import * as b from '../../../../utils/builders.js'; */ export function RenderTag(node, context) { context.state.template.push(''); - const callee = unwrap_optional(node.expression).callee; - const raw_args = unwrap_optional(node.expression).arguments; + + const expression = unwrap_optional(node.expression); + + const callee = expression.callee; + const raw_args = expression.arguments; /** @type {Expression[]} */ let args = []; for (let i = 0; i < raw_args.length; i++) { - const raw = raw_args[i]; - const arg = /** @type {Expression} */ (context.visit(raw)); - if (node.metadata.args_with_call_expression.has(i)) { + let thunk = b.thunk(/** @type {Expression} */ (context.visit(raw_args[i]))); + const { has_call } = node.metadata.arguments[i]; + + if (has_call) { const id = b.id(context.state.scope.generate('render_arg')); - context.state.init.push(b.var(id, b.call('$.derived_safe_equal', b.thunk(arg)))); + context.state.init.push(b.var(id, b.call('$.derived_safe_equal', thunk))); args.push(b.thunk(b.call('$.get', id))); } else { - args.push(b.thunk(arg)); + args.push(thunk); } } diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 1f266c5248..a544cd1dec 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -166,7 +166,7 @@ export namespace AST { /** @internal */ metadata: { dynamic: boolean; - args_with_call_expression: Set; + arguments: ExpressionMetadata[]; path: SvelteNode[]; /** The set of locally-defined snippets that this render tag could correspond to, * used for CSS pruning purposes */