Skip to content

Commit 5953c9f

Browse files
authored
fix(compiler-core): identifiers in switch-case should not be inferred as references (#13923)
1 parent 565741a commit 5953c9f

File tree

2 files changed

+89
-7
lines changed

2 files changed

+89
-7
lines changed

packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,4 +716,42 @@ describe('compiler: expression transform', () => {
716716
})
717717
})
718718
})
719+
720+
describe('switch case variable declarations', () => {
721+
test('should handle const declarations in switch case without braces', () => {
722+
const { code } = compile(
723+
`{{ (() => { switch (1) { case 1: const foo = "bar"; return \`\${foo}\`; } })() }}`,
724+
)
725+
726+
expect(code).toMatch(`const foo = "bar";`)
727+
expect(code).toMatch(`return \`\${foo}\`;`)
728+
expect(code).not.toMatch(`_ctx.foo`)
729+
})
730+
731+
test('should handle const declarations in switch case with braces (existing behavior)', () => {
732+
const { code } = compile(
733+
`{{ (() => {
734+
switch (true) {
735+
case true: {
736+
const foo = "bar";
737+
return \`\${foo}\`;
738+
}
739+
}
740+
})() }}`,
741+
)
742+
743+
expect(code).toMatch(`const foo = "bar";`)
744+
expect(code).toMatch(`return \`\${foo}\`;`)
745+
expect(code).not.toMatch(`_ctx.foo`)
746+
})
747+
748+
test('should parse switch case test as local scoped variables', () => {
749+
const { code } = compile(
750+
`{{ (() => { switch (foo) { case bar: return \`\${bar}\`; } })() }}`,
751+
)
752+
753+
expect(code).toMatch('_ctx.foo')
754+
expect(code).toMatch(`_ctx.bar`)
755+
})
756+
})
719757
})

packages/compiler-core/src/babelUtils.ts

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import type {
1010
Node,
1111
ObjectProperty,
1212
Program,
13+
SwitchCase,
14+
SwitchStatement,
1315
} from '@babel/types'
1416
import { walk } from 'estree-walker'
1517

@@ -80,14 +82,31 @@ export function walkIdentifiers(
8082
markScopeIdentifier(node, id, knownIds),
8183
)
8284
}
85+
} else if (node.type === 'SwitchStatement') {
86+
if (node.scopeIds) {
87+
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
88+
} else {
89+
// record switch case block-level local variables
90+
walkSwitchStatement(node, false, id =>
91+
markScopeIdentifier(node, id, knownIds),
92+
)
93+
}
8394
} else if (node.type === 'CatchClause' && node.param) {
84-
for (const id of extractIdentifiers(node.param)) {
85-
markScopeIdentifier(node, id, knownIds)
95+
if (node.scopeIds) {
96+
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
97+
} else {
98+
for (const id of extractIdentifiers(node.param)) {
99+
markScopeIdentifier(node, id, knownIds)
100+
}
86101
}
87102
} else if (isForStatement(node)) {
88-
walkForStatement(node, false, id =>
89-
markScopeIdentifier(node, id, knownIds),
90-
)
103+
if (node.scopeIds) {
104+
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
105+
} else {
106+
walkForStatement(node, false, id =>
107+
markScopeIdentifier(node, id, knownIds),
108+
)
109+
}
91110
}
92111
},
93112
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
@@ -187,10 +206,11 @@ export function walkFunctionParams(
187206
}
188207

189208
export function walkBlockDeclarations(
190-
block: BlockStatement | Program,
209+
block: BlockStatement | SwitchCase | Program,
191210
onIdent: (node: Identifier) => void,
192211
): void {
193-
for (const stmt of block.body) {
212+
const body = block.type === 'SwitchCase' ? block.consequent : block.body
213+
for (const stmt of body) {
194214
if (stmt.type === 'VariableDeclaration') {
195215
if (stmt.declare) continue
196216
for (const decl of stmt.declarations) {
@@ -206,6 +226,8 @@ export function walkBlockDeclarations(
206226
onIdent(stmt.id)
207227
} else if (isForStatement(stmt)) {
208228
walkForStatement(stmt, true, onIdent)
229+
} else if (stmt.type === 'SwitchStatement') {
230+
walkSwitchStatement(stmt, true, onIdent)
209231
}
210232
}
211233
}
@@ -239,6 +261,28 @@ function walkForStatement(
239261
}
240262
}
241263

264+
function walkSwitchStatement(
265+
stmt: SwitchStatement,
266+
isVar: boolean,
267+
onIdent: (id: Identifier) => void,
268+
) {
269+
for (const cs of stmt.cases) {
270+
for (const stmt of cs.consequent) {
271+
if (
272+
stmt.type === 'VariableDeclaration' &&
273+
(stmt.kind === 'var' ? isVar : !isVar)
274+
) {
275+
for (const decl of stmt.declarations) {
276+
for (const id of extractIdentifiers(decl.id)) {
277+
onIdent(id)
278+
}
279+
}
280+
}
281+
}
282+
walkBlockDeclarations(cs, onIdent)
283+
}
284+
}
285+
242286
export function extractIdentifiers(
243287
param: Node,
244288
nodes: Identifier[] = [],

0 commit comments

Comments
 (0)