@@ -956,6 +956,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
956
956
diag. span_label ( span, message) ;
957
957
}
958
958
}
959
+ self . suggest_as_ref_where_appropriate ( span, & exp_found, diag) ;
959
960
}
960
961
961
962
diag. note_expected_found ( & "type" , expected, found) ;
@@ -972,6 +973,79 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
972
973
self . note_error_origin ( diag, & cause) ;
973
974
}
974
975
976
+ /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
977
+ /// suggest it.
978
+ fn suggest_as_ref_where_appropriate (
979
+ & self ,
980
+ span : Span ,
981
+ exp_found : & ty:: error:: ExpectedFound < Ty < ' tcx > > ,
982
+ diag : & mut DiagnosticBuilder < ' tcx > ,
983
+ ) {
984
+ match ( & exp_found. expected . sty , & exp_found. found . sty ) {
985
+ ( TyKind :: Adt ( exp_def, exp_substs) , TyKind :: Ref ( _, found_ty, _) ) => {
986
+ if let TyKind :: Adt ( found_def, found_substs) = found_ty. sty {
987
+ let path_str = format ! ( "{:?}" , exp_def) ;
988
+ if exp_def == & found_def {
989
+ let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \
990
+ `.as_ref()`";
991
+ let result_msg = "you can convert from `&Result<T, E>` to \
992
+ `Result<&T, &E>` using `.as_ref()`";
993
+ let have_as_ref = & [
994
+ ( "std::option::Option" , opt_msg) ,
995
+ ( "core::option::Option" , opt_msg) ,
996
+ ( "std::result::Result" , result_msg) ,
997
+ ( "core::result::Result" , result_msg) ,
998
+ ] ;
999
+ if let Some ( msg) = have_as_ref. iter ( )
1000
+ . filter_map ( |( path, msg) | if & path_str == path {
1001
+ Some ( msg)
1002
+ } else {
1003
+ None
1004
+ } ) . next ( )
1005
+ {
1006
+ let mut show_suggestion = true ;
1007
+ for ( exp_ty, found_ty) in exp_substs. types ( ) . zip ( found_substs. types ( ) ) {
1008
+ if let TyKind :: Ref ( _, exp_ty, _) = exp_ty. sty {
1009
+ match ( & exp_ty. sty , & found_ty. sty ) {
1010
+ ( TyKind :: Adt ( exp_did, _) , TyKind :: Adt ( found_did, _) )
1011
+ if exp_did == found_did => { }
1012
+ ( TyKind :: Bool , TyKind :: Bool ) |
1013
+ ( TyKind :: Char , TyKind :: Char ) |
1014
+ ( TyKind :: Str , TyKind :: Str ) |
1015
+ ( _, TyKind :: Param ( _) ) |
1016
+ ( _, TyKind :: Infer ( _) ) |
1017
+ ( TyKind :: Param ( _) , _) |
1018
+ ( TyKind :: Infer ( _) , _) => { }
1019
+ ( TyKind :: Int ( x) , TyKind :: Int ( y) ) if x == y => { }
1020
+ ( TyKind :: Uint ( x) , TyKind :: Uint ( y) ) if x == y => { }
1021
+ ( TyKind :: Int ( x) , TyKind :: Int ( y) ) if x == y => { }
1022
+ ( TyKind :: Uint ( x) , TyKind :: Uint ( y) ) if x == y => { }
1023
+ ( TyKind :: Float ( x) , TyKind :: Float ( y) ) if x == y => { }
1024
+ _ => show_suggestion = false ,
1025
+ }
1026
+ } else {
1027
+ show_suggestion = false ;
1028
+ }
1029
+ }
1030
+ if let ( Ok ( snippet) , true ) = (
1031
+ self . tcx . sess . source_map ( ) . span_to_snippet ( span) ,
1032
+ show_suggestion,
1033
+ ) {
1034
+ diag. span_suggestion_with_applicability (
1035
+ span,
1036
+ msg,
1037
+ format ! ( "{}.as_ref()" , snippet) ,
1038
+ Applicability :: MachineApplicable ,
1039
+ ) ;
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+ _ => { }
1046
+ }
1047
+ }
1048
+
975
1049
pub fn report_and_explain_type_error (
976
1050
& self ,
977
1051
trace : TypeTrace < ' tcx > ,
0 commit comments