11//! This module contains functions to generate default trait impl function bodies where possible.
22
3+ use hir:: TraitRef ;
34use syntax:: {
45 ast:: { self , edit:: AstNodeEdit , make, AstNode , BinaryOp , CmpOp , HasName , LogicOp } ,
56 ted,
67} ;
78
89/// Generate custom trait bodies without default implementation where possible.
910///
11+ /// If `func` is defined within an existing impl block, pass [`TraitRef`]. Otherwise pass `None`.
12+ ///
1013/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
1114/// `None` means that generating a custom trait body failed, and the body will remain
1215/// as `todo!` instead.
1316pub ( crate ) fn gen_trait_fn_body (
1417 func : & ast:: Fn ,
1518 trait_path : & ast:: Path ,
1619 adt : & ast:: Adt ,
20+ trait_ref : Option < TraitRef > ,
1721) -> Option < ( ) > {
1822 match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
1923 "Clone" => gen_clone_impl ( adt, func) ,
2024 "Debug" => gen_debug_impl ( adt, func) ,
2125 "Default" => gen_default_impl ( adt, func) ,
2226 "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 ) ,
2529 _ => None ,
2630 }
2731}
@@ -395,7 +399,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
395399}
396400
397401/// 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 < ( ) > {
399403 stdx:: always!( func. name( ) . map_or( false , |name| name. text( ) == "eq" ) ) ;
400404 fn gen_eq_chain ( expr : Option < ast:: Expr > , cmp : ast:: Expr ) -> Option < ast:: Expr > {
401405 match expr {
@@ -423,8 +427,15 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
423427 ast:: Pat :: IdentPat ( make:: ident_pat ( false , false , make:: name ( field_name) ) )
424428 }
425429
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+ }
428439
429440 let body = match adt {
430441 // `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<()> {
568579 make:: block_expr ( None , expr) . indent ( ast:: edit:: IndentLevel ( 1 ) )
569580 }
570581
571- // No fields in the body means there's nothing to hash .
582+ // No fields in the body means there's nothing to compare .
572583 None => {
573584 let expr = make:: expr_literal ( "true" ) . into ( ) ;
574585 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<()> {
580591 Some ( ( ) )
581592}
582593
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 < ( ) > {
584595 stdx:: always!( func. name( ) . map_or( false , |name| name. text( ) == "partial_cmp" ) ) ;
585596 fn gen_partial_eq_match ( match_target : ast:: Expr ) -> Option < ast:: Stmt > {
586597 let mut arms = vec ! [ ] ;
@@ -605,8 +616,15 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
605616 make:: expr_method_call ( lhs, method, make:: arg_list ( Some ( rhs) ) )
606617 }
607618
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+ }
610628
611629 let body = match adt {
612630 // `PartialOrd` cannot be derived for unions, so no default impl can be provided.
0 commit comments