Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-trivial destructuring initializers are broken #8

Closed
simonbuchan opened this issue Jul 28, 2016 · 3 comments
Closed

Non-trivial destructuring initializers are broken #8

simonbuchan opened this issue Jul 28, 2016 · 3 comments

Comments

@simonbuchan
Copy link

simonbuchan commented Jul 28, 2016

fast-async badly transforms destructuring initializers using anything other than the trivial forms const [a, b, c] = ... or const { a, b, c } = ...; inside any async functions, even if the RHS is not an await expression.
Further, it fails to parse array rest (ES2015, so not #6), and fails while transforming array eliding.

// work
async function trivialArray() {
  const [a, b] = await Promise.resolve([1, 2]);
  console.log(a, b);
}
async function trivialObject() {
  const { a, b } = await Promise.resolve({ a: 1, b: 2 });
  console.log(a, b);
}

// fails in parse
//async function arraySpread() {
//  const [a, ...b, c] = await Promise.resolve([1, 2, 3, 4]);
//  console.log(a, b, c);
//}

// fails in transform
//async function arrayElide() {
//  const [,a,,b] = await Promise.resolve([1, 2, 3, 4]);
//  console.log(a, b);
//}

// generate bad code, only declaring `var a, b`
async function rename() {
  const { a, b: c } = await Promise.resolve({ a: 1, b: 2 });
  console.log(a, c);
}
async function key() {
  const { a, ['b']: c } = await Promise.resolve({ a: 1, b: 2 });
  console.log(a, c);
}
async function nestedArray() {
  const { a, b: [c, d] } = await Promise.resolve({ a: 1, b: [2, 3] });
  console.log(a, c, d);
}
async function nestedObject() {
  const { a, b: { c, d } } = await Promise.resolve({ a: 1, b: { c: 2, d: 3 } });
  console.log(a, c, d);
}
async function indirect() {
  const result = await Promise.resolve({ a: 1, b: 2 });
  const { a, b: c } = result;
  console.log(a, c);
}

Output is:

% babel --preset es2015 --plugins syntax-async-functions,fast-async async.js
Function.prototype.$asyncbind = <snip>

// work
function trivialArray() {
  return new Promise(function ($return, $error) {
    var a, b;
    return Promise.resolve([1, 2]).then(function ($await_1) {
      [a, b] = $await_1;

      console.log(a, b);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}
function trivialObject() {
  return new Promise(function ($return, $error) {
    var a, b;
    return Promise.resolve({ a: 1, b: 2 }).then(function ($await_2) {
      ({ a, b } = $await_2);

      console.log(a, b);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}

// fails in parse
//async function arraySpread() {
//  const [a, ...b, c] = await Promise.resolve([1, 2, 3, 4]);
//  console.log(a, b, c);
//}

// fails in transform
//async function arrayElide() {
//  const [,a,,b] = await Promise.resolve([1, 2, 3, 4]);
//  console.log(a, b);
//}

// generate bad code, only declaring `var a, b`
function rename() {
  return new Promise(function ($return, $error) {
    var a, b;
    return Promise.resolve({ a: 1, b: 2 }).then(function ($await_3) {
      ({ a, b: c } = $await_3);

      console.log(a, c);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}
function key() {
  return new Promise(function ($return, $error) {
    var a, undefined;
    return Promise.resolve({ a: 1, b: 2 }).then(function ($await_4) {
      ({ a, ['b']: c } = $await_4);

      console.log(a, c);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}
function nestedArray() {
  return new Promise(function ($return, $error) {
    var a, b;
    return Promise.resolve({ a: 1, b: [2, 3] }).then(function ($await_5) {
      ({ a, b: [c, d] } = $await_5);

      console.log(a, c, d);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}
function nestedObject() {
  return new Promise(function ($return, $error) {
    var a, b;
    return Promise.resolve({ a: 1, b: { c: 2, d: 3 } }).then(function ($await_6) {
      ({ a, b: { c, d } } = $await_6);

      console.log(a, c, d);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}
function indirect() {
  return new Promise(function ($return, $error) {
    var result, a, b;
    return Promise.resolve({ a: 1, b: 2 }).then(function ($await_7) {
      result = $await_7;
      ({ a, b: c } = result);

      console.log(a, c);
      return $return();
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}

Array rest gives error:

% babel --preset es2015 --plugins syntax-async-functions,fast-async async.js
SyntaxError: async.js: Unexpected token (10:16)
   8 | }
   9 | async function arraySpread() {
> 10 |   const [a, ...b, c] = await Promise.resolve([1, 2, 3, 4]);
     |                 ^
  11 |   console.log(a, b, c);
  12 | }
  13 | async function rename() {

Without fast-async:

% babel --preset es2015 --plugins syntax-async-functions array_rest.js
async function test() {
  const [a, ...b] = [1, 2, 3];
  console.log(a, b);
}

Array elide gives error:

% babel --preset es2015 --plugins syntax-async-functions,fast-async async.js
TypeError: async.js: Cannot read property 'type' of null
    at getDeclNames (/home/simon/code/xxx/node_modules/nodent/lib/arboriculture.js:2010:19)
    at /home/simon/code/xxx/node_modules/nodent/lib/arboriculture.js:2014:70
    at Array.reduce (native)
    at getDeclNames (/home/simon/code/xxx/node_modules/nodent/lib/arboriculture.js:2014:32)
    at /home/simon/code/xxx/node_modules/nodent/lib/arboriculture.js:2061:29
    at treeWalker (/home/simon/code/xxx/node_modules/nodent/lib/parser.js:156:5)
    at goDown (/home/simon/code/xxx/node_modules/nodent/lib/parser.js:122:9)
    at down (/home/simon/code/xxx/node_modules/nodent/lib/parser.js:146:25)
    at Object.base.Function (/home/simon/code/xxx/node_modules/acorn/dist/walk.js:269:4)
    at down (/home/simon/code/xxx/node_modules/nodent/lib/parser.js:133:60)
@simonbuchan simonbuchan changed the title Non-trivial object destructuring initializers in async functions Non-trivial destructuring initializers are broken Jul 28, 2016
@MatAtBread
Copy link
Owner

Wow. Thanks for finding these cases. I recently had a go at getting destructuring to work, but clearly missed quite a few cases. I'm away for 10 days, but will try and patch these up when I'm back

@MatAtBread
Copy link
Owner

@simonbuchan - I've fixed most of these issues, but const [a, ...b, c] = [1, 2, 3, 4] fails in acorn, and according to http://astexplorer.net, almost everything else (babylon, traceur, shift, esprima). Are you sure that is syntactically vaild (in particular the rest identifier should be the final declaration and cannot be followed by another identifier, as in const [a, ...b] = [1,2,3,4])?

@MatAtBread
Copy link
Owner

Fixed in fast-async@6.0.32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants