Skip to content

Commit 3e57453

Browse files
committed
Switch all manually_traced impls to unsafe_gc_impl!`
This procedural derive is **much** cleaner (although it brings in all of syn as a dependency)
1 parent 288f357 commit 3e57453

File tree

7 files changed

+215
-403
lines changed

7 files changed

+215
-403
lines changed

libs/derive/src/macros.rs

Lines changed: 89 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ impl MacroInput {
8686
} else {
8787
quote!()
8888
};
89-
let rebrand_impl = self.expand_brand_impl(true);
90-
let erase_impl = self.expand_brand_impl(false);
89+
let rebrand_impl = self.expand_brand_impl(true)?;
90+
let erase_impl = self.expand_brand_impl(false)?;
9191
Ok(quote! {
9292
#trace_impl
9393
#trace_immutable_impl
@@ -129,7 +129,7 @@ impl MacroInput {
129129
unsafe impl #impl_generics #trait_name for #target_type #where_clause {
130130
#needs_trace_const
131131
#[inline] // TODO: Should this be unconditional?
132-
fn #visit_method_name<V: GcVisitor + ?Sized>(&#mutability self, visitor: &mut V) -> Result<(), V::Err> {
132+
fn #visit_method_name<Visitor: GcVisitor + ?Sized>(&#mutability self, visitor: &mut Visitor) -> Result<(), Visitor::Err> {
133133
#visit_impl
134134
}
135135
}
@@ -151,16 +151,18 @@ impl MacroInput {
151151
}
152152
})
153153
}
154-
fn expand_brand_impl(&self, rebrand: bool /* true => rebrand, false => erase */) -> Option<TokenStream> {
154+
fn expand_brand_impl(&self, rebrand: bool /* true => rebrand, false => erase */) -> Result<Option<TokenStream>, Error> {
155155
let requirements = if rebrand { self.bounds.rebrand.clone() } else { self.bounds.erase.clone() };
156156
if let Some(TraitRequirements::Never) = requirements {
157157
// They are requesting that we dont implement
158-
return None;
158+
return Ok(None);
159159
}
160160
let target_type = &self.target_type;
161161
let mut generics = self.basic_generics();
162162
let default_bounds: Vec<TypeParamBound> = match requirements {
163-
Some(TraitRequirements::Where(_)) => {
163+
Some(TraitRequirements::Where(ref explicit_requirements)) => {
164+
generics.make_where_clause().predicates
165+
.extend(explicit_requirements.predicates.iter().cloned());
164166
// they have explicit requirements -> no default bounds
165167
vec![]
166168
}
@@ -185,6 +187,8 @@ impl MacroInput {
185187
match param {
186188
GenericParam::Type(ref tp) => {
187189
let type_name = &tp.ident;
190+
let mut bounds = tp.bounds.clone();
191+
bounds.extend(default_bounds.iter().cloned());
188192
generics.make_where_clause()
189193
.predicates.push(WherePredicate::Type(PredicateType {
190194
lifetimes: None,
@@ -193,19 +197,19 @@ impl MacroInput {
193197
parse_quote!(<#type_name as GcRebrand<'new_gc, Id>>::Branded)
194198
})
195199
} else {
196-
self.options.branded_type.clone().unwrap_or_else(|| {
200+
self.options.erased_type.clone().unwrap_or_else(|| {
197201
parse_quote!(<#type_name as GcErase<'min, Id>>::Erased)
198202
})
199203
},
200204
colon_token: Default::default(),
201-
bounds: default_bounds.iter().cloned().collect()
205+
bounds: bounds.clone(),
202206
}));
203207
generics.make_where_clause()
204208
.predicates.push(WherePredicate::Type(PredicateType {
205209
lifetimes: None,
206210
bounded_ty: parse_quote!(#type_name),
207211
colon_token: Default::default(),
208-
bounds: default_bounds.iter().cloned().collect()
212+
bounds
209213
}))
210214
}
211215
_ => {}
@@ -231,56 +235,6 @@ impl MacroInput {
231235
} else {
232236
quote!(GcErase<'min, Id>)
233237
};
234-
fn rewrite_type(target: &Type, target_type_name: &str, rewriter: &mut dyn FnMut(&Type) -> Option<Type>) -> Result<Type, Error> {
235-
if let Some(explicitly_rewritten) = rewriter(target) {
236-
return Ok(explicitly_rewritten)
237-
}
238-
match target {
239-
::syn::Type::Path(::syn::TypePath { ref qself, ref path }) => {
240-
let new_qself = qself.clone().map(|mut qself| {
241-
qself.ty = Box::new(rewrite_type(
242-
&*qself.ty, target_type_name,
243-
&mut *rewriter
244-
)?);
245-
Ok(qself)
246-
}).transpose()?;
247-
let new_path = ::syn::Path {
248-
leading_colon: path.leading_colon,
249-
segments: path.segments.iter().cloned().map(|segment| {
250-
// old_segment.ident is ignored...
251-
for arg in &mut segment.arguments {
252-
match arg {
253-
::syn::PathArguments::None => {}, // Nothing to do here
254-
::syn::PathArguments::AngleBracketed(ref mut generic_args) => {
255-
for arg in &mut generic_args {
256-
match arg {
257-
GenericArgument::Lifetime(_) | GenericArgument::Const(_) => {},
258-
GenericArgument::Type(ref mut generic_type) => {
259-
*generic_type = rewrite_type(generic_type, target_type_name, &mut *rewriter)?;
260-
}
261-
GenericArgument::Constraint(_) | GenericArgument::Binding(_) => {
262-
return Err(Error::new(
263-
arg.span(), format!(
264-
"Unable to handle generic arg while rewriting as a {}",
265-
target_type_name
266-
)
267-
))
268-
}
269-
}
270-
}
271-
}
272-
}
273-
}
274-
}).collect()
275-
};
276-
Ok(::syn::Type::Path(::syn::TypePath { qself: new_qself, path: new_path }))
277-
}
278-
_ => return Err(Error::new(target.span(), format!(
279-
"Unable to rewrite type as a `{}`: {}",
280-
target_type_name, target
281-
)))
282-
}
283-
}
284238
fn rewrite_brand_trait(
285239
target: &Type, trait_name: &str, target_params: &HashSet<Ident>,
286240
target_trait: TokenStream, associated_type: Ident
@@ -307,17 +261,17 @@ impl MacroInput {
307261
_ => None
308262
}).collect::<HashSet<_>>();
309263
let associated_type = if rebrand {
310-
let branded = Ok(self.options.branded_type.clone()).transpose().unwrap_or_else(|| {
264+
let branded = self.options.branded_type.clone().map_or_else(|| {
311265
rewrite_brand_trait(
312266
&self.target_type, "GcRebrand",
313267
&target_params,
314268
parse_quote!(GcRebrand<'new_gc, Id>),
315269
parse_quote!(Branded)
316270
)
317-
})?;
271+
}, Ok)?;
318272
quote!(type Branded = #branded;)
319273
} else {
320-
let erased = Ok(self.options.branded_type.clone()).transpose().unwrap_or_else(|| {
274+
let erased = Ok(self.options.erased_type.clone()).transpose().unwrap_or_else(|| {
321275
rewrite_brand_trait(
322276
&self.target_type, "GcErase",
323277
&target_params,
@@ -327,11 +281,11 @@ impl MacroInput {
327281
})?;
328282
quote!(type Erased = #erased;)
329283
};
330-
Some(quote! {
284+
Ok(Some(quote! {
331285
unsafe impl #impl_generics #target_trait for #target_type #where_clause {
332-
const
286+
#associated_type
333287
}
334-
})
288+
}))
335289
}
336290
}
337291

@@ -585,14 +539,7 @@ fn create_clause_with_default(
585539
}))
586540
}
587541
}
588-
let type_idents = generic_params.iter()
589-
.filter_map(|param| match param {
590-
GenericParam::Type(ref t) => {
591-
Some(t.ident.clone())
592-
},
593-
_ => None
594-
}).collect::<Vec<_>>();
595-
parse_quote!(where #(#type_idents: Trace),*)
542+
where_clause
596543
}
597544
})
598545
}
@@ -739,7 +686,7 @@ impl VisitImpl {
739686
if mutable {
740687
quote!(&mut)
741688
} else {
742-
quote!()
689+
quote!(&)
743690
}
744691
}
745692
};
@@ -853,4 +800,71 @@ impl Parse for TraitRequirements {
853800
return Err(input.error("Invalid `TraitRequirement`"))
854801
}
855802
}
856-
}
803+
}
804+
805+
806+
807+
fn rewrite_type(target: &Type, target_type_name: &str, rewriter: &mut dyn FnMut(&Type) -> Option<Type>) -> Result<Type, Error> {
808+
if let Some(explicitly_rewritten) = rewriter(target) {
809+
return Ok(explicitly_rewritten)
810+
}
811+
let mut target = target.clone();
812+
match target {
813+
Type::Paren(ref mut inner) => {
814+
*inner.elem = rewrite_type(&inner.elem, target_type_name, rewriter)?
815+
},
816+
Type::Group(ref mut inner) => {
817+
*inner.elem = rewrite_type(&inner.elem, target_type_name, rewriter)?
818+
},
819+
Type::Reference(ref mut target) => {
820+
// TODO: Lifetime safety?
821+
// Rewrite reference target
822+
*target.elem = rewrite_type(&target.elem, target_type_name, rewriter)?
823+
}
824+
Type::Path(::syn::TypePath { ref mut qself, ref mut path }) => {
825+
*qself = qself.clone().map::<Result<_, Error>, _>(|mut qself| {
826+
qself.ty = Box::new(rewrite_type(
827+
&*qself.ty, target_type_name,
828+
&mut *rewriter
829+
)?);
830+
Ok(qself)
831+
}).transpose()?;
832+
path.segments = path.segments.iter().cloned().map(|mut segment| {
833+
// old_segment.ident is ignored...
834+
match segment.arguments {
835+
::syn::PathArguments::None => {}, // Nothing to do here
836+
::syn::PathArguments::AngleBracketed(ref mut generic_args) => {
837+
for arg in &mut generic_args.args {
838+
match arg {
839+
GenericArgument::Lifetime(_) | GenericArgument::Const(_) => {},
840+
GenericArgument::Type(ref mut generic_type) => {
841+
*generic_type = rewrite_type(generic_type, target_type_name, &mut *rewriter)?;
842+
}
843+
GenericArgument::Constraint(_) | GenericArgument::Binding(_) => {
844+
return Err(Error::new(
845+
arg.span(), format!(
846+
"Unable to handle generic arg while rewriting as a {}",
847+
target_type_name
848+
)
849+
))
850+
}
851+
}
852+
}
853+
}
854+
::syn::PathArguments::Parenthesized(ref mut paran_args) => {
855+
return Err(Error::new(
856+
paran_args.span(),
857+
"TODO: Rewriting paranthesized (fn-style) args"
858+
));
859+
}
860+
}
861+
Ok(segment)
862+
}).collect::<Result<_, Error>>()?;
863+
}
864+
_ => return Err(Error::new(target.span(), format!(
865+
"Unable to rewrite type as a `{}`: {}",
866+
target_type_name, quote!(#target)
867+
)))
868+
}
869+
Ok(target)
870+
}

src/lib.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use core::marker::PhantomData;
3030
use core::hash::{Hash, Hasher};
3131
use core::fmt::{self, Debug, Formatter};
3232

33+
use zerogc_derive::unsafe_gc_impl;
34+
3335
#[macro_use]
3436
mod manually_traced;
3537
pub mod cell;
@@ -767,26 +769,24 @@ impl<T> DerefMut for AssumeNotTraced<T> {
767769
&mut self.0
768770
}
769771
}
770-
771-
unsafe impl<T> Trace for AssumeNotTraced<T> {
772-
const NEEDS_TRACE: bool = false;
773-
#[inline(always)] // This method does nothing and is always a win to inline
774-
fn visit<V: GcVisitor>(&mut self, _visitor: &mut V) -> Result<(), V::Err> {
775-
Ok(())
776-
}
777-
}
778-
unsafe impl<T> TraceImmutable for AssumeNotTraced<T> {
779-
#[inline(always)]
780-
fn visit_immutable<V: GcVisitor>(&self, _visitor: &mut V) -> Result<(), V::Err> {
781-
Ok(())
782-
}
783-
}
784-
unsafe impl<T> NullTrace for AssumeNotTraced<T> {}
785-
/// No tracing implies GcSafe
786-
unsafe impl<T> GcSafe for AssumeNotTraced<T> {
787-
const NEEDS_DROP: bool = core::mem::needs_drop::<T>();
772+
unsafe_gc_impl! {
773+
target => AssumeNotTraced<T>,
774+
params => [T],
775+
bounds => {
776+
// Unconditionally implement all traits
777+
Trace => always,
778+
TraceImmutable => always,
779+
GcSafe => always,
780+
GcRebrand => { where T: 'new_gc },
781+
GcErase => { where T: 'min }
782+
},
783+
null_trace => always,
784+
branded_type => AssumeNotTraced<T>,
785+
erased_type => AssumeNotTraced<T>,
786+
NEEDS_TRACE => false,
787+
NEEDS_DROP => core::mem::needs_drop::<T>(),
788+
visit => |self, visitor| { /* nop */ Ok(()) }
788789
}
789-
unsafe_gc_brand!(AssumeNotTraced, T);
790790

791791
/// Changes all references to garbage collected
792792
/// objects to match a specific lifetime.

0 commit comments

Comments
 (0)