diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 827cce8e1..25bdb9cfe 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -488,10 +488,23 @@ impl fmt::Display for Dynamic { f.write_str((***v).type_name()) } + #[cfg(not(feature = "no_closure"))] + Union::Shared(ref cell, ..) if cfg!(feature = "unchecked") => { + #[cfg(not(feature = "sync"))] + match cell.try_borrow() { + Ok(v) => { + fmt::Display::fmt(&*v, f)?; + f.write_str(" (shared)") + } + Err(_) => f.write_str(""), + } + #[cfg(feature = "sync")] + fmt::Display::fmt(&*cell.read().unwrap(), f) + } #[cfg(not(feature = "no_closure"))] Union::Shared(..) => { // Avoid infinite recursion for shared values in a reference loop. - pub fn display_fmt( + fn display_fmt( value: &Dynamic, f: &mut fmt::Formatter<'_>, dict: &mut std::collections::HashSet<*const Dynamic>, @@ -646,10 +659,23 @@ impl fmt::Debug for Dynamic { f.write_str((***v).type_name()) } + #[cfg(not(feature = "no_closure"))] + Union::Shared(ref cell, ..) if cfg!(feature = "unchecked") => { + #[cfg(not(feature = "sync"))] + match cell.try_borrow() { + Ok(v) => { + fmt::Debug::fmt(&*v, f)?; + f.write_str(" (shared)") + } + Err(_) => f.write_str(""), + } + #[cfg(feature = "sync")] + fmt::Debug::fmt(&*cell.read().unwrap(), f) + } #[cfg(not(feature = "no_closure"))] Union::Shared(..) => { // Avoid infinite recursion for shared values in a reference loop. - pub fn debug_fmt( + fn debug_fmt( value: &Dynamic, f: &mut fmt::Formatter<'_>, dict: &mut std::collections::HashSet<*const Dynamic>, diff --git a/src/types/scope.rs b/src/types/scope.rs index d94067736..16bc229bb 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -77,19 +77,13 @@ pub struct Scope<'a> { impl fmt::Display for Scope<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (i, (name, constant, value)) in self.iter_inner().enumerate() { - #[cfg(not(feature = "no_closure"))] - let value_is_shared = if value.is_shared() { " (shared)" } else { "" }; - #[cfg(feature = "no_closure")] - let value_is_shared = ""; - writeln!( f, - "[{}] {}{}{} = {:?}", + "[{}] {}{} = {:?}", i + 1, if constant { "const " } else { "" }, name, - value_is_shared, - *value.read_lock::().unwrap(), + value, )?; } diff --git a/tests/stack.rs b/tests/stack.rs index 2d187e951..1128d2544 100644 --- a/tests/stack.rs +++ b/tests/stack.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "unchecked"))] -use rhai::{Engine, EvalAltResult, ParseErrorType, INT}; +use rhai::{Dynamic, Engine, EvalAltResult, ParseErrorType, INT}; #[test] #[cfg(not(feature = "no_function"))] @@ -20,7 +20,6 @@ fn test_stack_overflow_fn_calls() { let max = engine.max_call_levels(); - #[cfg(not(feature = "unchecked"))] assert!(matches!( *engine .run(&format!( @@ -132,3 +131,24 @@ fn test_stack_overflow_parsing() { #[cfg(not(feature = "no_function"))] engine.compile("fn abc(x) { x + 1 }").unwrap(); } + +#[test] +#[cfg(not(feature = "no_closure"))] +#[cfg(not(feature = "no_function"))] +#[cfg(not(feature = "no_object"))] +fn test_stack_overflow_ref_loop() { + let engine = Engine::new(); + + let x = engine + .eval::( + " + let x; + let data = #{ foo: || x = this }; + data.foo(); + x + ", + ) + .unwrap(); + + println!("{x:?}"); +}