Skip to content

Commit 67fbafc

Browse files
committed
Have simple collector use parameterized GcSafe
1 parent eac6605 commit 67fbafc

File tree

12 files changed

+371
-119
lines changed

12 files changed

+371
-119
lines changed

libs/context/src/collector.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ pub unsafe trait RawCollectorImpl: 'static + Sized {
4949
const SYNC: bool;
5050

5151
fn id_for_gc<'a, 'gc, T>(gc: &'a Gc<'gc, T, CollectorId<Self>>) -> &'a CollectorId<Self>
52-
where 'gc: 'a, T: GcSafe<'gc, CollectorId<Self>> + ?Sized + 'gc;
52+
where 'gc: 'a, T: ?Sized + 'gc;
5353

5454
fn id_for_array<'a, 'gc, T>(gc: &'a GcArray<'gc, T, CollectorId<Self>>) -> &'a CollectorId<Self>
55-
where 'gc: 'a, T: GcSafe<'gc, CollectorId<Self>> + 'gc;
55+
where 'gc: 'a, T: 'gc;
5656

5757
fn resolve_array_len<'gc, T>(gc: GcArray<'gc, T, CollectorId<Self>>) -> usize
58-
where T: GcSafe<'gc, CollectorId<Self>> + 'gc;
58+
where T: 'gc;
5959

6060
/// Convert the specified value into a dyn pointer
6161
unsafe fn as_dyn_trace_pointer<T: Trace>(t: *mut T) -> Self::DynTracePtr;
@@ -286,17 +286,17 @@ unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {
286286
type RawVecRepr<'gc> = C::RawVecRepr<'gc>;
287287

288288
#[inline]
289-
fn from_gc_ptr<'a, 'gc, T>(gc: &'a Gc<'gc, T, Self>) -> &'a Self where T: GcSafe<'gc, Self> + ?Sized + 'gc, 'gc: 'a {
289+
fn from_gc_ptr<'a, 'gc, T>(gc: &'a Gc<'gc, T, Self>) -> &'a Self where T: ?Sized + 'gc, 'gc: 'a {
290290
C::id_for_gc(gc)
291291
}
292292

293293
#[inline]
294-
fn resolve_array_len<'gc, T>(gc: GcArray<'gc, T, Self>) -> usize where T: GcSafe<'gc, Self> + 'gc {
294+
fn resolve_array_len<'gc, T>(gc: GcArray<'gc, T, Self>) -> usize where T: 'gc {
295295
C::resolve_array_len(gc)
296296
}
297297

298298
#[inline]
299-
fn resolve_array_id<'a, 'gc, T>(gc: &'a GcArray<'gc, T, Self>) -> &'a Self where T: GcSafe<'gc, Self> + 'gc, 'gc: 'a {
299+
fn resolve_array_id<'a, 'gc, T>(gc: &'a GcArray<'gc, T, Self>) -> &'a Self where T: 'gc, 'gc: 'a {
300300
C::id_for_array(gc)
301301
}
302302

libs/context/src/handle.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,7 @@ unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
467467
let value = inner.value.load(Ordering::Acquire)
468468
as *mut T as *mut T::Branded;
469469
debug_assert!(!value.is_null());
470-
Gc::from_raw(
471-
collector,
472-
NonNull::new_unchecked(value)
473-
)
470+
Gc::from_raw(NonNull::new_unchecked(value))
474471
}
475472
}
476473

libs/derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ zerogc = { version = "0.2.0-alpha.5", path = "../.." }
1616

1717
[dependencies]
1818
# Proc macros
19-
syn = { version = "1.0.55", features = ["full", "extra-traits"] }
19+
syn = { version = "1.0.55", features = ["full", "extra-traits", "fold"] }
2020
quote = "1.0.8"
2121
darling = "0.13"
2222
proc-macro2 = "1"

libs/derive/src/derive.rs

