diff --git a/CHANGELOG.md b/CHANGELOG.md index 3063db23..10d05cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Bug fixes * `switch` cases with conditions that evaluate to constant `()` no longer optimize to `false` (should raise a type error during runtime). * Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings. +* Capturing an unknown variable in a closure no longer panics. New features ------------ diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 9154a92e..bb7ac905 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -1016,7 +1016,7 @@ impl Engine { // Share statement #[cfg(not(feature = "no_closure"))] - Stmt::Share(name, ..) => { + Stmt::Share(name, pos) => { if let Some((index, ..)) = scope.get_index(name) { let val = scope.get_mut_by_index(index); @@ -1024,10 +1024,10 @@ impl Engine { // Replace the variable with a shared value. *val = std::mem::take(val).into_shared(); } + Ok(Dynamic::UNIT) } else { - unreachable!("variable {} not found for sharing", name); + Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into()) } - Ok(Dynamic::UNIT) } _ => unreachable!("statement cannot be evaluated: {:?}", stmt), diff --git a/tests/closures.rs b/tests/closures.rs index f7c1b291..392e8e94 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -42,21 +42,35 @@ fn test_fn_ptr_curry_call() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] fn test_closures() -> Result<(), Box> { let mut engine = Engine::new(); + let mut scope = Scope::new(); + + scope.push("x", 42 as INT); assert!(matches!( - *engine - .compile_expression("let f = |x| {};") + engine + .compile_expression("|x| {}") .expect_err("should error") - .0, + .err_type(), ParseErrorType::BadInput(..) )); + assert_eq!( + engine.eval_with_scope::( + &mut scope, + " + let f = || { x }; + f.call() + ", + )?, + 42 + ); + assert_eq!( engine.eval::( " let foo = #{ x: 42 }; let f = || { this.x }; - foo.call(f) + foo.call(f) ", )?, 42