Fix panic of continue/break/return in try-catch block.

This commit is contained in:
Stephen Chung 2021-02-09 14:22:21 +08:00
parent e88e65f36e
commit 2dd5aceb1d
2 changed files with 21 additions and 5 deletions

View File

@ -569,6 +569,14 @@ impl State {
pub fn pop_fn_resolution_cache(&mut self) { pub fn pop_fn_resolution_cache(&mut self) {
self.fn_resolution_caches.pop(); self.fn_resolution_caches.pop();
} }
/// Clear the current functions resolution cache.
///
/// # Panics
///
/// Panics if there is no current functions resolution cache.
pub fn clear_fn_resolution_cache(&mut self) {
self.fn_resolution_caches.last_mut().unwrap().clear();
}
} }
/// _(INTERNALS)_ A type containing all the limits imposed by the [`Engine`]. /// _(INTERNALS)_ A type containing all the limits imposed by the [`Engine`].
@ -1908,11 +1916,9 @@ impl Engine {
Stmt::Import(_, _, _) => { Stmt::Import(_, _, _) => {
// When imports list is modified, clear the functions lookup cache // When imports list is modified, clear the functions lookup cache
if _has_imports { if _has_imports {
state.fn_resolution_caches.last_mut().map(|c| c.clear()); state.clear_fn_resolution_cache();
} else if restore { } else if restore {
state state.push_fn_resolution_cache();
.fn_resolution_caches
.push(HashMap::with_capacity_and_hasher(16, StraightHasherBuilder));
_has_imports = true; _has_imports = true;
} }
} }
@ -1926,7 +1932,7 @@ impl Engine {
scope.rewind(prev_scope_len); scope.rewind(prev_scope_len);
if _has_imports { if _has_imports {
// If imports list is modified, pop the functions lookup cache // If imports list is modified, pop the functions lookup cache
state.fn_resolution_caches.pop(); state.pop_fn_resolution_cache();
} }
mods.truncate(prev_mods_len); mods.truncate(prev_mods_len);
state.scope_level -= 1; state.scope_level -= 1;
@ -2286,6 +2292,7 @@ impl Engine {
match result { match result {
Ok(_) => result, Ok(_) => result,
Err(err) if err.is_pseudo_error() => Err(err),
Err(err) if !err.is_catchable() => Err(err), Err(err) if !err.is_catchable() => Err(err),
Err(mut err) => { Err(mut err) => {
let value = match *err { let value = match *err {

View File

@ -272,6 +272,15 @@ impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
} }
impl EvalAltResult { impl EvalAltResult {
/// Is this a pseudo error? A pseudo error is one that does not occur naturally.
///
/// [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return] are pseudo errors.
pub fn is_pseudo_error(&self) -> bool {
match self {
Self::LoopBreak(_, _) | Self::Return(_, _) => true,
_ => false,
}
}
/// Can this error be caught? /// Can this error be caught?
/// ///
/// # Panics /// # Panics