3
3
use std:: ops;
4
4
5
5
pub ( crate ) use gen_trait_fn_body:: gen_trait_fn_body;
6
- use hir:: { db:: HirDatabase , HasAttrs as HirHasAttrs , HirDisplay , InFile , Semantics } ;
6
+ use hir:: { db:: HirDatabase , known , HasAttrs as HirHasAttrs , HirDisplay , InFile , Semantics } ;
7
7
use ide_db:: {
8
8
famous_defs:: FamousDefs , path_transform:: PathTransform ,
9
9
syntax_helpers:: insert_whitespace_into_node:: insert_ws_into, RootDatabase , SnippetCap ,
@@ -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,88 @@ 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 impls_deref_for_target (
689
+ ty : & hir:: Type ,
690
+ target : hir:: Type ,
691
+ db : & dyn HirDatabase ,
692
+ famous_defs : & FamousDefs < ' _ , ' _ > ,
693
+ ) -> bool {
694
+ if let Some ( deref_trait) = famous_defs. core_ops_Deref ( ) {
695
+ if ty. impls_trait ( db, deref_trait, & [ ] ) {
696
+ let assoc_type_item = deref_trait. items ( db) . into_iter ( ) . find_map ( |item| match item {
697
+ hir:: AssocItem :: TypeAlias ( alias) if alias. name ( db) == known:: Target => Some ( alias) ,
698
+ _ => None ,
699
+ } ) ;
700
+ if let Some ( assoc_type_item) = assoc_type_item {
701
+ matches ! (
702
+ ty. normalize_trait_assoc_type( db, & [ ] , assoc_type_item) ,
703
+ Some ( ty) if ty. could_coerce_to( db, & target) ,
704
+ )
705
+ } else {
706
+ false
707
+ }
708
+ } else {
709
+ false
710
+ }
711
+ } else {
712
+ false
713
+ }
679
714
}
680
715
681
- fn handle_copy ( ty : & hir:: Type , db : & dyn HirDatabase ) -> Option < ReferenceConversionType > {
682
- ty. is_copy ( db) . then_some ( ReferenceConversionType :: Copy )
716
+ fn handle_copy ( ty : & hir:: Type , db : & dyn HirDatabase ) -> Option < ( ReferenceConversionType , bool ) > {
717
+ ty. is_copy ( db) . then_some ( ( ReferenceConversionType :: Copy , true ) )
683
718
}
684
719
685
720
fn handle_as_ref_str (
686
721
ty : & hir:: Type ,
687
722
db : & dyn HirDatabase ,
688
723
famous_defs : & FamousDefs < ' _ , ' _ > ,
689
- ) -> Option < ReferenceConversionType > {
724
+ ) -> Option < ( ReferenceConversionType , bool ) > {
690
725
let str_type = hir:: BuiltinType :: str ( ) . ty ( db) ;
691
726
692
- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ str_type] )
693
- . then_some ( ReferenceConversionType :: AsRefStr )
727
+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ str_type. clone ( ) ] ) . then_some ( (
728
+ ReferenceConversionType :: AsRefStr ,
729
+ impls_deref_for_target ( ty, str_type, db, famous_defs) ,
730
+ ) )
694
731
}
695
732
696
733
fn handle_as_ref_slice (
697
734
ty : & hir:: Type ,
698
735
db : & dyn HirDatabase ,
699
736
famous_defs : & FamousDefs < ' _ , ' _ > ,
700
- ) -> Option < ReferenceConversionType > {
737
+ ) -> Option < ( ReferenceConversionType , bool ) > {
701
738
let type_argument = ty. type_arguments ( ) . next ( ) ?;
702
739
let slice_type = hir:: Type :: new_slice ( type_argument) ;
703
740
704
- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ slice_type] )
705
- . then_some ( ReferenceConversionType :: AsRefSlice )
741
+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ slice_type. clone ( ) ] ) . then_some ( (
742
+ ReferenceConversionType :: AsRefSlice ,
743
+ impls_deref_for_target ( ty, slice_type, db, famous_defs) ,
744
+ ) )
706
745
}
707
746
708
747
fn handle_dereferenced (
709
748
ty : & hir:: Type ,
710
749
db : & dyn HirDatabase ,
711
750
famous_defs : & FamousDefs < ' _ , ' _ > ,
712
- ) -> Option < ReferenceConversionType > {
751
+ ) -> Option < ( ReferenceConversionType , bool ) > {
713
752
let type_argument = ty. type_arguments ( ) . next ( ) ?;
714
753
715
- ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ type_argument] )
716
- . then_some ( ReferenceConversionType :: Dereferenced )
754
+ ty. impls_trait ( db, famous_defs. core_convert_AsRef ( ) ?, & [ type_argument. clone ( ) ] ) . then_some ( (
755
+ ReferenceConversionType :: Dereferenced ,
756
+ impls_deref_for_target ( ty, type_argument, db, famous_defs) ,
757
+ ) )
717
758
}
718
759
719
760
fn handle_option_as_ref (
720
761
ty : & hir:: Type ,
721
762
db : & dyn HirDatabase ,
722
763
famous_defs : & FamousDefs < ' _ , ' _ > ,
723
- ) -> Option < ReferenceConversionType > {
764
+ ) -> Option < ( ReferenceConversionType , bool ) > {
724
765
if ty. as_adt ( ) == famous_defs. core_option_Option ( ) ?. ty ( db) . as_adt ( ) {
725
- Some ( ReferenceConversionType :: Option )
766
+ Some ( ( ReferenceConversionType :: Option , false ) )
726
767
} else {
727
768
None
728
769
}
@@ -732,9 +773,9 @@ fn handle_result_as_ref(
732
773
ty : & hir:: Type ,
733
774
db : & dyn HirDatabase ,
734
775
famous_defs : & FamousDefs < ' _ , ' _ > ,
735
- ) -> Option < ReferenceConversionType > {
776
+ ) -> Option < ( ReferenceConversionType , bool ) > {
736
777
if ty. as_adt ( ) == famous_defs. core_result_Result ( ) ?. ty ( db) . as_adt ( ) {
737
- Some ( ReferenceConversionType :: Result )
778
+ Some ( ( ReferenceConversionType :: Result , false ) )
738
779
} else {
739
780
None
740
781
}
0 commit comments