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

rest parameters don't work in async arrow functions unless args array is accessed without spreading (T7260) #4219

Closed
babel-bot opened this issue Apr 4, 2016 · 9 comments
Labels
help wanted i: bug outdated A closed issue/PR that is archived due to age. Recommended to make a new issue Priority: High

Comments

@babel-bot
Copy link
Collaborator

Issue originally made by @spudly

Options

preset-es2015, preset-stage-3

Input code

const callTest = async (...args) => {
    await test(...args);
  };

  const test = (arg) => console.log(arg);

  callTest('yo');

Description

This is similar to: T2776: Generators and async functions with default args place _this and _arguments incorrectly.

When you use an async arrow function that uses a rest arg and then spread the resulting array into another function call without first accessing the variable, the _arguments variable is placed outside of the function, causing it to send the wrong arguments.

Simply accessing the variable fixes this issue. All I have to do is add "args;" as the first line in the callTest() function and it starts working.

Tested with the REPL at babeljs.io, version 6.7.4.

@babel-bot
Copy link
Collaborator Author

Comment originally made by @loganfsmyth

Yup, looks like this is https://phabricator.babeljs.io/T1882 re-introduced in 6.7.0 from my changes to shadow processing. I'll need to dig in a bit to figure out a good solution.

@babel-bot
Copy link
Collaborator Author

Comment originally made by @loganfsmyth

Reintroduced by 42d3844

@olalonde
Copy link

Is this still an issue? Wasn't able to reproduce.

@danharper
Copy link
Member

Seems to still be an issue.

e.g. When using preset-latest, args references arguments from outside the function:

const callTest = async (...args) => {
  await test(...args);
};
"use strict";

var _arguments = arguments; // <-------

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

var callTest = function () {
    var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
        var _args = _arguments; // <-------
        return regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        _context.next = 2;
                        return test.apply(undefined, _args); // <-------

                    case 2:
                    case "end":
                        return _context.stop();
                }
            }
        }, _callee, undefined);
    }));

    return function callTest(_x) {
        return _ref.apply(this, arguments);
    };
}();

@olalonde
Copy link

olalonde commented Oct 28, 2016

I'm not sure if it's the presets I'm using but:

$ cat test-async.js
const callTest = async (...args) => {
  await test(...args);
};

const test = (arg) => console.log(arg);

callTest('hello')

$ babel-node test-async.js
hello

Compiled code:

'use strict';

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

const callTest = (() => {
  var _ref = _asyncToGenerator(function* () {
    yield test(...arguments);
  });

  return function callTest() {
    return _ref.apply(this, arguments);
  };
})();

const test = arg => console.log(arg);

callTest('hello');

Ah, I think I'm not actually compiling array rest/spread because it's supported by Node v6.

@spudly
Copy link

spudly commented Oct 31, 2016

Definitely still an issue, at least with the version in use on the website.

Try it out

Notice that when you comment out line 2 in the original code, the compiled code starts to fail because it now uses a new _arguments variable which is defined outside of the function (line 3).

@gpittarelli
Copy link

I've reproduced this using presets stage-0 and es2015 on current master, and noticed that it doesn't occur if you do one run with only stage-0 and then another run with es2015.

I further dug into the individual plugins, and while I'm still digging, I believe it only happens when transform-async-to-generator and transform-es2015-parameters are in the same pass.

@danez
Copy link
Member

danez commented Mar 31, 2017

This has been fixed in the 7.0 branch and will be backported to 6.0 with #5567.

@existentialism
Copy link
Member

Release in v6.24.1!

@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label May 4, 2018
@lock lock bot locked as resolved and limited conversation to collaborators May 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted i: bug outdated A closed issue/PR that is archived due to age. Recommended to make a new issue Priority: High
Projects
None yet
Development

No branches or pull requests

8 participants