Lines changed: 254 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use darling::{Error, FromMeta, FromGenerics, FromTypeParam, FromDeriveInput, FromVariant, FromField};
22
use proc_macro2::{Ident, TokenStream, Span};
3-
use syn::{Generics, Type, GenericParam, TypeParam, Lifetime, Path, parse_quote, PathArguments, GenericArgument, TypePath, Meta};
3+
use syn::{Generics, Type, GenericParam, TypeParam, Lifetime, Path, parse_quote, PathArguments, GenericArgument, TypePath, Meta, LifetimeDef};
44
use darling::util::{SpannedValue};
55
use quote::{quote_spanned, quote, format_ident, ToTokens};
66
use darling::ast::{Style, Data};
@@ -15,6 +15,37 @@ pub enum TraceDeriveKind {
1515
Regular
1616
}
1717

18+
trait PossiblyIgnoredParam {
19+
fn check_ignored(&self, generics: &TraceGenerics) -> bool;
20+
}
21+
impl PossiblyIgnoredParam for syn::Lifetime {
22+
fn check_ignored(&self, generics: &TraceGenerics) -> bool {
23+
generics.ignored_lifetimes.contains(self)
24+
}
25+
}
26+
impl PossiblyIgnoredParam for Ident {
27+
fn check_ignored(&self, generics: &TraceGenerics) -> bool {
28+
generics.type_params.iter().any(|param| (param.ignore || param.collector_id) && param.ident == *self)
29+
}
30+
}
31+
impl PossiblyIgnoredParam for Path {
32+
fn check_ignored(&self, generics: &TraceGenerics) -> bool {
33+
self.get_ident().map_or(false, |ident| ident.check_ignored(generics))
34+
}
35+
}
36+
impl PossiblyIgnoredParam for syn::Type {
37+
fn check_ignored(&self, generics: &TraceGenerics) -> bool {
38+
match *self {
39+
Type::Group(ref e) => e.elem.check_ignored(generics),
40+
Type::Paren(ref p) => p.elem.check_ignored(generics),
41+
Type::Path(ref p) if p.qself.is_none() => {
42+
p.path.check_ignored(generics)
43+
},
44+
_ => false
45+
}
46+
}
47+
}
48+
1849
#[derive(Debug)]
1950
struct TraceGenerics {
2051
original: Generics,
@@ -23,6 +54,9 @@ struct TraceGenerics {
2354
type_params: Vec<TraceTypeParam>
2455
}
2556
impl TraceGenerics {
57+
fn is_ignored<P: PossiblyIgnoredParam>(&self, item: &P) -> bool {
58+
item.check_ignored(self)
59+
}
2660
/// Return all the "regular" type parameters,
2761
/// excluding `Id` parameters and those marked `#[zerogc(ignore)]`
2862
fn regular_type_params(&self) -> impl Iterator<Item=&'_ TraceTypeParam> + '_ {
@@ -370,32 +404,176 @@ impl TraceDeriveInput {
370404
)
371405
}
372406
TraceDeriveKind::Regular => {
373-
let mut has_explicit_collector_ids = false;
374-
let mut impls = Vec::new();
375-
if let Some(ref ids) = self.collector_ids {
376-
for id in ids.0.iter() {
377-
has_explicit_collector_ids = true;
378-
let mut initial_generics = generics.clone();
379-
initial_generics.make_where_clause().predicates
380-
.push(parse_quote!(#id: zerogc::CollectorId));
381-
impls.push(self.expand_gcsafe_sepcific(
382-
kind, Some(initial_generics),
383-
id, &gc_lifetime
384-
)?)
407+
self.expand_for_each_regular_id(
408+
generics.clone(), kind, gc_lifetime,
409+
&mut |kind, initial, id, gc_lt| {
410+
self.expand_gcsafe_sepcific(kind, initial, id, gc_lt)
385411
}
412+
)
413+
}
414+
}
415+
}
416+
fn expand_for_each_regular_id(
417+
&self, generics: Generics,
418+
kind: TraceDeriveKind,
419+
gc_lifetime: Lifetime,
420+
func: &mut dyn FnMut(TraceDeriveKind, Option<Generics>, &Path, &Lifetime) -> Result<TokenStream, Error>
421+
) -> Result<TokenStream, Error> {
422+
let mut has_explicit_collector_ids = false;
423+
let mut impls = Vec::new();
424+
if let Some(ref ids) = self.collector_ids {
425+
for id in ids.0.iter() {
426+
has_explicit_collector_ids = true;
427+
let mut initial_generics = generics.clone();
428+
initial_generics.make_where_clause().predicates
429+
.push(parse_quote!(#id: zerogc::CollectorId));
430+
impls.push(func(
431+
kind, Some(initial_generics),
432+
id, &gc_lifetime
433+
)?)
434+
}
435+
}
436+
if !has_explicit_collector_ids {
437+
let mut initial_generics = generics;
438+
initial_generics.params.push(parse_quote!(Id: zerogc::CollectorId));
439+
impls.push(func(
440+
kind, Some(initial_generics.clone()),
441+
&parse_quote!(Id),&gc_lifetime
442+
)?)
443+
}
444+
assert!(!impls.is_empty());
445+
Ok(quote!(#(#impls)*))
446+
}
447+
fn expand_rebrand(&self, kind: TraceDeriveKind) -> Result<TokenStream, Error> {
448+
let target_type = &self.ident;
449+
if matches!(kind, TraceDeriveKind::NullTrace) {
450+
let mut generics = self.generics.original.clone();
451+
generics.params.push(parse_quote!(Id: zerogc::CollectorId));
452+
generics.params.push(parse_quote!('new_gc));
453+
for regular in self.generics.regular_type_params() {
454+
let regular = &regular.ident;
455+
generics.make_where_clause().predicates.push(parse_quote!(#regular: zerogc::NullTrace));
456+
}
457+
for ignored in &self.generics.ignored_lifetimes {
458+
generics.make_where_clause().predicates.push(parse_quote!(#ignored: 'new_gc))
459+
}
460+
generics.make_where_clause().predicates.push(parse_quote!(Self: GcSafe<'new_gc, Id>));
461+
if let Some(ref gc_lt) = self.gc_lifetime() {
462+
return Err(Error::custom("A NullTrace type may not have a 'gc lifetime").with_span(gc_lt))
463+
}
464+
let (_, ty_generics, _) = self.generics.original.split_for_impl();
465+
let (impl_generics, _, where_clause) = generics.split_for_impl();
466+
return Ok(quote! {
467+
unsafe impl #impl_generics zerogc::GcRebrand<'new_gc, Id> for #target_type #ty_generics #where_clause {
468+
type Branded = Self;
386469
}
387-
if !has_explicit_collector_ids {
388-
let mut initial_generics = generics.clone();
389-
initial_generics.params.push(parse_quote!(Id: zerogc::CollectorId));
390-
impls.push(self.expand_gcsafe_sepcific(
391-
kind, Some(initial_generics.clone()),
392-
&parse_quote!(Id),&gc_lifetime
393-
)?)
394-
}
395-
assert!(!impls.is_empty());
396-
Ok(quote!(#(#impls)*))
470+
});
471+
}
472+
let mut generics = self.generics.original.clone();
473+
let (old_gc_lt, new_gc_lt): (syn::Lifetime, syn::Lifetime) = match self.gc_lifetime() {
474+
Some(lt) => {
475+
generics.params.push(parse_quote!('new_gc));
476+
(lt.clone(), parse_quote!('new_gc))
477+
},
478+
None => {
479+
generics.params.push(parse_quote!('gc));
480+
generics.params.push(parse_quote!('new_gc));
481+
(parse_quote!('gc), parse_quote!('new_gc))
482+
}
483+
};
484+
self.expand_for_each_regular_id(
485+
generics, kind, old_gc_lt,
486+
&mut |kind, initial_generics, id, orig_lt| {
487+
self.expand_rebrand_specific(
488+
kind, initial_generics,
489+
id, orig_lt, new_gc_lt.clone()
490+
)
397491
}
492+
)
493+
}
494+
fn expand_rebrand_specific(
495+
&self, kind: TraceDeriveKind,
496+
initial_generics: Option<Generics>,
497+
id: &Path, orig_lt: &Lifetime, new_lt: Lifetime
498+
) -> Result<TokenStream, Error> {
499+
assert!(!matches!(kind, TraceDeriveKind::NullTrace));
500+
let mut fold = RebrandFold {
501+
generics: &self.generics,
502+
collector_ids: self.collector_ids.as_ref().map_or_else(
503+
|| HashSet::from([parse_quote!(Id)]),
504+
|ids| {
505+
ids.0.iter().map(|p| Type::Path(TypePath {
506+
qself: None,
507+
path: p.clone()
508+
})).collect()
509+
}),
510+
new_lt: &new_lt,
511+
orig_lt, id
512+
};
513+
let mut generics = syn::fold::fold_generics(
514+
&mut fold,
515+
initial_generics.unwrap_or_else(|| self.generics.original.clone()),
516+
);
517+
for param in self.generics.regular_type_params() {
518+
let name = &param.ident;
519+
generics.make_where_clause().predicates.push(parse_quote!(#name: zerogc::GcRebrand<#new_lt, #id>));
520+
let rewritten_bounds = param.bounds.iter().cloned().map(|bound| {
521+
syn::fold::fold_type_param_bound(&mut ReplaceLt {
522+
orig_lt, new_lt: &new_lt
523+
}, bound)
524+
}).collect::<Vec<_>>();
525+
generics.make_where_clause().predicates.push(parse_quote!(#name::Branded: #(#rewritten_bounds)+*));
398526
}
527+
for ignored in &self.generics.ignored_lifetimes {
528+
generics.make_where_clause().predicates.push(parse_quote!(#ignored: 'new_gc));
529+
}
530+
let target_type = &self.ident;
531+
532+
let rewritten_path: Path = {
533+
let mut params = self.generics.original.params.iter().map(|decl| {
534+
// decl -> use
535+
match decl {
536+
GenericParam::Type(ref tp) => {
537+
let name = &tp.ident;
538+
parse_quote!(#name)
539+
}
540+
GenericParam::Lifetime(ref lt) => {
541+
let name = fold.rewrite_lifetime(lt.lifetime.clone());
542+
parse_quote!(#name)
543+
},
544+
GenericParam::Const(ref c) => {
545+
let name = &c.ident;
546+
parse_quote!(#name)
547+
}
548+
}
549+
}).collect::<Vec<GenericArgument>>();
550+
params = params.into_iter().map(|arg| {
551+
syn::fold::fold_generic_argument(&mut fold, arg)
552+
}).collect();
553+
554+
parse_quote!(#target_type::<#(#params),*>)
555+
};
556+
let explicitly_unsized = self.generics.original.params.iter()
557+
.filter_map(|param| match param {
558+
GenericParam::Type(ref t) => Some(t),
559+
_ => None
560+
})
561+
.filter(|&param| crate::is_explicitly_unsized(param))
562+
.map(|param| param.ident.clone())
563+
.collect::<HashSet<Ident>>();
564+
// Add the appropriate T::Branded: Sized bounds
565+
for param in self.generics.regular_type_params() {
566+
let name = &param.ident;
567+
if explicitly_unsized.contains(name) { continue }
568+
generics.make_where_clause().predicates.push(parse_quote!(#name::Branded: Sized));
569+
}
570+
let ty_generics = self.generics.original.split_for_impl().1;
571+
let (impl_generics, _, where_clause) = generics.split_for_impl();
572+
Ok(quote! {
573+
unsafe impl #impl_generics zerogc::GcRebrand<#new_lt, #id> for #target_type #ty_generics #where_clause {
574+
type Branded = #rewritten_path;
575+
}
576+
})
399577
}
400578
fn expand_trace(&self, kind: TraceDeriveKind, immutable: bool) -> Result<TokenStream, Error> {
401579
let target_type = &self.ident;
@@ -472,7 +650,7 @@ impl TraceDeriveInput {
472650
ActualId: zerogc::CollectorId, Self: zerogc::GcSafe<'actual_gc, ActualId> + 'actual_gc);
473651
Some(quote! {
474652
#[inline]
475-
unsafe fn visit_inside_gc<'actual_gc, Visitor, ActualId>(gc: &mut crate::Gc<'actual_gc, Self, ActualId>, visitor: &mut Visitor) -> Result<(), Visitor::Err>
653+
unsafe fn visit_inside_gc<'actual_gc, Visitor, ActualId>(gc: &mut zerogc::Gc<'actual_gc, Self, ActualId>, visitor: &mut Visitor) -> Result<(), Visitor::Err>
476654
#where_clause {
477655
visitor.visit_gc(gc)
478656
}
@@ -660,10 +838,12 @@ impl TraceDeriveInput {
660838
} else {
661839
None
662840
};
841+
let rebrand = self.expand_rebrand(kind)?;
663842
let trace = self.expand_trace(kind, false)?;
664843
let protective_drop = self.expand_trusted_drop(kind);
665844
let extra_methods = self.expand_extra_methods(kind)?;
666845
Ok(quote! {
846+
#rebrand
667847
#gcsafe
668848
#trace_immutable
669849
#trace
@@ -715,3 +895,53 @@ impl FieldAccess {
715895
}
716896
}
717897
}
898+
899+
struct ReplaceLt<'a> {
900+
orig_lt: &'a syn::Lifetime,
901+
new_lt: &'a syn::Lifetime
902+
}
903+
impl syn::fold::Fold for ReplaceLt<'_> {
904+
fn fold_lifetime(&mut self, orig: Lifetime) -> Lifetime {
905+
if orig == *self.orig_lt {
906+
self.new_lt.clone()
907+
} else {
908+
orig
909+
}
910+
}
911+
}
912+
struct RebrandFold<'a> {
913+
generics: &'a TraceGenerics,
914+
collector_ids: HashSet<Type>,
915+
new_lt: &'a syn::Lifetime,
916+
orig_lt: &'a syn::Lifetime,
917+
id: &'a syn::Path
918+
}
919+
impl RebrandFold<'_> {
920+
fn rewrite_lifetime(&self, orig: Lifetime) -> Lifetime {
921+
if orig == *self.orig_lt {
922+
self.new_lt.clone()
923+
} else {
924+
orig
925+
}
926+
}
927+
}
928+
impl<'a> syn::fold::Fold for RebrandFold<'a> {
929+
fn fold_lifetime_def(&mut self, orig: LifetimeDef) -> LifetimeDef {
930+
LifetimeDef {
931+
bounds: orig.bounds.into_iter().map(|lt| self.rewrite_lifetime(lt)).collect(),
932+
colon_token: orig.colon_token,
933+
lifetime: orig.lifetime,
934+
attrs: orig.attrs
935+
}
936+
}
937+
938+
fn fold_type(&mut self, orig: Type) -> Type {
939+
if self.generics.is_ignored(&orig) || self.collector_ids.contains(&orig) {
940+
orig
941+
} else {
942+
let new_lt = self.new_lt;
943+
let id = self.id;
944+
parse_quote!(<#orig as zerogc::GcRebrand<#new_lt, #id>>::Branded)
945+
}
946+
}
947+
}

0 commit comments

Comments
 (0)