fix issue + add test

pull/14315/head
Dominic Gannaway 2 years ago
parent eaff9713f5
commit bc6f857ea5

@ -82,7 +82,7 @@ export function SnippetBlock(node, context) {
const declaration = b.const(node.expression, snippet);
const local_scope = context.state.scope;
const can_hoist = can_hoist_snippet(node, local_scope);
const can_hoist = can_hoist_snippet(node, local_scope, context.state.scopes);
// Top-level snippets are hoisted so they can be referenced in the `<script>`
if (context.path.length === 1 && context.path[0].type === 'Fragment') {

@ -18,7 +18,7 @@ export function SnippetBlock(node, context) {
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
fn.___snippet = true;
const can_hoist = can_hoist_snippet(node, context.state.scope);
const can_hoist = can_hoist_snippet(node, context.state.scope, context.state.scopes);
if (context.path.length === 1 && context.path[0].type === 'Fragment' && can_hoist) {
context.state.hoisted.push(fn);

@ -456,16 +456,17 @@ export function transform_inspect_rune(node, context) {
/**
* @param {AST.SnippetBlock} node
* @param {Map<SvelteNode, Scope>} scopes
* @param {Scope} scope
*/
export function can_hoist_snippet(node, scope) {
export function can_hoist_snippet(node, scope, scopes, visited = new Set()) {
let can_hoist = true;
ref_loop: for (const [reference] of scope.references) {
const local_binding = scope.get(reference);
if (local_binding) {
if (local_binding.node === node.expression) {
if (local_binding.node === node.expression || local_binding.scope.function_depth === 0) {
continue;
}
/** @type {Scope | null} */
@ -477,6 +478,24 @@ export function can_hoist_snippet(node, scope) {
}
current_scope = current_scope.parent;
}
// Recursively check if another snippet can be hoisted
if (local_binding.kind === 'normal') {
for (const ref of local_binding.references) {
const parent = ref.path.at(-1);
if (ref.node === local_binding.node && parent?.type === 'SnippetBlock') {
const ref_scope = scopes.get(parent);
if (visited.has(ref)) {
break;
}
visited.add(ref);
if (ref_scope && can_hoist_snippet(parent, ref_scope, scopes, visited)) {
continue ref_loop;
}
break;
}
}
}
can_hoist = false;
break;
}

@ -279,7 +279,8 @@ export interface Binding {
| 'snippet'
| 'store_sub'
| 'legacy_reactive'
| 'template';
| 'template'
| 'snippet';
declaration_kind: DeclarationKind;
/**
* What the value was initialized with.

@ -0,0 +1,13 @@
<script module>
const message = 'hello';
export { one };
</script>
{#snippet one()}
{@render two()}
{/snippet}
{#snippet two()}
{message}
{/snippet}

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true // Render in dev mode to check that the validation error is not thrown
},
html: `hello`
});

@ -0,0 +1,5 @@
<script>
import { one } from './Child.svelte';
</script>
{@render one()}
Loading…
Cancel
Save