From 348844d758a631033510c67e62dafb2e2b3480ad Mon Sep 17 00:00:00 2001 From: ljodea Date: Wed, 29 Jul 2026 16:37:50 -0500 Subject: [PATCH] perf: O(1) membership in sort_const_tags topological sort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DFS over {@const} tags used sorted.includes(node) (O(n) per check → O(n²) overall). Track visited nodes with a Set so membership is O(1) while keeping the same order and cycle handling. Closes #18599 --- .changeset/sort-const-tags-set.md | 5 +++++ .../svelte/src/compiler/phases/3-transform/utils.js | 6 +++++- .../samples/const-tag-reverse-diamond/_config.js | 13 +++++++++++++ .../samples/const-tag-reverse-diamond/main.svelte | 10 ++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .changeset/sort-const-tags-set.md create mode 100644 packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/_config.js create mode 100644 packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/main.svelte diff --git a/.changeset/sort-const-tags-set.md b/.changeset/sort-const-tags-set.md new file mode 100644 index 0000000000..2c1771fb5b --- /dev/null +++ b/.changeset/sort-const-tags-set.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +perf: O(1) membership in `{@const}` topological sort (`sort_const_tags`) diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index c7fce61ff9..f04911822f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -87,9 +87,12 @@ function sort_const_tags(nodes, state) { /** @type {AST.ConstTag[]} */ const sorted = []; + /** @type {Set} */ + const seen = new Set(); + /** @param {Tag} tag */ function add(tag) { - if (sorted.includes(tag.node)) { + if (seen.has(tag.node)) { return; } @@ -98,6 +101,7 @@ function sort_const_tags(nodes, state) { if (dep_tag) add(dep_tag); } + seen.add(tag.node); sorted.push(tag.node); } diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/_config.js new file mode 100644 index 0000000000..ed7bb52573 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +// sum is declared before left/right; sort_const_tags must emit deps first. +// Also exercises multi-parent membership (sum → left and sum → right). +export default test({ + html: '

23

', + + async test({ component, target, assert }) { + component.n = 1; + + assert.htmlEqual(target.innerHTML, '

5

'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/main.svelte new file mode 100644 index 0000000000..ffb5191f80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-reverse-diamond/main.svelte @@ -0,0 +1,10 @@ + + +{#if true} + {@const sum = left + right} + {@const left = n + 1} + {@const right = n + 2} +

{sum}

+{/if}