From 1798d4d6a0bab3deb938312b191cccd901c356a2 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 24 May 2020 11:57:46 +0800 Subject: [PATCH] Fix function call optimizations. --- src/engine.rs | 10 +++++----- src/optimize.rs | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 0e9b41f7..b708ecf5 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -698,7 +698,7 @@ impl Engine { } // If it is a 2-operand operator, see if it is built in - if native_only && args.len() == 2 && args[0].type_id() == args[1].type_id() { + if !is_ref && native_only && args.len() == 2 && args[0].type_id() == args[1].type_id() { match run_builtin_binary_op(fn_name, args[0], args[1])? { Some(v) => return Ok((v, false)), None => (), @@ -1327,7 +1327,7 @@ impl Engine { ) -> Result> { self.inc_operations(state, rhs.position())?; - let mut lhs_value = self.eval_expr(scope, state, lhs, level)?; + let lhs_value = self.eval_expr(scope, state, lhs, level)?; let rhs_value = self.eval_expr(scope, state, rhs, level)?; match rhs_value { @@ -1338,17 +1338,17 @@ impl Engine { // Call the `==` operator to compare each value for value in rhs_value.iter_mut() { - let args = &mut [&mut lhs_value, value]; + let args = &mut [&mut lhs_value.clone(), value]; let def_value = Some(&def_value); let pos = rhs.position(); - // Qualifiers (none) + function name + argument `TypeId`'s. + // Qualifiers (none) + function name + number of arguments + argument `TypeId`'s. let hash_fn = calc_fn_hash(empty(), op, args.len(), args.iter().map(|a| a.type_id())); let hashes = (hash_fn, 0); let (r, _) = self - .call_fn_raw(None, state, op, hashes, args, true, def_value, pos, level)?; + .call_fn_raw(None, state, op, hashes, args, false, def_value, pos, level)?; if r.as_bool().unwrap_or(false) { return Ok(true.into()); } diff --git a/src/optimize.rs b/src/optimize.rs index 5e9aa911..e2acc6d0 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -110,18 +110,18 @@ impl<'a> State<'a> { } /// Call a registered function -fn call_fn( +fn call_fn_with_constant_arguments( state: &State, fn_name: &str, - args: &mut FnCallArgs, + arg_values: &mut [Dynamic], pos: Position, ) -> Result, Box> { // Search built-in's and external functions let hash_fn = calc_fn_hash( empty(), fn_name, - args.len(), - args.iter().map(|a| a.type_id()), + arg_values.len(), + arg_values.iter().map(|a| a.type_id()), ); state @@ -131,8 +131,8 @@ fn call_fn( &mut EngineState::new(&Default::default()), fn_name, (hash_fn, 0), - args, - true, + arg_values.iter_mut().collect::>().as_mut(), + false, None, pos, 0, @@ -556,24 +556,24 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr { let ((name, native_only, pos), _, _, args, def_value) = x.as_mut(); // First search in script-defined functions (can override built-in) - if !*native_only && state.fn_lib.iter().find(|(id, len)| *id == name && *len == args.len()).is_some() { + // Cater for both normal function call style and method call style (one additional arguments) + if !*native_only && state.fn_lib.iter().find(|(id, len)| *id == name && (*len == args.len() || *len == args.len() + 1)).is_some() { // A script-defined function overrides the built-in function - do not make the call x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect(); return Expr::FnCall(x); } let mut arg_values: StaticVec<_> = args.iter().map(Expr::get_constant_value).collect(); - let mut call_args: StaticVec<_> = arg_values.iter_mut().collect(); // Save the typename of the first argument if it is `type_of()` // This is to avoid `call_args` being passed into the closure - let arg_for_type_of = if name == KEYWORD_TYPE_OF && call_args.len() == 1 { - state.engine.map_type_name(call_args[0].type_name()) + let arg_for_type_of = if name == KEYWORD_TYPE_OF && arg_values.len() == 1 { + state.engine.map_type_name(arg_values[0].type_name()) } else { "" }; - call_fn(&state, name, call_args.as_mut(), *pos).ok() + call_fn_with_constant_arguments(&state, name, arg_values.as_mut(), *pos).ok() .and_then(|result| result.or_else(|| { if !arg_for_type_of.is_empty() {