Skip to content

Commit 5b5e9ef

Browse files
committed
don't alias constant expressions
1 parent 1e55c1f commit 5b5e9ef

File tree

3 files changed

+166
-15
lines changed

3 files changed

+166
-15
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/ClassBody.js

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as b from '#compiler/builders';
55
import { dev } from '../../../../state.js';
66
import { get_parent } from '../../../../utils/ast.js';
77
import { get_name } from '../../../nodes.js';
8+
import { is_constant } from '../../../scope.js';
89

910
/**
1011
* @param {ClassBody} node
@@ -61,6 +62,20 @@ export function ClassBody(node, context) {
6162
);
6263
continue;
6364
}
65+
if (is_constant(computed_key, context.state.scope)) {
66+
body.push(
67+
b.prop_def(field.key, null),
68+
b.method('get', computed_key, [], [b.return(b.call('$.get', member))], true),
69+
b.method(
70+
'set',
71+
computed_key,
72+
[b.id('value')],
73+
[b.stmt(b.call('$.set', member, b.id('value'), should_proxy && b.true))],
74+
true
75+
)
76+
);
77+
continue;
78+
}
6479
const key = context.state.scope.generate('key');
6580
computed_field_declarations.push(b.let(key));
6681

@@ -163,18 +178,50 @@ export function ClassBody(node, context) {
163178
b.literal(`${declaration.id?.name ?? '[class]'}[computed key]`)
164179
);
165180
}
181+
const computed_key = /** @type {Expression} */ (context.visit(field.computed_key));
182+
const evaluation = context.state.scope.evaluate(computed_key);
183+
if (evaluation.is_known) {
184+
body.push(
185+
b.prop_def(field.key, call),
186+
b.method(
187+
'get',
188+
b.literal(evaluation.value),
189+
[],
190+
[b.return(b.call('$.get', member))],
191+
true
192+
),
193+
b.method(
194+
'set',
195+
b.literal(evaluation.value),
196+
[b.id('value')],
197+
[b.stmt(b.call('$.set', member, b.id('value'), should_proxy && b.true))],
198+
true
199+
)
200+
);
201+
continue;
202+
}
203+
if (is_constant(computed_key, context.state.scope)) {
204+
body.push(
205+
b.prop_def(field.key, call),
206+
b.method('get', computed_key, [], [b.return(b.call('$.get', member))], true),
207+
b.method(
208+
'set',
209+
computed_key,
210+
[b.id('value')],
211+
[b.stmt(b.call('$.set', member, b.id('value'), should_proxy && b.true))],
212+
true
213+
)
214+
);
215+
continue;
216+
}
166217
const key = context.state.scope.generate('key');
167218
computed_field_declarations.push(b.let(key));
168219

