@@ -16,13 +16,127 @@ pub(crate) fn gen_trait_fn_body(
1616 adt : & ast:: Adt ,
1717) -> Option < ( ) > {
1818 match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
19+ "Clone" => gen_clone_impl ( adt, func) ,
1920 "Debug" => gen_debug_impl ( adt, func) ,
2021 "Default" => gen_default_impl ( adt, func) ,
2122 "Hash" => gen_hash_impl ( adt, func) ,
2223 _ => None ,
2324 }
2425}
2526
27+ /// Generate a `Clone` impl based on the fields and members of the target type.
28+ fn gen_clone_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
29+ fn gen_clone_call ( target : ast:: Expr ) -> ast:: Expr {
30+ let method = make:: name_ref ( "clone" ) ;
31+ make:: expr_method_call ( target, method, make:: arg_list ( None ) )
32+ }
33+ let expr = match adt {
34+ // `Clone` cannot be derived for unions, so no default impl can be provided.
35+ ast:: Adt :: Union ( _) => return None ,
36+ ast:: Adt :: Enum ( enum_) => {
37+ let list = enum_. variant_list ( ) ?;
38+ let mut arms = vec ! [ ] ;
39+ for variant in list. variants ( ) {
40+ let name = variant. name ( ) ?;
41+ let left = make:: ext:: ident_path ( "Self" ) ;
42+ let right = make:: ext:: ident_path ( & format ! ( "{}" , name) ) ;
43+ let variant_name = make:: path_concat ( left, right) ;
44+
45+ match variant. field_list ( ) {
46+ // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
47+ Some ( ast:: FieldList :: RecordFieldList ( list) ) => {
48+ let mut pats = vec ! [ ] ;
49+ let mut fields = vec ! [ ] ;
50+ for field in list. fields ( ) {
51+ let field_name = field. name ( ) ?;
52+ let pat = make:: ident_pat ( false , false , field_name. clone ( ) ) ;
53+ pats. push ( pat. into ( ) ) ;
54+
55+ let path = make:: ext:: ident_path ( & field_name. to_string ( ) ) ;
56+ let method_call = gen_clone_call ( make:: expr_path ( path) ) ;
57+ let name_ref = make:: name_ref ( & field_name. to_string ( ) ) ;
58+ let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
59+ fields. push ( field) ;
60+ }
61+ let pat = make:: record_pat ( variant_name. clone ( ) , pats. into_iter ( ) ) ;
62+ let fields = make:: record_expr_field_list ( fields) ;
63+ let record_expr = make:: record_expr ( variant_name, fields) . into ( ) ;
64+ arms. push ( make:: match_arm ( Some ( pat. into ( ) ) , None , record_expr) ) ;
65+ }
66+
67+ // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
68+ Some ( ast:: FieldList :: TupleFieldList ( list) ) => {
69+ let mut pats = vec ! [ ] ;
70+ let mut fields = vec ! [ ] ;
71+ for ( i, _) in list. fields ( ) . enumerate ( ) {
72+ let field_name = format ! ( "arg{}" , i) ;
73+ let pat = make:: ident_pat ( false , false , make:: name ( & field_name) ) ;
74+ pats. push ( pat. into ( ) ) ;
75+
76+ let f_path = make:: expr_path ( make:: ext:: ident_path ( & field_name) ) ;
77+ fields. push ( gen_clone_call ( f_path) ) ;
78+ }
79+ let pat = make:: tuple_struct_pat ( variant_name. clone ( ) , pats. into_iter ( ) ) ;
80+ let struct_name = make:: expr_path ( variant_name) ;
81+ let tuple_expr = make:: expr_call ( struct_name, make:: arg_list ( fields) ) ;
82+ arms. push ( make:: match_arm ( Some ( pat. into ( ) ) , None , tuple_expr) ) ;
83+ }
84+
85+ // => match self { Self::Name => Self::Name }
86+ None => {
87+ let pattern = make:: path_pat ( variant_name. clone ( ) ) ;
88+ let variant_expr = make:: expr_path ( variant_name) ;
89+ arms. push ( make:: match_arm ( Some ( pattern. into ( ) ) , None , variant_expr) ) ;
90+ }
91+ }
92+ }
93+
94+ let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
95+ let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
96+ make:: expr_match ( match_target, list)
97+ }
98+ ast:: Adt :: Struct ( strukt) => {
99+ match strukt. field_list ( ) {
100+ // => Self { name: self.name.clone() }
101+ Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
102+ let mut fields = vec ! [ ] ;
103+ for field in field_list. fields ( ) {
104+ let base = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
105+ let target = make:: expr_field ( base, & field. name ( ) ?. to_string ( ) ) ;
106+ let method_call = gen_clone_call ( target) ;
107+ let name_ref = make:: name_ref ( & field. name ( ) ?. to_string ( ) ) ;
108+ let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
109+ fields. push ( field) ;
110+ }
111+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
112+ let fields = make:: record_expr_field_list ( fields) ;
113+ make:: record_expr ( struct_name, fields) . into ( )
114+ }
115+ // => Self(self.0.clone(), self.1.clone())
116+ Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
117+ let mut fields = vec ! [ ] ;
118+ for ( i, _) in field_list. fields ( ) . enumerate ( ) {
119+ let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
120+ let target = make:: expr_field ( f_path, & format ! ( "{}" , i) ) . into ( ) ;
121+ fields. push ( gen_clone_call ( target) ) ;
122+ }
123+ let struct_name = make:: expr_path ( make:: ext:: ident_path ( "Self" ) ) ;
124+ make:: expr_call ( struct_name, make:: arg_list ( fields) )
125+ }
126+ // => Self { }
127+ None => {
128+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
129+ let fields = make:: record_expr_field_list ( None ) ;
130+ make:: record_expr ( struct_name, fields) . into ( )
131+ }
132+ }
133+ }
134+ } ;
135+ let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
136+ ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
137+ Some ( ( ) )
138+ }
139+
26140/// Generate a `Debug` impl based on the fields and members of the target type.
27141fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
28142 let annotated_name = adt. name ( ) ?;
@@ -88,10 +202,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
88202 Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
89203 let method = make:: name_ref ( "debug_tuple" ) ;
90204 let mut expr = make:: expr_method_call ( target, method, args) ;
91- for ( idx , _) in field_list. fields ( ) . enumerate ( ) {
205+ for ( i , _) in field_list. fields ( ) . enumerate ( ) {
92206 let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
93207 let f_path = make:: expr_ref ( f_path, false ) ;
94- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , idx ) ) . into ( ) ;
208+ let f_path = make:: expr_field ( f_path, & format ! ( "{}" , i ) ) . into ( ) ;
95209 let method = make:: name_ref ( "field" ) ;
96210 expr = make:: expr_method_call ( expr, method, make:: arg_list ( Some ( f_path) ) ) ;
97211 }
@@ -182,7 +296,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
182296 make:: block_expr ( Some ( stmt) , None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
183297 }
184298 ast:: Adt :: Struct ( strukt) => match strukt. field_list ( ) {
185- // => self.<field>.hash(state);*
299+ // => self.<field>.hash(state);
186300 Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
187301 let mut stmts = vec ! [ ] ;
188302 for field in field_list. fields ( ) {
@@ -193,7 +307,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
193307 make:: block_expr ( stmts, None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
194308 }
195309
196- // => self.<field_index>.hash(state);*
310+ // => self.<field_index>.hash(state);
197311 Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
198312 let mut stmts = vec ! [ ] ;
199313 for ( i, _) in field_list. fields ( ) . enumerate ( ) {
0 commit comments