@@ -600,6 +600,7 @@ pub(crate) fn add_method_to_adt(
600
600
pub ( crate ) struct ReferenceConversion {
601
601
conversion : ReferenceConversionType ,
602
602
ty : hir:: Type ,
603
+ impls_deref : bool ,
603
604
}
604
605
605
606
#[ derive( Debug ) ]
@@ -656,7 +657,13 @@ impl ReferenceConversion {
656
657
| ReferenceConversionType :: AsRefSlice
657
658
| ReferenceConversionType :: Dereferenced
658
659
| 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
+ }
660
667
}
661
668
}
662
669
}
@@ -675,54 +682,64 @@ pub(crate) fn convert_reference_type(
675
682
. or_else ( || handle_dereferenced ( & ty, db, famous_defs) )
676
683
. or_else ( || handle_option_as_ref ( & ty, db, famous_defs) )
677
684
. 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)
679
692
}
680
693
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 ) )
683
696
}
684
697
685
698
fn handle_as_ref_str (
686
699
ty : & hir:: Type ,
687
700
db : & dyn HirDatabase ,
688
701
famous_defs : & FamousDefs < ' _ , ' _ > ,
689
- ) -> Option < ReferenceConversionType > {
702
+ ) -> Option < ( ReferenceConversionType , bool ) > {
690
703
let str_type = hir:: BuiltinType :: str ( ) . ty ( db) ;
691
704
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 ) ) )
694
707
}
695
708
696
709
fn handle_as_ref_slice (
697
710
ty : & hir:: Type ,
698
711
db : & dyn HirDatabase ,
699
712
famous_defs : & FamousDefs < ' _ , ' _ > ,
700
- ) -> Option < ReferenceConversionType > {
713
+ ) -> Option < ( ReferenceConversionType , bool ) > {
701
714
let type_argument = ty. type_arguments ( ) . next ( ) ?;
702
715
let slice_type = hir:: Type :: new_slice ( type_argument) ;
703
716
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
+ ) )
706
721
}
707
722
708
723
fn handle_dereferenced (
709
724
ty : & hir:: Type ,
710
725
db : & dyn HirDatabase ,
711
726
famous_defs : & FamousDefs < ' _ , ' _ > ,
712
- ) -> Option < ReferenceConversionType > {
727
+ ) -> Option < ( ReferenceConversionType , bool ) > {
713
728
let type_argument = ty. type_arguments ( ) . next ( ) ?;
714
729
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
+ ) )
717
734
}
718
735
719
736
fn handle_option_as_ref (
720
737
ty : & hir:: Type ,
721
738
db : & dyn HirDatabase ,
722
739
famous_defs : & FamousDefs < ' _ , ' _ > ,
723
- ) -> Option < ReferenceConversionType > {
740
+ ) -> Option < ( ReferenceConversionType , bool ) > {
724
741
if ty. as_adt ( ) == famous_defs. core_option_Option ( ) ?. ty ( db) . as_adt ( ) {
725
- Some ( ReferenceConversionType :: Option )
742
+ Some ( ( ReferenceConversionType :: Option , false ) )
726
743
} else {
727
744
None
728
745
}
@@ -732,9 +749,9 @@ fn handle_result_as_ref(
732
749
ty : & hir:: Type ,
733
750
db : & dyn HirDatabase ,
734
751
famous_defs : & FamousDefs < ' _ , ' _ > ,
735
- ) -> Option < ReferenceConversionType > {
752
+ ) -> Option < ( ReferenceConversionType , bool ) > {
736
753
if ty. as_adt ( ) == famous_defs. core_result_Result ( ) ?. ty ( db) . as_adt ( ) {
737
- Some ( ReferenceConversionType :: Result )
754
+ Some ( ( ReferenceConversionType :: Result , false ) )
738
755
} else {
739
756
None
740
757
}
0 commit comments