Skip to content

Commit

Permalink
fix(es/transforms): Fix bugs (swc-project#1795)
Browse files Browse the repository at this point in the history
swc_ecma_transforms_compat:
 - `async_to_generator`: Handle await in async generators correctly. (swc-project#1752)

swc_ecma_transforms_module:
 - Don't panic on double import from one module. (swc-project#1757)
  • Loading branch information
kdy1 authored Jun 6, 2021
1 parent 03db7ad commit 7730a6e
Show file tree
Hide file tree
Showing 14 changed files with 324 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class x87 { constructor(parm: () => Base[] = function named() { return [d1, d2] }) { } }

class x90 { constructor(parm: { (): Base[]; } = function named() { return [d1, d2] }) { } }
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class x87 {
constructor(parm__2: () => Base[] = function named__3() {
return [d1, d2];
}){
}
}
class x90 {
constructor(parm__4: {
() : Base[];
} = function named__5() {
return [d1, d2];
}){
}
}
2 changes: 1 addition & 1 deletion ecmascript/transforms/compat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_compat"
repository = "https://github.com/swc-project/swc.git"
version = "0.17.9"
version = "0.17.10"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down
35 changes: 28 additions & 7 deletions ecmascript/transforms/compat/src/es2017/async_to_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,9 @@ impl Actual {
///
/// `_asyncToGenerator(function*() {})` from `async function() {}`;
fn make_fn_ref(mut expr: FnExpr, should_not_bind_this: bool) -> Expr {
expr.function.body = expr.function.body.fold_with(&mut AsyncFnBodyHandler);
expr.function.body = expr.function.body.fold_with(&mut AsyncFnBodyHandler {
is_async_generator: expr.function.is_generator,
});

assert!(expr.function.is_async);
expr.function.is_async = false;
Expand Down Expand Up @@ -901,7 +903,9 @@ fn make_fn_ref(mut expr: FnExpr, should_not_bind_this: bool) -> Expr {
})
}

struct AsyncFnBodyHandler;
struct AsyncFnBodyHandler {
is_async_generator: bool,
}

macro_rules! noop {
($name:ident, $T:path) => {
Expand All @@ -924,11 +928,28 @@ impl Fold for AsyncFnBodyHandler {
let expr = expr.fold_children_with(self);

match expr {
Expr::Await(AwaitExpr { span, arg }) => Expr::Yield(YieldExpr {
span,
delegate: false,
arg: Some(arg),
}),
Expr::Await(AwaitExpr { span, arg }) => {
if self.is_async_generator {
let callee = helper!(await_async_generator, "awaitAsyncGenerator");
let arg = Box::new(Expr::Call(CallExpr {
span,
callee,
args: vec![arg.as_arg()],
type_args: Default::default(),
}));
Expr::Yield(YieldExpr {
span,
delegate: false,
arg: Some(arg),
})
} else {
Expr::Yield(YieldExpr {
span,
delegate: false,
arg: Some(arg),
})
}
}
_ => expr,
}
}
Expand Down
28 changes: 28 additions & 0 deletions ecmascript/transforms/compat/tests/es2017_async_to_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2612,3 +2612,31 @@ test!(
}
"
);

test_exec!(
syntax(),
|_| async_to_generator(),
issue_1752_1,
"
async function* generate() {
const results = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
])
for (const result of results) {
console.log(`yield ${result}`)
yield result
}
}
async function printValues() {
const iterator = generate()
for await (const value of iterator) {
console.log(`iterator value: ${value}`)
}
}
printValues()
"
);
2 changes: 1 addition & 1 deletion ecmascript/transforms/module/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_module"
repository = "https://github.com/swc-project/swc.git"
version = "0.17.1"
version = "0.17.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down
8 changes: 8 additions & 0 deletions ecmascript/transforms/module/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ impl Scope {
} else {
self.imports
.entry(import.src.value.clone())
.and_modify(|opt| {
if opt.is_none() {
*opt = Some((
local_name_for_src(&import.src.value),
import.src.span.apply_mark(Mark::fresh(Mark::root())),
));
}
})
.or_insert_with(|| {
Some((
local_name_for_src(&import.src.value),
Expand Down
17 changes: 17 additions & 0 deletions ecmascript/transforms/module/tests/common_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4765,3 +4765,20 @@ test!(
});
"
);

test!(
syntax(),
|_| tr(Default::default()),
issue_1757_1,
"
import 'testlibrary';
import { aFunc } from 'testlibrary';
console.log('aFunc: ', aFunc(1,2));
",
"
'use strict';
var _testlibrary = require('testlibrary');
console.log('aFunc: ', (0, _testlibrary).aFunc(1, 2));
"
);
8 changes: 8 additions & 0 deletions tests/fixture/issue-1752/case1/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2017"
}
}
20 changes: 20 additions & 0 deletions tests/fixture/issue-1752/case1/input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
async function* generate() {
const results = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
])
for (const result of results) {
console.log(`yield ${result}`)
yield result
}
}

