1
1
//! This module contains functions to generate default trait impl function bodies where possible.
2
2
3
+ use hir:: TraitRef ;
3
4
use syntax:: {
4
5
ast:: { self , edit:: AstNodeEdit , make, AstNode , BinaryOp , CmpOp , HasName , LogicOp } ,
5
6
ted,
6
7
} ;
7
8
8
9
/// Generate custom trait bodies without default implementation where possible.
9
10
///
11
+ /// If `func` is defined within an existing impl block, pass [`TraitRef`]. Otherwise pass `None`.
12
+ ///
10
13
/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
11
14
/// `None` means that generating a custom trait body failed, and the body will remain
12
15
/// as `todo!` instead.
13
16
pub ( crate ) fn gen_trait_fn_body (
14
17
func : & ast:: Fn ,
15
18
trait_path : & ast:: Path ,
16
19
adt : & ast:: Adt ,
20
+ trait_ref : Option < TraitRef > ,
17
21
) -> Option < ( ) > {
18
22
match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
19
23
"Clone" => gen_clone_impl ( adt, func) ,
20
24
"Debug" => gen_debug_impl ( adt, func) ,
21
25
"Default" => gen_default_impl ( adt, func) ,
22
26
"Hash" => gen_hash_impl ( adt, func) ,
23
- "PartialEq" => gen_partial_eq ( adt, func) ,
24
- "PartialOrd" => gen_partial_ord ( adt, func) ,
27
+ "PartialEq" => gen_partial_eq ( adt, func, trait_ref ) ,
28
+ "PartialOrd" => gen_partial_ord ( adt, func, trait_ref ) ,
25
29
_ => None ,
26
30
}
27
31
}
@@ -395,7 +399,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
395
399
}
396
400
397
401
/// Generate a `PartialEq` impl based on the fields and members of the target type.
398
- fn gen_partial_eq ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
402
+ fn gen_partial_eq ( adt : & ast:: Adt , func : & ast:: Fn , trait_ref : Option < TraitRef > ) -> Option < ( ) > {
399
403
stdx:: always!( func. name( ) . map_or( false , |name| name. text( ) == "eq" ) ) ;
400
404
fn gen_eq_chain ( expr : Option < ast:: Expr > , cmp : ast:: Expr ) -> Option < ast:: Expr > {
401
405
match expr {
@@ -423,8 +427,15 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
423
427
ast:: Pat :: IdentPat ( make:: ident_pat ( false , false , make:: name ( field_name) ) )
424
428
}
425
429
426
- // FIXME: return `None` if the trait carries a generic type; we can only
427
- // generate this code `Self` for the time being.
430
+ // Check that self type and rhs type match. We don't know how to implement the method
431
+ // automatically otherwise.
432
+ if let Some ( trait_ref) = trait_ref {
433
+ let self_ty = trait_ref. self_ty ( ) ;
434
+ let rhs_ty = trait_ref. get_type_argument ( 1 ) ?;
435
+ if self_ty != rhs_ty {
436
+ return None ;
437
+ }
438
+ }
428
439
429
440
let body = match adt {
430
441
// `PartialEq` cannot be derived for unions, so no default impl can be provided.
@@ -568,7 +579,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
568
579
make:: block_expr ( None , expr) . indent ( ast:: edit:: IndentLevel ( 1 ) )
569
580
}
570
581
571
- // No fields in the body means there's nothing to hash .
582
+ // No fields in the body means there's nothing to compare .
572
583
None => {
573
584
let expr = make:: expr_literal ( "true" ) . into ( ) ;
574
585
make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
@@ -580,7 +591,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
580
591
Some ( ( ) )
581
592
}
582
593
583
- fn gen_partial_ord ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
594
+ fn gen_partial_ord ( adt : & ast:: Adt , func : & ast:: Fn , trait_ref : Option < TraitRef > ) -> Option < ( ) > {
584
595
stdx:: always!( func. name( ) . map_or( false , |name| name. text( ) == "partial_cmp" ) ) ;
585
596
fn gen_partial_eq_match ( match_target : ast:: Expr ) -> Option < ast:: Stmt > {
586
597
let mut arms = vec ! [ ] ;
@@ -605,8 +616,15 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
605
616
make:: expr_method_call ( lhs, method, make:: arg_list ( Some ( rhs) ) )
606
617
}
607
618
608
- // FIXME: return `None` if the trait carries a generic type; we can only
609
- // generate this code `Self` for the time being.
619
+ // Check that self type and rhs type match. We don't know how to implement the method
620
+ // automatically otherwise.
621
+ if let Some ( trait_ref) = trait_ref {
622
+ let self_ty = trait_ref. self_ty ( ) ;
623
+ let rhs_ty = trait_ref. get_type_argument ( 1 ) ?;
624
+ if self_ty != rhs_ty {
625
+ return None ;
626
+ }
627
+ }
610
628
611
629
let body = match adt {
612
630
// `PartialOrd` cannot be derived for unions, so no default impl can be provided.
0 commit comments