1
1
use darling:: { Error , FromMeta , FromGenerics , FromTypeParam , FromDeriveInput , FromVariant , FromField } ;
2
2
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 } ;
4
4
use darling:: util:: { SpannedValue } ;
5
5
use quote:: { quote_spanned, quote, format_ident, ToTokens } ;
6
6
use darling:: ast:: { Style , Data } ;
@@ -15,6 +15,37 @@ pub enum TraceDeriveKind {
15
15
Regular
16
16
}
17
17
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
+
18
49
#[ derive( Debug ) ]
19
50
struct TraceGenerics {
20
51
original : Generics ,
@@ -23,6 +54,9 @@ struct TraceGenerics {
23
54
type_params : Vec < TraceTypeParam >
24
55
}
25
56
impl TraceGenerics {
57
+ fn is_ignored < P : PossiblyIgnoredParam > ( & self , item : & P ) -> bool {
58
+ item. check_ignored ( self )
59
+ }
26
60
/// Return all the "regular" type parameters,
27
61
/// excluding `Id` parameters and those marked `#[zerogc(ignore)]`
28
62
fn regular_type_params ( & self ) -> impl Iterator < Item =& ' _ TraceTypeParam > + ' _ {
@@ -370,32 +404,176 @@ impl TraceDeriveInput {
370
404
)
371
405
}
372
406
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)
385
411
}
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 ;
386
469
}
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
+ )
397
491
}
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) +* ) ) ;
398
526
}
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
+ } )
399
577
}
400
578
fn expand_trace ( & self , kind : TraceDeriveKind , immutable : bool ) -> Result < TokenStream , Error > {
401
579
let target_type = & self . ident ;
@@ -472,7 +650,7 @@ impl TraceDeriveInput {
472
650
ActualId : zerogc:: CollectorId , Self : zerogc:: GcSafe <' actual_gc, ActualId > + ' actual_gc) ;
473
651
Some ( quote ! {
474
652
#[ 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 >
476
654
#where_clause {
477
655
visitor. visit_gc( gc)
478
656
}
@@ -660,10 +838,12 @@ impl TraceDeriveInput {
660
838
} else {
661
839
None
662
840
} ;
841
+ let rebrand = self . expand_rebrand ( kind) ?;
663
842
let trace = self . expand_trace ( kind, false ) ?;
664
843
let protective_drop = self . expand_trusted_drop ( kind) ;
665
844
let extra_methods = self . expand_extra_methods ( kind) ?;
666
845
Ok ( quote ! {
846
+ #rebrand
667
847
#gcsafe
668
848
#trace_immutable
669
849
#trace
@@ -715,3 +895,53 @@ impl FieldAccess {
715
895
}
716
896
}
717
897
}
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