22
33use std:: ops;
44
5- use itertools:: Itertools ;
6-
75pub ( crate ) use gen_trait_fn_body:: gen_trait_fn_body;
86use hir:: { db:: HirDatabase , HirDisplay , Semantics } ;
97use ide_db:: { famous_defs:: FamousDefs , path_transform:: PathTransform , RootDatabase , SnippetCap } ;
@@ -15,7 +13,7 @@ use syntax::{
1513 edit_in_place:: { AttrsOwnerEdit , Removable } ,
1614 make, HasArgList , HasAttrs , HasGenericParams , HasName , HasTypeBounds , Whitespace ,
1715 } ,
18- ted, AstNode , AstToken , Direction , SmolStr , SourceFile ,
16+ ted, AstNode , AstToken , Direction , SourceFile ,
1917 SyntaxKind :: * ,
2018 SyntaxNode , TextRange , TextSize , T ,
2119} ;
@@ -424,34 +422,44 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
424422}
425423
426424fn generate_impl_text_inner ( adt : & ast:: Adt , trait_text : Option < & str > , code : & str ) -> String {
427- let generic_params = adt. generic_param_list ( ) ;
425+ // Ensure lifetime params are before type & const params
426+ let generic_params = adt. generic_param_list ( ) . map ( |generic_params| {
427+ let lifetime_params =
428+ generic_params. lifetime_params ( ) . map ( ast:: GenericParam :: LifetimeParam ) ;
429+ let ty_or_const_params = generic_params. type_or_const_params ( ) . filter_map ( |param| {
430+ // remove defaults since they can't be specified in impls
431+ match param {
432+ ast:: TypeOrConstParam :: Type ( param) => {
433+ let param = param. clone_for_update ( ) ;
434+ param. remove_default ( ) ;
435+ Some ( ast:: GenericParam :: TypeParam ( param) )
436+ }
437+ ast:: TypeOrConstParam :: Const ( param) => {
438+ let param = param. clone_for_update ( ) ;
439+ param. remove_default ( ) ;
440+ Some ( ast:: GenericParam :: ConstParam ( param) )
441+ }
442+ }
443+ } ) ;
444+
445+ make:: generic_param_list ( itertools:: chain ( lifetime_params, ty_or_const_params) )
446+ } ) ;
447+
448+ // FIXME: use syntax::make & mutable AST apis instead
449+ // `trait_text` and `code` can't be opaque blobs of text
428450 let mut buf = String :: with_capacity ( code. len ( ) ) ;
451+
452+ // Copy any cfg attrs from the original adt
429453 buf. push_str ( "\n \n " ) ;
430- adt. attrs ( )
431- . filter ( |attr| attr. as_simple_call ( ) . map ( |( name, _arg) | name == "cfg" ) . unwrap_or ( false ) )
432- . for_each ( |attr| buf. push_str ( format ! ( "{}\n " , attr) . as_str ( ) ) ) ;
454+ let cfg_attrs = adt
455+ . attrs ( )
456+ . filter ( |attr| attr. as_simple_call ( ) . map ( |( name, _arg) | name == "cfg" ) . unwrap_or ( false ) ) ;
457+ cfg_attrs. for_each ( |attr| buf. push_str ( & format ! ( "{attr}\n " ) ) ) ;
458+
459+ // `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
433460 buf. push_str ( "impl" ) ;
434461 if let Some ( generic_params) = & generic_params {
435- let lifetimes = generic_params. lifetime_params ( ) . map ( |lt| format ! ( "{}" , lt. syntax( ) ) ) ;
436- let toc_params = generic_params. type_or_const_params ( ) . map ( |toc_param| {
437- let type_param = match toc_param {
438- ast:: TypeOrConstParam :: Type ( x) => x,
439- ast:: TypeOrConstParam :: Const ( x) => return x. syntax ( ) . to_string ( ) ,
440- } ;
441- let mut buf = String :: new ( ) ;
442- if let Some ( it) = type_param. name ( ) {
443- format_to ! ( buf, "{}" , it. syntax( ) ) ;
444- }
445- if let Some ( it) = type_param. colon_token ( ) {
446- format_to ! ( buf, "{} " , it) ;
447- }
448- if let Some ( it) = type_param. type_bound_list ( ) {
449- format_to ! ( buf, "{}" , it. syntax( ) ) ;
450- }
451- buf
452- } ) ;
453- let generics = lifetimes. chain ( toc_params) . format ( ", " ) ;
454- format_to ! ( buf, "<{}>" , generics) ;
462+ format_to ! ( buf, "{generic_params}" ) ;
455463 }
456464 buf. push ( ' ' ) ;
457465 if let Some ( trait_text) = trait_text {
@@ -460,23 +468,15 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
460468 }
461469 buf. push_str ( & adt. name ( ) . unwrap ( ) . text ( ) ) ;
462470 if let Some ( generic_params) = generic_params {
463- let lifetime_params = generic_params
464- . lifetime_params ( )
465- . filter_map ( |it| it. lifetime ( ) )
466- . map ( |it| SmolStr :: from ( it. text ( ) ) ) ;
467- let toc_params = generic_params
468- . type_or_const_params ( )
469- . filter_map ( |it| it. name ( ) )
470- . map ( |it| SmolStr :: from ( it. text ( ) ) ) ;
471- format_to ! ( buf, "<{}>" , lifetime_params. chain( toc_params) . format( ", " ) )
471+ format_to ! ( buf, "{}" , generic_params. to_generic_args( ) ) ;
472472 }
473473
474474 match adt. where_clause ( ) {
475475 Some ( where_clause) => {
476- format_to ! ( buf, "\n {}\n {{\n {}\n }}" , where_clause , code ) ;
476+ format_to ! ( buf, "\n {where_clause }\n {{\n {code }\n }}" ) ;
477477 }
478478 None => {
479- format_to ! ( buf, " {{\n {}\n }}" , code ) ;
479+ format_to ! ( buf, " {{\n {code }\n }}" ) ;
480480 }
481481 }
482482
0 commit comments