@@ -5,7 +5,6 @@ use std::ops;
5
5
pub ( crate ) use gen_trait_fn_body:: gen_trait_fn_body;
6
6
use hir:: { db:: HirDatabase , HirDisplay , Semantics } ;
7
7
use ide_db:: { famous_defs:: FamousDefs , path_transform:: PathTransform , RootDatabase , SnippetCap } ;
8
- use itertools:: Itertools ;
9
8
use stdx:: format_to;
10
9
use syntax:: {
11
10
ast:: {
@@ -435,52 +434,67 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
435
434
Some ( end)
436
435
}
437
436
438
- // Generates the surrounding `impl Type { <code> }` including type and lifetime
439
- // parameters
437
+ /// Generates the surrounding `impl Type { <code> }` including type and lifetime
438
+ /// parameters.
440
439
pub ( crate ) fn generate_impl_text ( adt : & ast:: Adt , code : & str ) -> String {
441
- generate_impl_text_inner ( adt, None , code)
440
+ generate_impl_text_inner ( adt, None , true , code)
442
441
}
443
442
444
- // Generates the surrounding `impl <trait> for Type { <code> }` including type
445
- // and lifetime parameters
443
+ /// Generates the surrounding `impl <trait> for Type { <code> }` including type
444
+ /// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
445
+ ///
446
+ /// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
446
447
pub ( crate ) fn generate_trait_impl_text ( adt : & ast:: Adt , trait_text : & str , code : & str ) -> String {
447
- generate_impl_text_inner ( adt, Some ( trait_text) , code)
448
+ generate_impl_text_inner ( adt, Some ( trait_text) , true , code)
449
+ }
450
+
451
+ /// Generates the surrounding `impl <trait> for Type { <code> }` including type
452
+ /// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
453
+ ///
454
+ /// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
455
+ pub ( crate ) fn generate_trait_impl_text_intransitive (
456
+ adt : & ast:: Adt ,
457
+ trait_text : & str ,
458
+ code : & str ,
459
+ ) -> String {
460
+ generate_impl_text_inner ( adt, Some ( trait_text) , false , code)
448
461
}
449
462
450
- fn generate_impl_text_inner ( adt : & ast:: Adt , trait_text : Option < & str > , code : & str ) -> String {
463
+ fn generate_impl_text_inner (
464
+ adt : & ast:: Adt ,
465
+ trait_text : Option < & str > ,
466
+ trait_is_transitive : bool ,
467
+ code : & str ,
468
+ ) -> String {
451
469
// Ensure lifetime params are before type & const params
452
470
let generic_params = adt. generic_param_list ( ) . map ( |generic_params| {
453
471
let lifetime_params =
454
472
generic_params. lifetime_params ( ) . map ( ast:: GenericParam :: LifetimeParam ) ;
455
- let ty_or_const_params = generic_params. type_or_const_params ( ) . filter_map ( |param| {
473
+ let ty_or_const_params = generic_params. type_or_const_params ( ) . map ( |param| {
456
474
match param {
457
475
ast:: TypeOrConstParam :: Type ( param) => {
458
476
let param = param. clone_for_update ( ) ;
459
477
// remove defaults since they can't be specified in impls
460
478
param. remove_default ( ) ;
461
- let mut bounds = param
462
- . type_bound_list ( )
463
- . map_or_else ( Vec :: new, |it| it. bounds ( ) . collect_vec ( ) ) ;
464
- // `{ty_param}: {trait_text}`
479
+ let mut bounds =
480
+ param. type_bound_list ( ) . map_or_else ( Vec :: new, |it| it. bounds ( ) . collect ( ) ) ;
465
481
if let Some ( trait_) = trait_text {
466
- // Defense against the following cases:
467
- // - The trait is undetermined, e.g. `$0`.
468
- // - The trait is a `From`, e.g. `From<T>`.
469
- if !trait_. starts_with ( '$' )
470
- && !matches ! ( trait_. split_once( '<' ) , Some ( ( left, _right) ) if left. trim( ) == "From" )
471
- {
482
+ // Add the current trait to `bounds` if the trait is transitive,
483
+ // meaning `impl<T> Trait for U<T>` requires `T: Trait`.
484
+ if trait_is_transitive {
472
485
bounds. push ( make:: type_bound ( trait_) ) ;
473
486
}
474
487
} ;
488
+ // `{ty_param}: {bounds}`
475
489
let param =
476
490
make:: type_param ( param. name ( ) . unwrap ( ) , make:: type_bound_list ( bounds) ) ;
477
- Some ( ast:: GenericParam :: TypeParam ( param) )
491
+ ast:: GenericParam :: TypeParam ( param)
478
492
}
479
493
ast:: TypeOrConstParam :: Const ( param) => {
480
494
let param = param. clone_for_update ( ) ;
481
495
// remove defaults since they can't be specified in impls
482
496
param. remove_default ( ) ;
483
- Some ( ast:: GenericParam :: ConstParam ( param) )
497
+ ast:: GenericParam :: ConstParam ( param)
484
498
}
485
499
}
486
500
} ) ;
0 commit comments