@@ -955,44 +955,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
955
955
& self ,
956
956
err : & mut Diagnostic ,
957
957
expr : & hir:: Expr < ' _ > ,
958
- expected : Ty < ' tcx > ,
958
+ expected : Option < Ty < ' tcx > > ,
959
959
found : Ty < ' tcx > ,
960
960
) {
961
961
if found != self . tcx . types . unit {
962
962
return ;
963
963
}
964
- if let ExprKind :: MethodCall ( path_segment, rcvr, ..) = expr. kind {
965
- if self
966
- . typeck_results
964
+
965
+ let ExprKind :: MethodCall ( path_segment, rcvr, ..) = expr. kind else {
966
+ return ;
967
+ } ;
968
+
969
+ let rcvr_has_the_expected_type = self
970
+ . typeck_results
971
+ . borrow ( )
972
+ . expr_ty_adjusted_opt ( rcvr)
973
+ . and_then ( |ty| expected. map ( |expected_ty| expected_ty. peel_refs ( ) == ty. peel_refs ( ) ) )
974
+ . unwrap_or ( false ) ;
975
+
976
+ let prev_call_mutates_and_returns_unit = || {
977
+ self . typeck_results
967
978
. borrow ( )
968
- . expr_ty_adjusted_opt ( rcvr)
969
- . map_or ( true , |ty| expected. peel_refs ( ) != ty. peel_refs ( ) )
970
- {
971
- return ;
972
- }
973
- let mut sp = MultiSpan :: from_span ( path_segment. ident . span ) ;
974
- sp. push_span_label (
975
- path_segment. ident . span ,
976
- format ! (
977
- "this call modifies {} in-place" ,
978
- match rcvr. kind {
979
- ExprKind :: Path ( QPath :: Resolved (
980
- None ,
981
- hir:: Path { segments: [ segment] , .. } ,
982
- ) ) => format!( "`{}`" , segment. ident) ,
983
- _ => "its receiver" . to_string( ) ,
984
- }
985
- ) ,
986
- ) ;
979
+ . type_dependent_def_id ( expr. hir_id )
980
+ . map ( |def_id| self . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) )
981
+ . and_then ( |sig| sig. inputs_and_output . split_last ( ) )
982
+ . map ( |( output, inputs) | {
983
+ output. is_unit ( )
984
+ && inputs
985
+ . get ( 0 )
986
+ . and_then ( |self_ty| self_ty. ref_mutability ( ) )
987
+ . map_or ( false , rustc_ast:: Mutability :: is_mut)
988
+ } )
989
+ . unwrap_or ( false )
990
+ } ;
991
+
992
+ if !( rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit ( ) ) {
993
+ return ;
994
+ }
995
+
996
+ let mut sp = MultiSpan :: from_span ( path_segment. ident . span ) ;
997
+ sp. push_span_label (
998
+ path_segment. ident . span ,
999
+ format ! (
1000
+ "this call modifies {} in-place" ,
1001
+ match rcvr. kind {
1002
+ ExprKind :: Path ( QPath :: Resolved (
1003
+ None ,
1004
+ hir:: Path { segments: [ segment] , .. } ,
1005
+ ) ) => format!( "`{}`" , segment. ident) ,
1006
+ _ => "its receiver" . to_string( ) ,
1007
+ }
1008
+ ) ,
1009
+ ) ;
1010
+
1011
+ let modifies_rcvr_note =
1012
+ format ! ( "method `{}` modifies its receiver in-place" , path_segment. ident) ;
1013
+ if rcvr_has_the_expected_type {
987
1014
sp. push_span_label (
988
1015
rcvr. span ,
989
1016
"you probably want to use this value after calling the method..." ,
990
1017
) ;
1018
+ err. span_note ( sp, & modifies_rcvr_note) ;
1019
+ err. note ( & format ! ( "...instead of the `()` output of method `{}`" , path_segment. ident) ) ;
1020
+ } else if let ExprKind :: MethodCall ( ..) = rcvr. kind {
991
1021
err. span_note (
992
1022
sp,
993
- & format ! ( "method `{}` modifies its receiver in-place" , path_segment . ident ) ,
1023
+ modifies_rcvr_note . clone ( ) + ", it is not meant to be used in method chains." ,
994
1024
) ;
995
- err. note ( & format ! ( "...instead of the `()` output of method `{}`" , path_segment. ident) ) ;
1025
+ } else {
1026
+ err. span_note ( sp, & modifies_rcvr_note) ;
996
1027
}
997
1028
}
998
1029
0 commit comments