169220
body.push(
170221
b.prop_def(field.key, call),
171222
b.method(
172223
'get',
173-
b.assignment(
174-
'=',
175-
b.id(key),
176-
/** @type {Expression} */ (context.visit(field.computed_key))
177-
),
224+
b.assignment('=', b.id(key), computed_key),
178225
[],
179226
[b.return(b.call('$.get', member))],
180227
true

packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/** @import { Context } from '../types.js' */
33
import * as b from '#compiler/builders';
44
import { get_name } from '../../../nodes.js';
5+
import { is_constant } from '../../../scope.js';
56

67
/**
78
* @param {ClassBody} node
@@ -34,17 +35,43 @@ export function ClassBody(node, context) {
3435

3536
const member = b.member(b.this, field.key);
3637
if (typeof name !== 'string' && field.computed_key) {
38+
const computed_key = /** @type {Expression} */ (context.visit(field.computed_key));
39+
const evaluation = context.state.scope.evaluate(computed_key);
40+
if (evaluation.is_known) {
41+
body.push(
42+
b.prop_def(field.key, null),
43+
b.method('get', b.literal(evaluation.value), [], [b.return(b.call(member))], true),
44+
b.method(
45+
'set',
46+
b.literal(evaluation.value),
47+
[b.id('$$value')],
48+
[b.return(b.call(member, b.id('$$value')))],
49+
true
50+
)
51+
);
52+
continue;
53+
}
54+
if (is_constant(computed_key, context.state.scope)) {
55+
body.push(
56+
b.prop_def(field.key, null),
57+
b.method('get', computed_key, [], [b.return(b.call(member))], true),
58+
b.method(
59+
'set',
60+
computed_key,
61+
[b.id('$$value')],
62+
[b.return(b.call(member, b.id('$$value')))],
63+
true
64+
)
65+
);
66+
continue;
67+
}
3768
const key = context.state.scope.generate('key');
3869
computed_field_declarations.push(b.let(key));
3970
body.push(
4071
b.prop_def(field.key, null),
4172
b.method(
4273
'get',
43-
b.assignment(
44-
'=',
45-
b.id(key),
46-
/** @type {Expression} */ (context.visit(field.computed_key))
47-
),
74+
b.assignment('=', b.id(key), computed_key),
4875
[],
4976
[b.return(b.call(member))],
5077
true
@@ -133,6 +160,23 @@ export function ClassBody(node, context) {
133160
);
134161
continue;
135162
}
163+
if (is_constant(computed_key, context.state.scope)) {
164+
body.push(
165+
b.prop_def(
166+
field.key,
167+
/** @type {CallExpression} */ (context.visit(field.value, child_state))
168+
),
169+
b.method('get', computed_key, [], [b.return(b.call(member))], true),
170+
b.method(
171+
'set',
172+
computed_key,
173+
[b.id('$$value')],
174+
[b.return(b.call(member, b.id('$$value')))],
175+
true
176+
)
177+
);
178+
continue;
179+
}
136180
const key = context.state.scope.generate('key');
137181
computed_field_declarations.push(b.let(key));
138182
body.push(
@@ -142,11 +186,7 @@ export function ClassBody(node, context) {
142186
),
143187
b.method(
144188
'get',
145-
b.assignment(
146-
'=',
147-
b.id(key),
148-
/** @type {Expression} */ (context.visit(field.computed_key))
149-
),
189+
b.assignment('=', b.id(key), computed_key),
150190
[],
151191
[b.return(b.call(member))],
152192
true

packages/svelte/src/compiler/phases/scope.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,70 @@ export function get_rune(node, scope) {
13581358
return keypath;
13591359
}
13601360

1361+
/**
1362+
* @param {Expression} expression
1363+
* @param {Scope} scope
1364+
*/
1365+
export function is_constant(expression, scope) {
1366+
const evaluation = scope.evaluate(expression);
1367+
if (evaluation.is_known) {
1368+
return true;
1369+
}
1370+
let constant = true;
1371+
walk(/** @type {Node} */ (expression), null, {
1372+
Identifier(node, { path, stop }) {
1373+
if (is_reference(node, /** @type {Node} */ (path.at(-1)))) {
1374+
const binding = scope.get(node.name);
1375+
if (!binding || binding.reassigned) {
1376+
constant = false;
1377+
stop();
1378+
return;
1379+
}
1380+
}
1381+
},
1382+
ArrowFunctionExpression(_, { stop }) {
1383+
constant = false;
1384+
stop();
1385+
},
1386+
FunctionExpression(_, { stop }) {
1387+
constant = false;
1388+
stop();
1389+
},
1390+
ClassExpression(_, { stop }) {
1391+
constant = false;
1392+
stop();
1393+
},
1394+
MemberExpression(_, { stop }) {
1395+
constant = false;
1396+
stop();
1397+
},
1398+
CallExpression(node, { stop }) {
1399+
if (scope.evaluate(node).is_known) {
1400+
return;
1401+
}
1402+
constant = false;
1403+
stop();
1404+
},
1405+
UpdateExpression(_, { stop }) {
1406+
constant = false;
1407+
stop();
1408+
},
1409+
AssignmentExpression(_, { stop }) {
1410+
constant = false;
1411+
stop();
1412+
},
1413+
UnaryExpression(node, { next, stop }) {
1414+
if (node.operator === 'delete') {
1415+
constant = false;
1416+
stop();
1417+
return;
1418+
}
1419+
next();
1420+
}
1421+
});
1422+
return constant;
1423+
}
1424+
13611425
/**
13621426
* Returns the name of the rune if the given expression is a `CallExpression` using a rune.
13631427
* @param {Expression | Super} node

0 commit comments

Comments
 (0)