@@ -332,6 +332,46 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
332332 RefCell :: new ( f)
333333}
334334
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+ }
335375
336376impl < ' a > TraitDef < ' a > {
337377 pub fn expand < F > ( & self ,
@@ -374,18 +414,42 @@ impl<'a> TraitDef<'a> {
374414 } ) )
375415 }
376416
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:
379418 ///
380419 /// ```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+ /// }
382444 /// ```
383445 ///
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.
385448 fn create_derived_impl ( & self ,
386449 cx : & mut ExtCtxt ,
387450 type_ident : Ident ,
388451 generics : & Generics ,
452+ field_tys : Vec < P < ast:: Ty > > ,
389453 methods : Vec < P < ast:: ImplItem > > ) -> P < ast:: Item > {
390454 let trait_path = self . path . to_path ( cx, self . span , type_ident, generics) ;
391455
@@ -466,6 +530,35 @@ impl<'a> TraitDef<'a> {
466530 }
467531 } ) ) ;
468532
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+
469562 let trait_generics = Generics {
470563 lifetimes : lifetimes,
471564 ty_params : OwnedSlice :: from_vec ( ty_params) ,
@@ -518,6 +611,10 @@ impl<'a> TraitDef<'a> {
518611 struct_def : & StructDef ,
519612 type_ident : Ident ,
520613 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+
521618 let methods = self . methods . iter ( ) . map ( |method_def| {
522619 let ( explicit_self, self_args, nonself_args, tys) =
523620 method_def. split_self_nonself_args (
@@ -550,14 +647,29 @@ impl<'a> TraitDef<'a> {
550647 body)
551648 } ) . collect ( ) ;
552649
553- self . create_derived_impl ( cx, type_ident, generics, methods)
650+ self . create_derived_impl ( cx, type_ident, generics, field_tys , methods)
554651 }
555652
556653 fn expand_enum_def ( & self ,
557654 cx : & mut ExtCtxt ,
558655 enum_def : & EnumDef ,
559656 type_ident : Ident ,
560657 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+
561673 let methods = self . methods . iter ( ) . map ( |method_def| {
562674 let ( explicit_self, self_args, nonself_args, tys) =
563675 method_def. split_self_nonself_args ( cx, self ,
@@ -590,7 +702,7 @@ impl<'a> TraitDef<'a> {
590702 body)
591703 } ) . collect ( ) ;
592704
593- self . create_derived_impl ( cx, type_ident, generics, methods)
705+ self . create_derived_impl ( cx, type_ident, generics, field_tys , methods)
594706 }
595707}
596708
0 commit comments