regenerator: allow nested finally block (#601)

Previously, 

```js
function *foo() {
    try {
    } finally {
        try {
        } finally {
             throw new Error('foo');
        }
    }
}

```

make swc panic

Closes #600.
This commit is contained in:
kdy1 2020-01-23 01:04:08 +00:00
parent ec98516b0e
commit 20e37eae5d
9 changed files with 125 additions and 16 deletions

View File

@ -1,6 +1,6 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Use this when swc breaks something
title: '' title: ''
labels: C-bug labels: C-bug
assignees: '' assignees: ''

View File

@ -1,6 +1,6 @@
--- ---
name: Crash report name: Crash report
about: Create a report to help us improve about: Use this when swc panics
title: 'panic: ' title: 'panic: '
labels: C-bug labels: C-bug
assignees: '' assignees: ''

View File

@ -0,0 +1,15 @@
---
name: Feature request
about: Use this when you want a new feature
title: ''
labels: ''
assignees: ''
---
**Describe the feature**
**Babel plugin or link to the feature description**
**Additional context**
Add any other context about the problem here.

10
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
name: Question
about: Use this when you have a question
title: ''
labels: ''
assignees: ''
---
**Question**

View File

@ -74,9 +74,9 @@ impl<'a> CaseHandler<'a> {
} }
impl CaseHandler<'_> { impl CaseHandler<'_> {
fn with_entry<F, Ret>(&mut self, entry: Entry, op: F) -> Ret fn with_entry<F>(&mut self, entry: Entry, op: F)
where where
F: FnOnce(&mut Self) -> Ret, F: FnOnce(&mut Self),
{ {
self.leaps.push(entry); self.leaps.push(entry);
let ret = op(self); let ret = op(self);
@ -92,15 +92,20 @@ impl CaseHandler<'_> {
return None; return None;
} }
let mut last_loc_value = 0; // let mut last_loc_value = 0;
Some(ArrayLit { Some(ArrayLit {
span: DUMMY_SP, span: DUMMY_SP,
elems: replace(&mut self.try_entries, Default::default()) elems: replace(&mut self.try_entries, Default::default())
.into_iter() .into_iter()
.map(|entry: TryEntry| { .map(|entry: TryEntry| {
let this_loc_value = entry.first_loc; // let this_loc_value = entry.first_loc;
assert!(this_loc_value.stmt_index >= last_loc_value); // assert!(
last_loc_value = this_loc_value.stmt_index; // this_loc_value.stmt_index >= last_loc_value,
// "this_loc_value = {:?}; last_loc_value = {};",
// this_loc_value,
// last_loc_value
// );
// last_loc_value = this_loc_value.stmt_index;
let ce = entry.catch_entry; let ce = entry.catch_entry;
let fe = entry.finally_entry; let fe = entry.finally_entry;
@ -1091,7 +1096,7 @@ impl CaseHandler<'_> {
}; };
self.update_ctx_prev_loc(Some(&mut try_entry.first_loc)); self.update_ctx_prev_loc(Some(&mut try_entry.first_loc));
// TODO: Track unmarked entries in a separate field,
self.with_entry(Entry::TryEntry(try_entry.clone()), |folder| { self.with_entry(Entry::TryEntry(try_entry.clone()), |folder| {
// //
folder.explode_stmts(block.stmts); folder.explode_stmts(block.stmts);
@ -1343,7 +1348,12 @@ impl CaseHandler<'_> {
self.mark(after); self.mark(after);
} }
Stmt::Decl(_) | Stmt::ForOf(_) => self.emit(s), Stmt::ForOf(s) => unreachable!(
"for-of statement should be removed by es2015::for_of pass\n{:?}",
s
),
Stmt::Decl(_) => self.emit(s),
} }
} }
} }

View File

@ -79,11 +79,9 @@ impl Fold<VarDecl> for Hoister {
impl Fold<VarDeclOrExpr> for Hoister { impl Fold<VarDeclOrExpr> for Hoister {
fn fold(&mut self, var: VarDeclOrExpr) -> VarDeclOrExpr { fn fold(&mut self, var: VarDeclOrExpr) -> VarDeclOrExpr {
let var = var.fold_children(self);
match var { match var {
VarDeclOrExpr::VarDecl(var) => VarDeclOrExpr::Expr(box self.var_decl_to_expr(var)), VarDeclOrExpr::VarDecl(var) => VarDeclOrExpr::Expr(box self.var_decl_to_expr(var)),
_ => var, _ => var.fold_children(self),
} }
} }
} }

View File

@ -13,8 +13,8 @@ impl LeapManager {
pub fn push(&mut self, entry: Entry) { pub fn push(&mut self, entry: Entry) {
self.stack.push(entry); self.stack.push(entry);
} }
pub fn pop(&mut self) { pub fn pop(&mut self) -> Option<Entry> {
self.stack.pop(); self.stack.pop()
} }
pub fn find_leap_loc<F>(&self, mut pred: F, label: Option<&JsWord>) -> Option<Loc> pub fn find_leap_loc<F>(&self, mut pred: F, label: Option<&JsWord>) -> Option<Loc>

View File

@ -6,7 +6,10 @@
use swc_common::chain; use swc_common::chain;
use swc_ecma_parser::Syntax; use swc_ecma_parser::Syntax;
use swc_ecma_transforms::{ use swc_ecma_transforms::{
compat::es2015::regenerator, modules::common_js::common_js, pass::Pass, resolver, compat::{es2015, es2015::regenerator, es2016, es2017, es2017::async_to_generator},
modules::common_js::common_js,
pass::Pass,
resolver,
}; };
#[macro_use] #[macro_use]
@ -965,3 +968,53 @@ expect(v.next()).toEqual({ value: 4, done: false });
expect(v.next()).toEqual({ done: true }); expect(v.next()).toEqual({ done: true });
" "
); );
test_exec!(
syntax(),
|_| chain!(es2017(), es2016(), es2015(Default::default()),),
issue_600_full,
"async function foo(b) {
for (let a of b) {
await a
}
}"
);
test_exec!(
syntax(),
|_| chain!(
async_to_generator(),
es2015::for_of(Default::default()),
es2015::regenerator(),
),
issue_600_exact_passes,
"async function foo(b) {
for (let a of b) {
await a
}
}"
);
test_exec!(
syntax(),
|_| es2015::regenerator(),
issue_600_min,
"function* foo() {
try {
yield 1;
throw new Error('1')
} finally{
try {
yield 2;
} finally{
throw new Error('2');
}
}
}
var v = foo();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(() => v.next()).toThrow('2')
"
);

View File

@ -2105,3 +2105,26 @@ async function foo() {}
"# "#
); );
// async_to_generator_parameters
test!(
syntax(),
|_| async_to_generator(),
issue_600,
r#"
async function foo() {
for (let a of b) {
}
}
"#,
"function _foo() {
_foo = _asyncToGenerator(function*() {
for (let a of b){
}
});
return _foo.apply(this, arguments);
}
function foo() {
return _foo.apply(this, arguments);
}"
);