@@ -168,76 +168,92 @@ fn impl_def_from_trait(
168
168
add_trait_assoc_items_to_impl ( sema, trait_items, trait_, impl_def, target_scope) ;
169
169
170
170
// Generate a default `impl` function body for the derived trait.
171
- if let ast:: AssocItem :: Fn ( func) = & first_assoc_item {
172
- match trait_path. segment ( ) . unwrap ( ) . name_ref ( ) . unwrap ( ) . text ( ) . as_str ( ) {
173
- "Debug" => gen_debug_impl ( adt, func, annotated_name) ,
174
- _ => { }
175
- } ;
176
- }
171
+ if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item {
172
+ let _ = gen_default_impl ( func, trait_path, adt, annotated_name) ;
173
+ } ;
174
+
177
175
Some ( ( impl_def, first_assoc_item) )
178
176
}
179
177
178
+ /// Generate custom trait bodies where possible.
179
+ ///
180
+ /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
181
+ /// `None` means that generating a custom trait body failed, and the body will remain
182
+ /// as `todo!` instead.
183
+ fn gen_default_impl (
184
+ func : & ast:: Fn ,
185
+ trait_path : & ast:: Path ,
186
+ adt : & ast:: Adt ,
187
+ annotated_name : & ast:: Name ,
188
+ ) -> Option < ( ) > {
189
+ match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
190
+ "Debug" => gen_debug_impl ( adt, func, annotated_name) ,
191
+ _ => Some ( ( ) ) ,
192
+ }
193
+ }
194
+
180
195
/// Generate a `Debug` impl based on the fields and members of the target type.
181
- fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn , annotated_name : & ast:: Name ) {
196
+ fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn , annotated_name : & ast:: Name ) -> Option < ( ) > {
182
197
match adt {
183
- ast:: Adt :: Union ( _) => { } // `Debug` cannot be derived for unions, so no default impl can be provided.
198
+ // `Debug` cannot be derived for unions, so no default impl can be provided.
199
+ ast:: Adt :: Union ( _) => Some ( ( ) ) ,
200
+
201
+ // => match self { Self::Variant => write!(f, "Variant") }
184
202
ast:: Adt :: Enum ( enum_) => {
185
- // => match self { Self::Variant => write!(f, "Variant") }
186
- if let Some ( list) = enum_. variant_list ( ) {
187
- let mut arms = vec ! [ ] ;
188
- for variant in list. variants ( ) {
189
- let name = variant. name ( ) . unwrap ( ) ;
190
-
191
- let left = make:: ext:: ident_path ( "Self" ) ;
192
- let right = make:: ext:: ident_path ( & format ! ( "{}" , name) ) ;
193
- let variant_name = make:: path_pat ( make:: path_concat ( left, right) ) ;
194
-
195
- let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) . into ( ) ) ;
196
- let fmt_string = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
197
- let args = make:: arg_list ( vec ! [ target, fmt_string] ) ;
198
- let macro_name = make:: expr_path ( make:: ext:: ident_path ( "write" ) ) ;
199
- let macro_call = make:: expr_macro_call ( macro_name, args) ;
200
-
201
- arms. push ( make:: match_arm ( Some ( variant_name. into ( ) ) , None , macro_call. into ( ) ) ) ;
202
- }
203
+ let list = enum_. variant_list ( ) ?;
204
+ let mut arms = vec ! [ ] ;
205
+ for variant in list. variants ( ) {
206
+ let name = variant. name ( ) ?;
207
+ let left = make:: ext:: ident_path ( "Self" ) ;
208
+ let right = make:: ext:: ident_path ( & format ! ( "{}" , name) ) ;
209
+ let variant_name = make:: path_pat ( make:: path_concat ( left, right) ) ;
210
+
211
+ let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) . into ( ) ) ;
212
+ let fmt_string = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
213
+ let args = make:: arg_list ( vec ! [ target, fmt_string] ) ;
214
+ let macro_name = make:: expr_path ( make:: ext:: ident_path ( "write" ) ) ;
215
+ let macro_call = make:: expr_macro_call ( macro_name, args) ;
216
+
217
+ arms. push ( make:: match_arm ( Some ( variant_name. into ( ) ) , None , macro_call. into ( ) ) ) ;
218
+ }
203
219
204
- let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
205
- let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
206
- let match_expr = make:: expr_match ( match_target, list) ;
220
+ let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
221
+ let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
222
+ let match_expr = make:: expr_match ( match_target, list) ;
207
223
208
- let body = make:: block_expr ( None , Some ( match_expr) ) ;
209
- let body = body. indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
210
- ted:: replace ( func. body ( ) . unwrap ( ) . syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
211
- }
224
+ let body = make:: block_expr ( None , Some ( match_expr) ) ;
225
+ let body = body. indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
226
+ ted:: replace ( func. body ( ) ? . syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
227
+ Some ( ( ) )
212
228
}
229
+
213
230
ast:: Adt :: Struct ( strukt) => {
214
231
let name = format ! ( "\" {}\" " , annotated_name) ;
215
232
let args = make:: arg_list ( Some ( make:: expr_literal ( & name) . into ( ) ) ) ;
216
233
let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) ) ;
217
234
218
235
let expr = match strukt. field_list ( ) {
219
- None => {
220
- // => f.debug_struct("Name").finish()
221
- make :: expr_method_call ( target , make :: name_ref ( "debug_struct" ) , args )
222
- }
236
+ // => f.debug_struct("Name").finish()
237
+ None => make :: expr_method_call ( target , make :: name_ref ( "debug_struct" ) , args ) ,
238
+
239
+ // => f.debug_struct("Name").field("foo", &self.foo).finish()
223
240
Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
224
- // => f.debug_struct("Name").field("foo", &self.foo).finish()
225
241
let method = make:: name_ref ( "debug_struct" ) ;
226
242
let mut expr = make:: expr_method_call ( target, method, args) ;
227
243
for field in field_list. fields ( ) {
228
- if let Some ( name) = field. name ( ) {
229
- let f_name = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
230
- let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
231
- let f_path = make:: expr_ref ( f_path, false ) ;
232
- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , name) ) . into ( ) ;
233
- let args = make:: arg_list ( vec ! [ f_name, f_path] ) ;
234
- expr = make:: expr_method_call ( expr, make:: name_ref ( "field" ) , args) ;
235
- }
244
+ let name = field. name ( ) ?;
245
+ let f_name = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
246
+ let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
247
+ let f_path = make:: expr_ref ( f_path, false ) ;
248
+ let f_path = make:: expr_field ( f_path, & format ! ( "{}" , name) ) . into ( ) ;
249
+ let args = make:: arg_list ( vec ! [ f_name, f_path] ) ;
250
+ expr = make:: expr_method_call ( expr, make:: name_ref ( "field" ) , args) ;
236
251
}
237
252
expr
238
253
}
254
+
255
+ // => f.debug_tuple("Name").field(self.0).finish()
239
256
Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
240
- // => f.debug_tuple("Name").field(self.0).finish()
241
257
let method = make:: name_ref ( "debug_tuple" ) ;
242
258
let mut expr = make:: expr_method_call ( target, method, args) ;
243
259
for ( idx, _) in field_list. fields ( ) . enumerate ( ) {
@@ -254,7 +270,8 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn, annotated_name: &ast::Name) {
254
270
let method = make:: name_ref ( "finish" ) ;
255
271
let expr = make:: expr_method_call ( expr, method, make:: arg_list ( None ) ) ;
256
272
let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
257
- ted:: replace ( func. body ( ) . unwrap ( ) . syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
273
+ ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
274
+ Some ( ( ) )
258
275
}
259
276
}
260
277
}
0 commit comments