diff --git a/src/func/call.rs b/src/func/call.rs index de8198dc..1d770324 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -834,13 +834,13 @@ impl Engine { let fn_ptr = mem::take(&mut call_args[0]).cast::(); #[cfg(not(feature = "no_function"))] - let (fn_name, is_anon, fn_curry, environ, fn_def) = { + let (fn_name, is_anon, fn_curry, _environ, fn_def) = { let is_anon = fn_ptr.is_anonymous(); let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data(); (fn_name, is_anon, fn_curry, environ, fn_def) }; #[cfg(feature = "no_function")] - let (fn_name, is_anon, environ, fn_curry) = { + let (fn_name, is_anon, fn_curry, _environ) = { let (fn_name, fn_curry, environ) = fn_ptr.take_data(); (fn_name, false, fn_curry, environ) }; @@ -868,7 +868,7 @@ impl Engine { caches, &mut Scope::new(), target, - environ.as_deref(), + _environ.as_deref(), &fn_def, args, true, @@ -1043,13 +1043,13 @@ impl Engine { let fn_ptr = arg_value.cast::(); #[cfg(not(feature = "no_function"))] - let (fn_name, is_anon, fn_curry, environ, fn_def) = { + let (fn_name, is_anon, fn_curry, _environ, fn_def) = { let is_anon = fn_ptr.is_anonymous(); let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data(); (fn_name, is_anon, fn_curry, environ, fn_def) }; #[cfg(feature = "no_function")] - let (fn_name, is_anon, fn_curry, environ) = { + let (fn_name, is_anon, fn_curry, _environ) = { let (fn_name, fn_curry, environ) = fn_ptr.take_data(); (fn_name, false, fn_curry, environ) }; @@ -1077,7 +1077,7 @@ impl Engine { caches, &mut Scope::new(), &mut this_ptr, - environ.as_deref(), + _environ.as_deref(), &fn_def, args, true, diff --git a/src/module/mod.rs b/src/module/mod.rs index 534f0ff4..241ded4f 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -2139,19 +2139,37 @@ impl Module { let _ = result?; // Encapsulated environment - #[cfg(not(feature = "no_function"))] let environ = Shared::new(crate::func::EncapsulatedEnviron { + #[cfg(not(feature = "no_function"))] lib: ast.shared_lib().clone(), imports: imports.into_boxed_slice(), + #[cfg(not(feature = "no_function"))] constants, }); + fn update_encapsulated_environ( + value: &mut Dynamic, + environ: &Shared, + ) { + match value.0 { + #[cfg(not(feature = "no_index"))] + crate::types::dynamic::Union::Array(ref mut a, _, _) => a + .iter_mut() + .for_each(|v| update_encapsulated_environ(v, environ)), + #[cfg(not(feature = "no_object"))] + crate::types::dynamic::Union::Map(ref mut map, _, _) => map + .values_mut() + .for_each(|v| update_encapsulated_environ(v, environ)), + crate::types::dynamic::Union::FnPtr(ref mut fn_ptr, _, _) => { + fn_ptr.set_encapsulated_environ(Some(environ.clone())) + } + _ => (), + } + } + // Variables with an alias left in the scope become module variables for (_name, mut value, mut aliases) in scope { - #[cfg(not(feature = "no_function"))] - if let Some(mut fn_ptr) = value.write_lock::() { - fn_ptr.set_encapsulated_environ(Some(environ.clone())); - } + update_encapsulated_environ(&mut value, &environ); match aliases.len() { 0 => (), diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 7be7fcee..61837d09 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -1,11 +1,12 @@ //! The `FnPtr` type. use crate::eval::GlobalRuntimeState; +use crate::func::EncapsulatedEnviron; use crate::tokenizer::is_valid_function_name; use crate::types::dynamic::Variant; use crate::{ Dynamic, Engine, FnArgsVec, FuncArgs, ImmutableString, NativeCallContext, Position, RhaiError, - RhaiResult, RhaiResultOf, StaticVec, AST, ERR, + RhaiResult, RhaiResultOf, Shared, StaticVec, AST, ERR, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -13,7 +14,7 @@ use std::{ any::{type_name, TypeId}, convert::{TryFrom, TryInto}, fmt, - hash::Hash, + hash::{Hash, Hasher}, mem, }; @@ -23,23 +24,23 @@ use std::{ pub struct FnPtr { name: ImmutableString, curry: StaticVec, - environ: Option>, + environ: Option>, #[cfg(not(feature = "no_function"))] - fn_def: Option>, + fn_def: Option>, } impl Hash for FnPtr { #[inline(always)] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { self.name.hash(state); self.curry.hash(state); + // Hash the shared [`EncapsulatedEnviron`] by hashing its shared pointer. + self.environ.as_ref().map(|e| Shared::as_ptr(e)).hash(state); + // Hash the linked [`ScriptFnDef`][crate::ast::ScriptFnDef] by hashing its shared pointer. #[cfg(not(feature = "no_function"))] - self.fn_def - .as_ref() - .map(|f| crate::Shared::as_ptr(f)) - .hash(state); + self.fn_def.as_ref().map(|f| Shared::as_ptr(f)).hash(state); } } @@ -102,8 +103,8 @@ impl FnPtr { ) -> ( ImmutableString, StaticVec, - Option>, - Option>, + Option>, + Option>, ) { (self.name, self.curry, self.environ, self.fn_def) } @@ -116,7 +117,7 @@ impl FnPtr { ) -> ( ImmutableString, StaticVec, - Option>, + Option>, ) { (self.name, self.curry, self.environ) } @@ -192,7 +193,7 @@ impl FnPtr { args: impl FuncArgs, ) -> RhaiResultOf { let _ast = ast; - let mut arg_values = crate::StaticVec::new_const(); + let mut arg_values = StaticVec::new_const(); args.parse(&mut arg_values); let global = &mut GlobalRuntimeState::new(engine); @@ -228,7 +229,7 @@ impl FnPtr { context: &NativeCallContext, args: impl FuncArgs, ) -> RhaiResultOf { - let mut arg_values = crate::StaticVec::new_const(); + let mut arg_values = StaticVec::new_const(); args.parse(&mut arg_values); self.call_raw(context, None, arg_values).and_then(|result| { @@ -316,17 +317,19 @@ impl FnPtr { context.call_fn_raw(self.fn_name(), is_method, is_method, args) } - /// Get a reference to the [encapsulated environment][crate::func::EncapsulatedEnviron]. + /// Get a reference to the [encapsulated environment][EncapsulatedEnviron]. #[inline(always)] #[must_use] - pub(crate) fn encapsulated_environ(&self) -> Option<&crate::func::EncapsulatedEnviron> { + #[allow(dead_code)] + pub(crate) fn encapsulated_environ(&self) -> Option<&EncapsulatedEnviron> { self.environ.as_deref() } - /// Set a reference to the [encapsulated environment][crate::func::EncapsulatedEnviron]. + /// Set a reference to the [encapsulated environment][EncapsulatedEnviron]. #[inline(always)] + #[allow(dead_code)] pub(crate) fn set_encapsulated_environ( &mut self, - value: Option>>, + value: Option>>, ) { self.environ = value.map(Into::into); } @@ -334,16 +337,13 @@ impl FnPtr { #[cfg(not(feature = "no_function"))] #[inline(always)] #[must_use] - pub(crate) fn fn_def(&self) -> Option<&crate::Shared> { + pub(crate) fn fn_def(&self) -> Option<&Shared> { self.fn_def.as_ref() } /// Set a reference to the linked [`ScriptFnDef`][crate::ast::ScriptFnDef]. #[cfg(not(feature = "no_function"))] #[inline(always)] - pub(crate) fn set_fn_def( - &mut self, - value: Option>>, - ) { + pub(crate) fn set_fn_def(&mut self, value: Option>>) { self.fn_def = value.map(Into::into); } } @@ -374,7 +374,7 @@ impl TryFrom for FnPtr { } #[cfg(not(feature = "no_function"))] -impl>> From for FnPtr { +impl>> From for FnPtr { #[inline(always)] fn from(value: T) -> Self { let fn_def = value.into();