Store negative result from has_override to function resolution cache.

This commit is contained in:
Stephen Chung 2021-03-02 22:31:07 +08:00
parent 6fd2262ace
commit 5b1f80f5ce
2 changed files with 32 additions and 11 deletions

View File

@ -584,6 +584,7 @@ impl Engine {
pub(crate) fn has_override_by_name_and_arguments( pub(crate) fn has_override_by_name_and_arguments(
&self, &self,
mods: Option<&Imports>, mods: Option<&Imports>,
state: &mut State,
lib: &[&Module], lib: &[&Module],
fn_name: &str, fn_name: &str,
arg_types: &[TypeId], arg_types: &[TypeId],
@ -592,6 +593,7 @@ impl Engine {
self.has_override( self.has_override(
mods, mods,
state,
lib, lib,
calc_native_fn_hash(empty(), fn_name, arg_types.iter().cloned()), calc_native_fn_hash(empty(), fn_name, arg_types.iter().cloned()),
calc_script_fn_hash(empty(), fn_name, arg_types.len()), calc_script_fn_hash(empty(), fn_name, arg_types.len()),
@ -603,12 +605,21 @@ impl Engine {
pub(crate) fn has_override( pub(crate) fn has_override(
&self, &self,
mods: Option<&Imports>, mods: Option<&Imports>,
state: &mut State,
lib: &[&Module], lib: &[&Module],
hash_fn: Option<NonZeroU64>, hash_fn: Option<NonZeroU64>,
hash_script: Option<NonZeroU64>, hash_script: Option<NonZeroU64>,
) -> bool { ) -> bool {
let cache = state.fn_resolution_cache_mut();
if hash_script.map_or(false, |hash| cache.contains_key(&hash))
|| hash_fn.map_or(false, |hash| cache.contains_key(&hash))
{
return true;
}
// First check script-defined functions // First check script-defined functions
hash_script.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false))) if hash_script.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false)))
//|| hash_fn.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false))) //|| hash_fn.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false)))
// Then check registered functions // Then check registered functions
|| hash_script.map_or(false, |hash| self.global_namespace.contains_fn(hash, false)) || hash_script.map_or(false, |hash| self.global_namespace.contains_fn(hash, false))
@ -622,6 +633,17 @@ impl Engine {
// Then check sub-modules // Then check sub-modules
|| hash_script.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash))) || hash_script.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash)))
|| hash_fn.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash))) || hash_fn.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash)))
{
true
} else {
if let Some(hash_fn) = hash_fn {
cache.insert(hash_fn, None);
}
if let Some(hash_script) = hash_script {
cache.insert(hash_script, None);
}
false
}
} }
/// Perform an actual function call, native Rust or scripted, taking care of special functions. /// Perform an actual function call, native Rust or scripted, taking care of special functions.
@ -674,7 +696,8 @@ impl Engine {
} else { } else {
let hash_script = let hash_script =
calc_script_fn_hash(empty(), fn_name, num_params as usize); calc_script_fn_hash(empty(), fn_name, num_params as usize);
self.has_override(Some(mods), lib, None, hash_script).into() self.has_override(Some(mods), state, lib, None, hash_script)
.into()
}, },
false, false,
)); ));
@ -1127,12 +1150,13 @@ impl Engine {
self.make_type_mismatch_err::<INT>(err, args_expr[0].position()) self.make_type_mismatch_err::<INT>(err, args_expr[0].position())
})?; })?;
if num_params < 0 { return Ok(if num_params < 0 {
return Ok(Dynamic::FALSE); Dynamic::FALSE
} else { } else {
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize); let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
return Ok(self.has_override(Some(mods), lib, None, hash_script).into()); self.has_override(Some(mods), state, lib, None, hash_script)
} .into()
});
} }
// Handle is_def_var() // Handle is_def_var()

View File

@ -3,7 +3,7 @@
use crate::ast::{Expr, ScriptFnDef, Stmt}; use crate::ast::{Expr, ScriptFnDef, Stmt};
use crate::builtin::get_builtin_binary_op_fn; use crate::builtin::get_builtin_binary_op_fn;
use crate::dynamic::AccessMode; use crate::dynamic::AccessMode;
use crate::engine::{Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
use crate::parser::map_dynamic_to_expr; use crate::parser::map_dynamic_to_expr;
use crate::stdlib::{ use crate::stdlib::{
boxed::Box, boxed::Box,
@ -62,8 +62,6 @@ struct State<'a> {
propagate_constants: bool, propagate_constants: bool,
/// An [`Engine`] instance for eager function evaluation. /// An [`Engine`] instance for eager function evaluation.
engine: &'a Engine, engine: &'a Engine,
/// Collection of sub-modules.
mods: Imports,
/// [Module] containing script-defined functions. /// [Module] containing script-defined functions.
lib: &'a [&'a Module], lib: &'a [&'a Module],
/// Optimization level. /// Optimization level.
@ -79,7 +77,6 @@ impl<'a> State<'a> {
variables: vec![], variables: vec![],
propagate_constants: true, propagate_constants: true,
engine, engine,
mods: Default::default(),
lib, lib,
optimization_level: level, optimization_level: level,
} }
@ -673,7 +670,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
// Search for overloaded operators (can override built-in). // Search for overloaded operators (can override built-in).
if !state.engine.has_override_by_name_and_arguments(Some(&state.mods), state.lib, x.name.as_ref(), arg_types.as_ref()) { if !state.engine.has_override_by_name_and_arguments(Some(&Default::default()), &mut Default::default(), state.lib, x.name.as_ref(), arg_types.as_ref()) {
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
.and_then(|f| { .and_then(|f| {
let ctx = (state.engine, x.name.as_ref(), state.lib).into(); let ctx = (state.engine, x.name.as_ref(), state.lib).into();