@@ -332,6 +332,46 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
332
332
RefCell :: new ( f)
333
333
}
334
334
335
+ /// This method helps to extract all the type parameters referenced from a
336
+ /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
337
+ /// is not global and starts with `T`, or a `TyQPath`.
338
+ fn find_type_parameters ( ty : & ast:: Ty , ty_param_names : & [ ast:: Name ] ) -> Vec < P < ast:: Ty > > {
339
+ use visit;
340
+
341
+ struct Visitor < ' a > {
342
+ ty_param_names : & ' a [ ast:: Name ] ,
343
+ types : Vec < P < ast:: Ty > > ,
344
+ }
345
+
346
+ impl < ' a > visit:: Visitor < ' a > for Visitor < ' a > {
347
+ fn visit_ty ( & mut self , ty : & ' a ast:: Ty ) {
348
+ match ty. node {
349
+ ast:: TyPath ( _, ref path) if !path. global => {
350
+ match path. segments . first ( ) {
351
+ Some ( segment) => {
352
+ if self . ty_param_names . contains ( & segment. identifier . name ) {
353
+ self . types . push ( P ( ty. clone ( ) ) ) ;
354
+ }
355
+ }
356
+ None => { }
357
+ }
358
+ }
359
+ _ => { }
360
+ }
361
+
362
+ visit:: walk_ty ( self , ty)
363
+ }
364
+ }
365
+
366
+ let mut visitor = Visitor {
367
+ ty_param_names : ty_param_names,
368
+ types : Vec :: new ( ) ,
369
+ } ;
370
+
371
+ visit:: Visitor :: visit_ty ( & mut visitor, ty) ;
372
+
373
+ visitor. types
374
+ }
335
375
336
376
impl < ' a > TraitDef < ' a > {
337
377
pub fn expand < F > ( & self ,
@@ -374,18 +414,42 @@ impl<'a> TraitDef<'a> {
374
414
} ) )
375
415
}
376
416
377
- /// Given that we are deriving a trait `Tr` for a type `T<'a, ...,
378
- /// 'z, A, ..., Z>`, creates an impl like:
417
+ /// Given that we are deriving a trait `DerivedTrait` for a type like:
379
418
///
380
419
/// ```ignore
381
- /// impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
420
+ /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
421
+ /// a: A,
422
+ /// b: B::Item,
423
+ /// b1: <B as DeclaredTrait>::Item,
424
+ /// c1: <C as WhereTrait>::Item,
425
+ /// c2: Option<<C as WhereTrait>::Item>,
426
+ /// ...
427
+ /// }
428
+ /// ```
429
+ ///
430
+ /// create an impl like:
431
+ ///
432
+ /// ```ignore
433
+ /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
434
+ /// C: WhereTrait,
435
+ /// A: DerivedTrait + B1 + ... + BN,
436
+ /// B: DerivedTrait + B1 + ... + BN,
437
+ /// C: DerivedTrait + B1 + ... + BN,
438
+ /// B::Item: DerivedTrait + B1 + ... + BN,
439
+ /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
440
+ /// ...
441
+ /// {
442
+ /// ...
443
+ /// }
382
444
/// ```
383
445
///
384
- /// where B1, B2, ... are the bounds given by `bounds_paths`.'
446
+ /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
447
+ /// therefore does not get bound by the derived trait.
385
448
fn create_derived_impl ( & self ,
386
449
cx : & mut ExtCtxt ,
387
450
type_ident : Ident ,
388
451
generics : & Generics ,
452
+ field_tys : Vec < P < ast:: Ty > > ,
389
453
methods : Vec < P < ast:: ImplItem > > ) -> P < ast:: Item > {
390
454
let trait_path = self . path . to_path ( cx, self . span , type_ident, generics) ;
391
455
@@ -466,6 +530,35 @@ impl<'a> TraitDef<'a> {
466
530
}
467
531
} ) ) ;
468
532
533
+ if !ty_params. is_empty ( ) {
534
+ let ty_param_names: Vec < ast:: Name > = ty_params. iter ( )
535
+ . map ( |ty_param| ty_param. ident . name )
536
+ . collect ( ) ;
537
+
538
+ for field_ty in field_tys. into_iter ( ) {
539
+ let tys = find_type_parameters ( & * field_ty, & ty_param_names) ;
540
+
541
+ for ty in tys. into_iter ( ) {
542
+ let mut bounds: Vec < _ > = self . additional_bounds . iter ( ) . map ( |p| {
543
+ cx. typarambound ( p. to_path ( cx, self . span , type_ident, generics) )
544
+ } ) . collect ( ) ;
545
+
546
+ // require the current trait
547
+ bounds. push ( cx. typarambound ( trait_path. clone ( ) ) ) ;
548
+
549
+ let predicate = ast:: WhereBoundPredicate {
550
+ span : self . span ,
551
+ bound_lifetimes : vec ! [ ] ,
552
+ bounded_ty : ty,
553
+ bounds : OwnedSlice :: from_vec ( bounds) ,
554
+ } ;
555
+
556
+ let predicate = ast:: WherePredicate :: BoundPredicate ( predicate) ;
557
+ where_clause. predicates . push ( predicate) ;
558
+ }
559
+ }
560
+ }
561
+
469
562
let trait_generics = Generics {
470
563
lifetimes : lifetimes,
471
564
ty_params : OwnedSlice :: from_vec ( ty_params) ,
@@ -518,6 +611,10 @@ impl<'a> TraitDef<'a> {
518
611
struct_def : & StructDef ,
519
612
type_ident : Ident ,
520
613
generics : & Generics ) -> P < ast:: Item > {
614
+ let field_tys: Vec < P < ast:: Ty > > = struct_def. fields . iter ( )
615
+ . map ( |field| field. node . ty . clone ( ) )
616
+ . collect ( ) ;
617
+
521
618
let methods = self . methods . iter ( ) . map ( |method_def| {
522
619
let ( explicit_self, self_args, nonself_args, tys) =
523
620
method_def. split_self_nonself_args (
@@ -550,14 +647,29 @@ impl<'a> TraitDef<'a> {
550
647
body)
551
648
} ) . collect ( ) ;
552
649
553
- self . create_derived_impl ( cx, type_ident, generics, methods)
650
+ self . create_derived_impl ( cx, type_ident, generics, field_tys , methods)
554
651
}
555
652
556
653
fn expand_enum_def ( & self ,
557
654
cx : & mut ExtCtxt ,
558
655
enum_def : & EnumDef ,
559
656
type_ident : Ident ,
560
657
generics : & Generics ) -> P < ast:: Item > {
658
+ let mut field_tys = Vec :: new ( ) ;
659
+
660
+ for variant in enum_def. variants . iter ( ) {
661
+ match variant. node . kind {
662
+ ast:: VariantKind :: TupleVariantKind ( ref args) => {
663
+ field_tys. extend ( args. iter ( )
664
+ . map ( |arg| arg. ty . clone ( ) ) ) ;
665
+ }
666
+ ast:: VariantKind :: StructVariantKind ( ref args) => {
667
+ field_tys. extend ( args. fields . iter ( )
668
+ . map ( |field| field. node . ty . clone ( ) ) ) ;
669
+ }
670
+ }
671
+ }
672
+
561
673
let methods = self . methods . iter ( ) . map ( |method_def| {
562
674
let ( explicit_self, self_args, nonself_args, tys) =
563
675
method_def. split_self_nonself_args ( cx, self ,
@@ -590,7 +702,7 @@ impl<'a> TraitDef<'a> {
590
702
body)
591
703
} ) . collect ( ) ;
592
704
593
- self . create_derived_impl ( cx, type_ident, generics, methods)
705
+ self . create_derived_impl ( cx, type_ident, generics, field_tys , methods)
594
706
}
595
707
}
596
708
0 commit comments