Handle `return` showing up in closures

pull/3/head
Bradlee Speice 2018-11-17 10:32:58 -05:00
parent eef377708b
commit 3341faeb91
2 changed files with 28 additions and 2 deletions

View File

@ -120,17 +120,26 @@ fn protected_body(fn_body: Group) -> TokenTree {
/// to `return` with an exit guard.
fn escape_return(ts: TokenStream) -> TokenStream {
let mut protected: Vec<TokenTree> = Vec::new();
let mut in_closure: bool = false;
let mut tt_iter = ts.into_iter();
while let Some(tt) = tt_iter.next() {
let mut tokens = match tt {
TokenTree::Group(ref g) if g.delimiter() == Delimiter::Brace => {
TokenTree::Group(ref g) if g.delimiter() == Delimiter::Brace && !in_closure => {
vec![group!(Delimiter::Brace, escape_return(g.stream()))]
}
TokenTree::Ident(ref i) if i.to_string() == "return" => vec![
TokenTree::Ident(ref i) if i.to_string() == "return" && !in_closure => vec![
group!(Delimiter::Brace, release_guard("exit_protected")),
tt.clone(),
],
TokenTree::Punct(ref p) if p.as_char() == '|' => {
in_closure = true;
vec![tt.clone()]
}
TokenTree::Punct(ref p) if p.as_char() == ';' => {
in_closure = false;
vec![tt.clone()]
}
t => vec![t],
};

View File

@ -132,3 +132,20 @@ fn macro_branching_return() {
assert_eq!(7, branching_return(false, false, true));
assert_eq!(8, branching_return(false, false, false));
}
fn run_closure(x: impl Fn(bool, bool) -> bool) -> bool {
x(true, false)
}
#[allocate_panic]
fn example_closure() {
let c = run_closure(|a: bool, b| return a && b);
assert!(!c);
let x = || return true;
assert!(x());
}
#[test]
fn macro_closure() {
example_closure()
}