diff --git a/src/bytecode.rs b/src/bytecode.rs index dc10e96e..7000a685 100755 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -1041,7 +1041,7 @@ mod test { cx: &mut Context, ) { root!(env, Env::default(), cx); - let val = rebind!(call(bytecode, args, "test", env, cx).unwrap(), cx); + let val = rebind!(call(bytecode, args, "test", env, cx).unwrap()); let expect = expect.bind(cx); assert_eq!(val, expect); } diff --git a/src/core/gc/context.rs b/src/core/gc/context.rs index 3ba1bc00..4ad3ae2a 100644 --- a/src/core/gc/context.rs +++ b/src/core/gc/context.rs @@ -259,6 +259,14 @@ impl Drop for Block { } } +// helper macro for the `rebind!` macro +macro_rules! last { + ($arg:expr) => { $arg }; + ($head:expr, $($rest:expr),+) => { + last!($($rest),+) + }; +} + /// Rebinds an object so that it is bound to an immutable borrow of [Context] /// instead of a mutable borrow. This can release the mutable borrow and allow /// Context to be used for other things. @@ -266,14 +274,28 @@ impl Drop for Block { /// # Examples /// /// ``` -/// let object = func_taking_mut_context(&mut cx); -/// rebind!(object, cx); +/// let object = rebind!(func1(&mut cx)); +/// func2(&mut cx); +/// let object2 = object; /// ``` +/// +/// wthout this macro the above code would not compile because `object` can't +/// outlive the call to func2. #[macro_export] macro_rules! rebind { - ($value:expr, $cx:ident) => {{ + // rebind!(func(x, cx)?) + ($($path:ident).*($($arg:expr),+)$($x:tt)?) => {{ + rebind!($($path).*($($arg),+)$($x)?, last!($($arg),+)) + }}; + // rebind!(func(x, cx).unwrap()) + ($($path:ident).*($($arg:expr),+).unwrap()) => {{ + rebind!($($path).*($($arg),+).unwrap(), last!($($arg),+)) + }}; + // rebind!(x, cx) + ($value:expr, $cx:expr) => {{ let bits = $value.into_raw(); - unsafe { $cx.rebind_raw_ptr(bits) } + #[allow(clippy::unnecessary_mut_passed)] + unsafe { $crate::core::gc::Context::rebind_raw_ptr($cx, bits) } }}; } @@ -290,7 +312,7 @@ mod test { fn test_reborrow() { let roots = &RootSet::default(); let mut cx = Context::new(roots); - let obj = rebind!(bind_to_mut(&mut cx), cx); + let obj = rebind!(bind_to_mut(&mut cx)); _ = "foo".into_obj(&cx); assert_eq!(obj, "invariant"); } diff --git a/src/interpreter.rs b/src/interpreter.rs index df4de6f0..74b57339 100755 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -129,7 +129,7 @@ impl Interpreter<'_> { root!(name, cx); let value = match forms.next() { // (defvar x y) - Some(value) => rebind!(self.eval_form(value, cx)?, cx), + Some(value) => rebind!(self.eval_form(value, cx)?), // (defvar x) None => nil(), }; @@ -316,7 +316,7 @@ impl Interpreter<'_> { (Object::Symbol(var), Some(val)) => { root!(var, cx); root!(val, cx); - let val = rebind!(self.eval_form(val, cx)?, cx); + let val = rebind!(self.eval_form(val, cx)?); self.var_set(var.bind(cx), val, cx)?; last_value.set(val); } @@ -393,7 +393,7 @@ impl Interpreter<'_> { } else { self.let_bind_serial(obj, cx) }?; - let obj = rebind!(self.implicit_progn(iter, cx)?, cx); + let obj = rebind!(self.implicit_progn(iter, cx)?); // Remove old bindings self.vars.truncate(prev_len); self.env.unbind(varbind_count, cx); @@ -408,7 +408,7 @@ impl Interpreter<'_> { // (let ((x y))) Object::Cons(_) => { let cons = binding.as_cons(); - let val = rebind!(self.let_bind_value(cons, cx)?, cx); + let val = rebind!(self.let_bind_value(cons, cx)?); let var: Symbol = cons .get(cx) .car() @@ -435,7 +435,7 @@ impl Interpreter<'_> { // (let ((x y))) Object::Cons(_) => { let cons = binding.as_cons(); - let var = rebind!(self.let_bind_value(cons, cx)?, cx); + let var = rebind!(self.let_bind_value(cons, cx)?); let sym: Symbol = cons .get(cx) .car() @@ -762,7 +762,7 @@ mod test { println!("Test String: {test_str}"); let obj = crate::reader::read(test_str, cx).unwrap().0; root!(obj, cx); - let compare = rebind!(eval(obj, None, env, cx).unwrap(), cx); + let compare = rebind!(eval(obj, None, env, cx).unwrap()); let expect: GcObj = expect.into_obj(cx).copy_as_obj(); assert_eq!(compare, expect); }