async function printValues() {
const iterator = generate()
for await (const value of iterator) {
console.log(`iterator value: ${value}`)
}
}

printValues()
184 changes: 184 additions & 0 deletions tests/fixture/issue-1752/case1/output/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
function AsyncGenerator(gen) {
var front, back;
function send(key, arg) {
return new Promise(function(resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null
};
if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}
function resume(key, arg) {
try {
var result = gen[key](arg);
var value = result.value;
var wrappedAwait = value instanceof _AwaitValue;
Promise.resolve(wrappedAwait ? value.wrapped : value).then(function(arg) {
if (wrappedAwait) {
resume("next", arg);
return;
}
settle(result.done ? "return" : "normal", arg);
}, function(err) {
resume("throw", err);
});
} catch (err) {
settle("throw", err);
}
}
function settle(type, value) {
switch(type){
case "return":
front.resolve({
value: value,
done: true
});
break;
case "throw":
front.reject(value);
break;
default:
front.resolve({
value: value,
done: false
});
break;
}
front = front.next;
if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}
this._invoke = send;
if (typeof gen.return !== "function") {
this.return = undefined;
}
}
if (typeof Symbol === "function" && Symbol.asyncIterator) {
AsyncGenerator.prototype[Symbol.asyncIterator] = function() {
return this;
};
}
AsyncGenerator.prototype.next = function(arg) {
return this._invoke("next", arg);
};
AsyncGenerator.prototype.throw = function(arg) {
return this._invoke("throw", arg);
};
AsyncGenerator.prototype.return = function(arg) {
return this._invoke("return", arg);
};
function _asyncIterator(iterable) {
var method;
if (typeof Symbol === "function") {
if (Symbol.asyncIterator) {
method = iterable[Symbol.asyncIterator];
if (method != null) return method.call(iterable);
}
if (Symbol.iterator) {
method = iterable[Symbol.iterator];
if (method != null) return method.call(iterable);
}
}
throw new TypeError("Object is not async iterable");
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _awaitAsyncGenerator(value) {
return new _AwaitValue(value);
}
function _AwaitValue(value) {
this.wrapped = value;
}
function _wrapAsyncGenerator(fn) {
return function() {
return new AsyncGenerator(fn.apply(this, arguments));
};
}
function _generate() {
_generate = _wrapAsyncGenerator(function*() {
const results = yield _awaitAsyncGenerator(Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
]));
for (const result of results){
console.log(`yield ${result}`);
yield result;
}
});
return _generate.apply(this, arguments);
}
function generate() {
return _generate.apply(this, arguments);
}
function _printValues() {
_printValues = _asyncToGenerator(function*() {
const iterator = generate();
{
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError;
try {
for(var _iterator = _asyncIterator(iterator), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true){
const value = _value;
console.log(`iterator value: ${value}`);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally{
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
yield _iteratorError.return();
}
} finally{
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
});
return _printValues.apply(this, arguments);
}
function printValues() {
return _printValues.apply(this, arguments);
}
printValues();
5 changes: 5 additions & 0 deletions tests/fixture/issue-1757/case1/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"module": {
"type": "commonjs"
}
}
4 changes: 4 additions & 0 deletions tests/fixture/issue-1757/case1/input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import "testlibrary";
import { aFunc } from "testlibrary";

console.log("aFunc: ", aFunc(1, 2));
3 changes: 3 additions & 0 deletions tests/fixture/issue-1757/case1/output/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";
var _testlibrary = require("testlibrary");
console.log("aFunc: ", (0, _testlibrary).aFunc(1, 2));

0 comments on commit 7730a6e

Please sign in to comment.