diff --git a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts index 5854a0ae8..e3088f4a2 100644 --- a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts @@ -652,6 +652,17 @@ export function lowerArrayLiteral( return lowered; }); if (!needsStateBuild) { + // `[...text]`: the code points call already builds a fresh array of the + // literal's type, so it is the literal's value, as `Array.from(text)` is. + const only = elems[0]; + if ( + elems.length === 1 && + spreads.length === 1 && + only?.kind === "libCall" && + only.fn === "str.codePoints" && + typeEquals(only.type, type) + ) + return { ...only, loc }; return { kind: "arrayLit", elems, ...(spreads.length > 0 ? { spreads } : {}), type, loc }; } const out = lowerer.declareHiddenLocal("%arrayLit", type); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/string-spread.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/string-spread.ts.json new file mode 100644 index 000000000..2c5cc69e8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/string-spread.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/string-spread.ts" + ], + "diags": [] +} diff --git a/tests/corpus/string-spread.ts b/tests/corpus/string-spread.ts new file mode 100644 index 000000000..6813806f4 --- /dev/null +++ b/tests/corpus/string-spread.ts @@ -0,0 +1,25 @@ +// Spreading strings into arrays: code points of each UTF-8 length, astral +// pairs, lone surrogates, the empty string, and the fresh array each spread +// returns. + +const samples = ["", "a", "abc", "é", "café", "日本語", "😀", "a😀b", "🚀🚀", "\ud800", "a\udc00b", "xé日😀"]; + +for (const s of samples) { + const chars = [...s]; + console.log(JSON.stringify(s), chars.length, JSON.stringify(chars), chars.join("|")); +} + +// Each spread is a new array: changing one leaves the others and the string. +const text = "héllo 😀"; +const first = [...text]; +const second = [...text]; +first.reverse(); +first.push("!"); +console.log(first.join(""), second.join(""), first === second, text); + +// The spread result is an ordinary array. +const letters = [..."naïve"]; +letters.sort(); +console.log(letters, letters.length, Array.isArray(letters)); +console.log([..."abc"].map((c) => c.toUpperCase()).join("")); +console.log([..."日本"].concat([..."語"]).join("-")); diff --git a/tests/harness/corpus-costs/string-spread.ts.json b/tests/harness/corpus-costs/string-spread.ts.json new file mode 100644 index 000000000..d7fbd510a --- /dev/null +++ b/tests/harness/corpus-costs/string-spread.ts.json @@ -0,0 +1 @@ +{ "plain": 4500, "san": 4300 }