feat: I think non-destructured rest should work now?

pull/10320/head
S. Elliott Johnson 2 years ago
parent c1bb2397dd
commit 3a726a9c39

@ -2460,9 +2460,7 @@ export const template_visitors = {
node.context.elements.forEach((argument, i) => { node.context.elements.forEach((argument, i) => {
if (!argument) return; if (!argument) return;
// If the argument is itself an identifier (`foo`) or is a simple rest identifier (`...foo`) const arg_alias = `$$arg${i}`;
// we don't have to do anything fancy -- just push it onto the args array and make sure its
// binding expression is a call of itself.
/** @type {import('estree').Identifier | undefined} */ /** @type {import('estree').Identifier | undefined} */
let identifier; let identifier;
/** @type {import('estree').Identifier | import('estree').RestElement | string} */ /** @type {import('estree').Identifier | import('estree').RestElement | string} */
@ -2470,9 +2468,6 @@ export const template_visitors = {
if (argument.type === 'Identifier') { if (argument.type === 'Identifier') {
identifier = argument; identifier = argument;
arg = argument; arg = argument;
} else if (argument.type === 'RestElement' && argument.argument.type === 'Identifier') {
identifier = argument.argument;
arg = argument;
} else if (argument.type === 'RestElement') { } else if (argument.type === 'RestElement') {
arg = b.rest(b.id(`$$arg${i}`)); arg = b.rest(b.id(`$$arg${i}`));
} else { } else {
@ -2485,36 +2480,46 @@ export const template_visitors = {
context.state.scope.get(identifier.name) context.state.scope.get(identifier.name)
); );
binding.expression = b.call(identifier); binding.expression = b.call(identifier);
} else { return;
// If, on the other hand, it isn't an identifier, it's a destructuring expression, which could be }
// a rest destructure (eg. `...[foo, bar, { baz }, ...rest]`, which, absurdly, is all valid syntax).
// In this case, we need to follow the destructuring expression to figure out what variables are being extracted. if (argument.type === 'RestElement' && argument.argument.type === 'Identifier') {
const paths = extract_paths(argument.type === 'RestElement' ? argument.argument : argument); // this is a "simple" rest argument (not destructured), so we just need to thunkify it
const binding = /** @type {import('#compiler').Binding} */ (
for (const path of paths) { context.state.scope.get(argument.argument.name)
const name = /** @type {import('estree').Identifier} */ (path.node).name; );
const binding = /** @type {import('#compiler').Binding} */ ( binding.expression = b.call(argument.argument.name);
context.state.scope.get(name) // TODO: where does `context.visit` go here? does it matter? i don't understand what it's for :thinkies:
); declarations.push(b.let(argument.argument.name, b.thunk(b.id(`$$arg${i}`))));
declarations.push( return;
b.let( }
path.node,
b.thunk( // If, on the other hand, it's a destructuring expression, which could be
/** @type {import('estree').Expression} */ ( // a rest destructure (eg. `...[foo, bar, { baz }, ...rest]`, which, absurdly, is all valid syntax),
context.visit(path.expression?.(b.call(`$$arg${i}`))) // we need to follow the destructuring expression to figure out what variables are being extracted.
) const paths = extract_paths(argument.type === 'RestElement' ? argument.argument : argument);
for (const path of paths) {
const name = /** @type {import('estree').Identifier} */ (path.node).name;
const binding = /** @type {import('#compiler').Binding} */ (context.state.scope.get(name));
declarations.push(
b.let(
path.node,
b.thunk(
/** @type {import('estree').Expression} */ (
context.visit(path.expression?.(b.call(`$$arg${i}`)))
) )
) )
); )
);
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
if (context.state.options.dev) {
declarations.push(b.stmt(b.call(name)));
}
binding.expression = b.call(name); // we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
if (context.state.options.dev) {
declarations.push(b.stmt(b.call(name)));
} }
binding.expression = b.call(name);
} }
}); });

Loading…
Cancel
Save