2
2
3
3
use std:: ops;
4
4
5
- use itertools:: Itertools ;
6
-
7
5
pub ( crate ) use gen_trait_fn_body:: gen_trait_fn_body;
8
6
use hir:: { db:: HirDatabase , HirDisplay , Semantics } ;
9
7
use ide_db:: { famous_defs:: FamousDefs , path_transform:: PathTransform , RootDatabase , SnippetCap } ;
@@ -15,7 +13,7 @@ use syntax::{
15
13
edit_in_place:: { AttrsOwnerEdit , Removable } ,
16
14
make, HasArgList , HasAttrs , HasGenericParams , HasName , HasTypeBounds , Whitespace ,
17
15
} ,
18
- ted, AstNode , AstToken , Direction , SmolStr , SourceFile ,
16
+ ted, AstNode , AstToken , Direction , SourceFile ,
19
17
SyntaxKind :: * ,
20
18
SyntaxNode , TextRange , TextSize , T ,
21
19
} ;
@@ -424,34 +422,44 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
424
422
}
425
423
426
424
fn 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
428
450
let mut buf = String :: with_capacity ( code. len ( ) ) ;
451
+
452
+ // Copy any cfg attrs from the original adt
429
453
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()}`
433
460
buf. push_str ( "impl" ) ;
434
461
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}" ) ;
455
463
}
456
464
buf. push ( ' ' ) ;
457
465
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
460
468
}
461
469
buf. push_str ( & adt. name ( ) . unwrap ( ) . text ( ) ) ;
462
470
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( ) ) ;
472
472
}
473
473
474
474
match adt. where_clause ( ) {
475
475
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 }}" ) ;
477
477
}
478
478
None => {
479
- format_to ! ( buf, " {{\n {}\n }}" , code ) ;
479
+ format_to ! ( buf, " {{\n {code }\n }}" ) ;
480
480
}
481
481
}
482
482
0 commit comments