From f647e0f64b303a20121d30744cefd7b55cd0a489 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Wed, 23 Nov 2022 23:15:33 -0600 Subject: [PATCH 1/7] generic arenas --- src/gc-arena/src/arena.rs | 8 ++------ src/gc-arena/tests/tests.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/gc-arena/src/arena.rs b/src/gc-arena/src/arena.rs index 7c33339..75c8207 100644 --- a/src/gc-arena/src/arena.rs +++ b/src/gc-arena/src/arena.rs @@ -97,18 +97,14 @@ impl ArenaParameters { /// pointers and manually ensuring that invariants are held. #[macro_export] macro_rules! make_arena { - ($arena:ident, $root:ident) => { - make_arena!(pub(self) $arena, $root); - }; - - ($vis:vis $arena:ident, $root:ident) => { + ($vis:vis $arena:ident $(( $($arena_generics:tt)* ))?, $root:ident $(( $($root_generics:tt)* ))?) => { // Instead of generating an impl of `RootProvider`, we use a trait object. // The projection `>::Root` is used to obtain the root // type with the lifetime `'gc` applied // By using a trait object, we avoid the need to generate a new type for each // invocation of this macro, which would lead to name conflicts if the macro was // used multiple times in the same scope. - $vis type $arena = $crate::Arena $crate::RootProvider<'a, Root = $root<'a>>>; + $vis type $arena $(< $($arena_generics)* >)? = $crate::Arena $crate::RootProvider<'a, Root = $root<'a, $($($root_generics)*)?>>>; }; } diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index c59d576..0a76e0e 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -251,6 +251,22 @@ fn derive_collect() { assert_eq!(Test8::needs_trace(), false); } +#[test] +fn generic_make_arena() { + #[derive(Collect)] + #[collect(no_drop)] + struct Test<'gc, T: 'gc + Collect>(Gc<'gc, T>); + make_arena!(TestArena(T), Test(T)); + + fn test(v: T) -> T { + let arena = TestArena::new(Default::default(), |mc| Test(Gc::allocate(mc, v))); + arena.mutate(|_, arena| *arena.0) + } + + assert_eq!(test(34), 34); + assert_eq!(test(false), false); +} + #[test] fn ui() { let t = trybuild::TestCases::new(); From 1abaa91f3dfccb5eef894415bb9156a1dec0b15f Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Thu, 24 Nov 2022 00:41:10 -0600 Subject: [PATCH 2/7] more complex test --- src/gc-arena/tests/tests.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index 0a76e0e..b7c5442 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -255,16 +255,16 @@ fn derive_collect() { fn generic_make_arena() { #[derive(Collect)] #[collect(no_drop)] - struct Test<'gc, T: 'gc + Collect>(Gc<'gc, T>); - make_arena!(TestArena(T), Test(T)); + struct Test<'gc, T: 'gc + Collect, const N: usize>(Gc<'gc, T>); + make_arena!(TestArena(T, const N: usize), Test((T, T), N)); - fn test(v: T) -> T { - let arena = TestArena::new(Default::default(), |mc| Test(Gc::allocate(mc, v))); - arena.mutate(|_, arena| *arena.0) + fn test(v: T) -> ((T, T), usize) { + let arena = TestArena::::new(Default::default(), |mc| Test(Gc::allocate(mc, (v, v)))); + (arena.mutate(|_, arena| *arena.0), N) } - assert_eq!(test(34), 34); - assert_eq!(test(false), false); + assert_eq!(test::<12, _>(34), ((34, 34), 12)); + assert_eq!(test::<7, _>(false), ((false, false), 7)); } #[test] From ec1760356ff4bab7be309205316b0959324908e0 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Thu, 24 Nov 2022 00:45:30 -0600 Subject: [PATCH 3/7] better const generic test --- src/gc-arena/tests/tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index b7c5442..0d0ee97 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -255,12 +255,14 @@ fn derive_collect() { fn generic_make_arena() { #[derive(Collect)] #[collect(no_drop)] - struct Test<'gc, T: 'gc + Collect, const N: usize>(Gc<'gc, T>); + struct Test<'gc, T: 'gc + Collect, const N: usize>(Gc<'gc, T>, [(); N]); make_arena!(TestArena(T, const N: usize), Test((T, T), N)); fn test(v: T) -> ((T, T), usize) { - let arena = TestArena::::new(Default::default(), |mc| Test(Gc::allocate(mc, (v, v)))); - (arena.mutate(|_, arena| *arena.0), N) + let arena = TestArena::::new(Default::default(), |mc| { + Test(Gc::allocate(mc, (v, v)), [(); N]) + }); + arena.mutate(|_, arena| (*arena.0, arena.1.len())) } assert_eq!(test::<12, _>(34), ((34, 34), 12)); From 2b466d4bb0328fe61136df1f4678f6dd5cbe9a42 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Thu, 24 Nov 2022 01:07:40 -0600 Subject: [PATCH 4/7] access `'gc` in generic args --- src/gc-arena/src/arena.rs | 2 +- src/gc-arena/tests/tests.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/gc-arena/src/arena.rs b/src/gc-arena/src/arena.rs index 75c8207..3621ce6 100644 --- a/src/gc-arena/src/arena.rs +++ b/src/gc-arena/src/arena.rs @@ -104,7 +104,7 @@ macro_rules! make_arena { // By using a trait object, we avoid the need to generate a new type for each // invocation of this macro, which would lead to name conflicts if the macro was // used multiple times in the same scope. - $vis type $arena $(< $($arena_generics)* >)? = $crate::Arena $crate::RootProvider<'a, Root = $root<'a, $($($root_generics)*)?>>>; + $vis type $arena $(< $($arena_generics)* >)? = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($($root_generics)*)?>>>; }; } diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index 0d0ee97..d788dbf 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -255,18 +255,21 @@ fn derive_collect() { fn generic_make_arena() { #[derive(Collect)] #[collect(no_drop)] - struct Test<'gc, T: 'gc + Collect, const N: usize>(Gc<'gc, T>, [(); N]); - make_arena!(TestArena(T, const N: usize), Test((T, T), N)); - - fn test(v: T) -> ((T, T), usize) { - let arena = TestArena::::new(Default::default(), |mc| { - Test(Gc::allocate(mc, (v, v)), [(); N]) + struct Test<'gc, T: 'gc + Collect, const N: usize, U: 'gc + Collect>(Gc<'gc, T>, [(); N], U); + make_arena!(TestArena(T, const N: usize, U), Test((T, T), N, Gc<'gc, U>)); + + fn test( + v: T, + x: U, + ) -> ((T, T), usize, U) { + let arena = TestArena::::new(Default::default(), |mc| { + Test(Gc::allocate(mc, (v, v)), [(); N], Gc::allocate(mc, x)) }); - arena.mutate(|_, arena| (*arena.0, arena.1.len())) + arena.mutate(|_, arena| (*arena.0, arena.1.len(), *arena.2)) } - assert_eq!(test::<12, _>(34), ((34, 34), 12)); - assert_eq!(test::<7, _>(false), ((false, false), 7)); + assert_eq!(test::<12, _, _>(34, 12i8), ((34, 34), 12, 12i8)); + assert_eq!(test::<7, _, _>(false, -6i64), ((false, false), 7, -6i64)); } #[test] From 11b34d4174e9623846e8afc9938af94608671055 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Fri, 25 Nov 2022 00:15:33 -0600 Subject: [PATCH 5/7] switch to angle brackets --- src/gc-arena/src/arena.rs | 20 ++++++++++++++++++-- src/gc-arena/tests/tests.rs | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/gc-arena/src/arena.rs b/src/gc-arena/src/arena.rs index 3621ce6..3471486 100644 --- a/src/gc-arena/src/arena.rs +++ b/src/gc-arena/src/arena.rs @@ -97,14 +97,30 @@ impl ArenaParameters { /// pointers and manually ensuring that invariants are held. #[macro_export] macro_rules! make_arena { - ($vis:vis $arena:ident $(( $($arena_generics:tt)* ))?, $root:ident $(( $($root_generics:tt)* ))?) => { + ($vis:vis $arena:ident < $($rest:tt)*) => { make_arena!(@arena $vis $arena () $($rest)*); }; + ($vis:vis $arena:ident , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena () $root () $($rest)*); }; + ($vis:vis $arena:ident , $root:ident) => { make_arena!(@done $vis $arena () $root ()); }; + + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* $ty ,) $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* $ty) $root () $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* $ty) $root ()); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* const $var : $ty ,) $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* const $var : $ty) $root () $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* const $var : $ty) $root ()); }; + + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty ,) $($rest)*); }; + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty)); }; + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) const $var:ident : $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* const $var : $ty ,) $($rest)*); }; + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) const $var:ident : $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* const $var : $ty)); }; + + (@done $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*)) => { // Instead of generating an impl of `RootProvider`, we use a trait object. // The projection `>::Root` is used to obtain the root // type with the lifetime `'gc` applied // By using a trait object, we avoid the need to generate a new type for each // invocation of this macro, which would lead to name conflicts if the macro was // used multiple times in the same scope. - $vis type $arena $(< $($arena_generics)* >)? = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($($root_generics)*)?>>>; + $vis type $arena <$($arena_gen)*> = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($root_gen)*>>>; }; } diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index d788dbf..42e41ca 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -256,7 +256,7 @@ fn generic_make_arena() { #[derive(Collect)] #[collect(no_drop)] struct Test<'gc, T: 'gc + Collect, const N: usize, U: 'gc + Collect>(Gc<'gc, T>, [(); N], U); - make_arena!(TestArena(T, const N: usize, U), Test((T, T), N, Gc<'gc, U>)); + make_arena!(TestArena, Test<(T, T), N, Gc<'gc, U>>); fn test( v: T, From 3ac4e6d10c6f34b4cfd5156989909699b7112154 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Fri, 25 Nov 2022 02:31:00 -0600 Subject: [PATCH 6/7] simp + decl lifetimes --- src/gc-arena/src/arena.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/gc-arena/src/arena.rs b/src/gc-arena/src/arena.rs index 3471486..4d70cb5 100644 --- a/src/gc-arena/src/arena.rs +++ b/src/gc-arena/src/arena.rs @@ -101,17 +101,15 @@ macro_rules! make_arena { ($vis:vis $arena:ident , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena () $root () $($rest)*); }; ($vis:vis $arena:ident , $root:ident) => { make_arena!(@done $vis $arena () $root ()); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* $ty ,) $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* $ty) $root () $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $ty:ident > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* $ty) $root ()); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* $tok ,) $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* $tok) $root () $($rest)*); }; + (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* $tok) $root ()); }; (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* const $var : $ty ,) $($rest)*); }; (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* const $var : $ty) $root () $($rest)*); }; (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* const $var : $ty) $root ()); }; - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty ,) $($rest)*); }; - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty)); }; - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) const $var:ident : $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* const $var : $ty ,) $($rest)*); }; - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) const $var:ident : $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* const $var : $ty)); }; + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty ,) $($rest)*); }; + (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty)); }; (@done $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*)) => { // Instead of generating an impl of `RootProvider`, we use a trait object. @@ -120,7 +118,7 @@ macro_rules! make_arena { // By using a trait object, we avoid the need to generate a new type for each // invocation of this macro, which would lead to name conflicts if the macro was // used multiple times in the same scope. - $vis type $arena <$($arena_gen)*> = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($root_gen)*>>>; + $vis type $arena<$($arena_gen)*> = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($root_gen)*>>>; }; } From 265611d0b4b56665d6106841d18cb06899bd4f23 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Mon, 28 Nov 2022 23:58:27 -0600 Subject: [PATCH 7/7] revert to simple syntax --- src/gc-arena/src/arena.rs | 18 ++---------------- src/gc-arena/tests/tests.rs | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/gc-arena/src/arena.rs b/src/gc-arena/src/arena.rs index 4d70cb5..e2fb79a 100644 --- a/src/gc-arena/src/arena.rs +++ b/src/gc-arena/src/arena.rs @@ -97,28 +97,14 @@ impl ArenaParameters { /// pointers and manually ensuring that invariants are held. #[macro_export] macro_rules! make_arena { - ($vis:vis $arena:ident < $($rest:tt)*) => { make_arena!(@arena $vis $arena () $($rest)*); }; - ($vis:vis $arena:ident , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena () $root () $($rest)*); }; - ($vis:vis $arena:ident , $root:ident) => { make_arena!(@done $vis $arena () $root ()); }; - - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* $tok ,) $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* $tok) $root () $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) $tok:tt > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* $tok) $root ()); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty , $($rest:tt)*) => { make_arena!(@arena $vis $arena ($($arena_gen)* const $var : $ty ,) $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident < $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)* const $var : $ty) $root () $($rest)*); }; - (@arena $vis:vis $arena:ident ($($arena_gen:tt)*) const $var:ident : $ty:ty > , $root:ident) => { make_arena!(@done $vis $arena ($($arena_gen)* const $var : $ty) $root ()); }; - - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty , $($rest:tt)*) => { make_arena!(@root $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty ,) $($rest)*); }; - (@root $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*) $ty:ty >) => { make_arena!(@done $vis $arena ($($arena_gen)*) $root ($($root_gen)* $ty)); }; - - (@done $vis:vis $arena:ident ($($arena_gen:tt)*) $root:ident ($($root_gen:tt)*)) => { + ($vis:vis $arena:ident $(( $($arena_gen:tt)* ))?, $root:ident $(( $($root_gen:tt)* ))?) => { // Instead of generating an impl of `RootProvider`, we use a trait object. // The projection `>::Root` is used to obtain the root // type with the lifetime `'gc` applied // By using a trait object, we avoid the need to generate a new type for each // invocation of this macro, which would lead to name conflicts if the macro was // used multiple times in the same scope. - $vis type $arena<$($arena_gen)*> = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $($root_gen)*>>>; + $vis type $arena $( <$($arena_gen)*> )? = $crate::Arena $crate::RootProvider<'gc, Root = $root<'gc, $( $($root_gen)* )?>>>; }; } diff --git a/src/gc-arena/tests/tests.rs b/src/gc-arena/tests/tests.rs index 42e41ca..d788dbf 100644 --- a/src/gc-arena/tests/tests.rs +++ b/src/gc-arena/tests/tests.rs @@ -256,7 +256,7 @@ fn generic_make_arena() { #[derive(Collect)] #[collect(no_drop)] struct Test<'gc, T: 'gc + Collect, const N: usize, U: 'gc + Collect>(Gc<'gc, T>, [(); N], U); - make_arena!(TestArena, Test<(T, T), N, Gc<'gc, U>>); + make_arena!(TestArena(T, const N: usize, U), Test((T, T), N, Gc<'gc, U>)); fn test( v: T,