@@ -600,6 +600,7 @@ pub(crate) fn add_method_to_adt(
600600pub ( crate ) struct ReferenceConversion {
601601 conversion : ReferenceConversionType ,
602602 ty : hir:: Type ,
603+ impls_deref : bool ,
603604}
604605
605606#[ derive( Debug ) ]
@@ -656,7 +657,13 @@ impl ReferenceConversion {
656657 | ReferenceConversionType :: AsRefSlice
657658 | ReferenceConversionType :: Dereferenced
658659 | ReferenceConversionType :: Option
659- | ReferenceConversionType :: Result => format ! ( "self.{field_name}.as_ref()" ) ,
660+ | ReferenceConversionType :: Result => {
661+ if self . impls_deref {
662+ format ! ( "&self.{field_name}" )
663+ } else {
664+ format ! ( "self.{field_name}.as_ref()" )
665+ }
666+ }
660667 }
661668 }
662669}
@@ -675,54 +682,64 @@ pub(crate) fn convert_reference_type(
675682 . or_else ( || handle_dereferenced ( & ty, db, famous_defs) )
676683 . or_else ( || handle_option_as_ref ( & ty, db, famous_defs) )
677684 . or_else ( || handle_result_as_ref ( & ty, db, famous_defs) )
678- . map ( |conversion| ReferenceConversion { ty, conversion } )
685+ . map ( |( conversion, impls_deref) | ReferenceConversion { ty, conversion, impls_deref } )
686+ }
687+
688+ fn could_deref_to_target ( ty : & hir:: Type , target : & hir:: Type , db : & dyn HirDatabase ) -> bool {
689+ let ty_ref = hir:: Type :: reference ( ty, hir:: Mutability :: Shared ) ;
690+ let target_ref = hir:: Type :: reference ( target, hir:: Mutability :: Shared ) ;
691+ ty_ref. could_coerce_to ( db, & target_ref)
679692}
680693
681- fn handle_copy ( ty : & hir:: Type , db : & dyn HirDatabase ) -> Option < ReferenceConversionType > {
682- ty. is_copy ( db) . then_some ( ReferenceConversionType :: Copy )
694+ fn handle_copy ( ty : & hir:: Type , db : & dyn HirDatabase ) -> Option < ( ReferenceConversionType , bool ) > {
695+ ty. is_copy ( db) . then_some ( ( ReferenceConversionType :: Copy , true ) )
683696}
684697
685698fn handle_as_ref_str (
686699 ty : & hir:: Type ,
687700 db : & dyn HirDatabase ,
688701 famous_defs : & FamousDefs < ' _ , ' _ > ,
689- ) -> Option < ReferenceConversionType > {
702+ ) -> Option < ( ReferenceConversionType , bool ) > {
690703 let str_type = hir:: BuiltinType :: str ( ) . ty ( db) ;
691704
692- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ str_type] )
693- . then_some ( ReferenceConversionType :: AsRefStr )
705+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ str_type. clone ( ) ] )
706+ . then_some ( ( ReferenceConversionType :: AsRefStr , could_deref_to_target ( ty , & str_type , db ) ) )
694707}
695708
696709fn handle_as_ref_slice (
697710 ty : & hir:: Type ,
698711 db : & dyn HirDatabase ,
699712 famous_defs : & FamousDefs < ' _ , ' _ > ,
700- ) -> Option < ReferenceConversionType > {
713+ ) -> Option < ( ReferenceConversionType , bool ) > {
701714 let type_argument = ty. type_arguments ( ) . next ( ) ?;
702715 let slice_type = hir:: Type :: new_slice ( type_argument) ;
703716
704- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ slice_type] )
705- . then_some ( ReferenceConversionType :: AsRefSlice )
717+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ slice_type. clone ( ) ] ) . then_some ( (
718+ ReferenceConversionType :: AsRefSlice ,
719+ could_deref_to_target ( ty, & slice_type, db) ,
720+ ) )
706721}
707722
708723fn handle_dereferenced (
709724 ty : & hir:: Type ,
710725 db : & dyn HirDatabase ,
711726 famous_defs : & FamousDefs < ' _ , ' _ > ,
712- ) -> Option < ReferenceConversionType > {
727+ ) -> Option < ( ReferenceConversionType , bool ) > {
713728 let type_argument = ty. type_arguments ( ) . next ( ) ?;
714729
715- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ type_argument] )
716- . then_some ( ReferenceConversionType :: Dereferenced )
730+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ type_argument. clone ( ) ] ) . then_some ( (
731+ ReferenceConversionType :: Dereferenced ,
732+ could_deref_to_target ( ty, & type_argument, db) ,
733+ ) )
717734}
718735
719736fn handle_option_as_ref (
720737 ty : & hir:: Type ,
721738 db : & dyn HirDatabase ,
722739 famous_defs : & FamousDefs < ' _ , ' _ > ,
723- ) -> Option < ReferenceConversionType > {
740+ ) -> Option < ( ReferenceConversionType , bool ) > {
724741 if ty. as_adt ( ) == famous_defs. core_option_Option ( ) ?. ty ( db) . as_adt ( ) {
725- Some ( ReferenceConversionType :: Option )
742+ Some ( ( ReferenceConversionType :: Option , false ) )
726743 } else {
727744 None
728745 }
@@ -732,9 +749,9 @@ fn handle_result_as_ref(
732749 ty : & hir:: Type ,
733750 db : & dyn HirDatabase ,
734751 famous_defs : & FamousDefs < ' _ , ' _ > ,
735- ) -> Option < ReferenceConversionType > {
752+ ) -> Option < ( ReferenceConversionType , bool ) > {
736753 if ty. as_adt ( ) == famous_defs. core_result_Result ( ) ?. ty ( db) . as_adt ( ) {
737- Some ( ReferenceConversionType :: Result )
754+ Some ( ( ReferenceConversionType :: Result , false ) )
738755 } else {
739756 None
740757 }
0 commit comments