@@ -168,76 +168,92 @@ fn impl_def_from_trait(
168168 add_trait_assoc_items_to_impl ( sema, trait_items, trait_, impl_def, target_scope) ;
169169
170170 // 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+
177175 Some ( ( impl_def, first_assoc_item) )
178176}
179177
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+
180195/// 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 < ( ) > {
182197 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") }
184202 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+ }
203219
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) ;
207223
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 ( ( ) )
212228 }
229+
213230 ast:: Adt :: Struct ( strukt) => {
214231 let name = format ! ( "\" {}\" " , annotated_name) ;
215232 let args = make:: arg_list ( Some ( make:: expr_literal ( & name) . into ( ) ) ) ;
216233 let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) ) ;
217234
218235 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()
223240 Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
224- // => f.debug_struct("Name").field("foo", &self.foo).finish()
225241 let method = make:: name_ref ( "debug_struct" ) ;
226242 let mut expr = make:: expr_method_call ( target, method, args) ;
227243 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) ;
236251 }
237252 expr
238253 }
254+
255+ // => f.debug_tuple("Name").field(self.0).finish()
239256 Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
240- // => f.debug_tuple("Name").field(self.0).finish()
241257 let method = make:: name_ref ( "debug_tuple" ) ;
242258 let mut expr = make:: expr_method_call ( target, method, args) ;
243259 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) {
254270 let method = make:: name_ref ( "finish" ) ;
255271 let expr = make:: expr_method_call ( expr, method, make:: arg_list ( None ) ) ;
256272 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 ( ( ) )
258275 }
259276 }
260277}
0 commit comments