Change:
&self, err: &mut Diagnostic, expr: &hir::Expr<'_>, <del> expected: Ty<'tcx>, </del> <ins> expected: Option<Ty<'tcx>>, </ins> found: Ty<'tcx>, ) { if found != self.tcx.types.unit { return; } <del> if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind { if self .typeck_results </del> <ins> let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind else { return; }; let rcvr_has_the_expected_type = self .typeck_results .borrow() .expr_ty_adjusted_opt(rcvr) .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs())) .unwrap_or(false); let prev_call_mutates_and_returns_unit = || { self.typeck_results </ins> .borrow() <del> .expr_ty_adjusted_opt(rcvr) .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) { return; } let mut sp = MultiSpan::from_span(path_segment.ident.span); sp.push_span_label( path_segment.ident.span, format!( "this call modifies {} in-place", match rcvr.kind { ExprKind::Path(QPath::Resolved( None, hir::Path { segments: [segment], .. }, )) => format!("`{}`", segment.ident), _ => "its receiver".to_string(), } ), ); </del> <ins> .type_dependent_def_id(expr.hir_id) .map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder()) .and_then(|sig| sig.inputs_and_output.split_last()) .map(|(output, inputs)| { output.is_unit() && inputs .get(0) .and_then(|self_ty| self_ty.ref_mutability()) .map_or(false, rustc_ast::Mutability::is_mut) }) .unwrap_or(false) }; if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) { return; } let mut sp = MultiSpan::from_span(path_segment.ident.span); sp.push_span_label( path_segment.ident.span, format!( "this call modifies {} in-place", match rcvr.kind { ExprKind::Path(QPath::Resolved( None, hir::Path { segments: [segment], .. }, )) => format!("`{}`", segment.ident), _ => "its receiver".to_string(), } ), ); let modifies_rcvr_note = format!("method `{}` modifies its receiver in-place", path_segment.ident); if rcvr_has_the_expected_type { </ins> sp.push_span_label( rcvr.span, "you probably want to use this value after calling the method...", ); <ins> err.span_note(sp, &modifies_rcvr_note); err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); } else if let ExprKind::MethodCall(..) = rcvr.kind { </ins> err.span_note( sp, <del> &format!("method `{}` modifies its receiver in-place", path_segment.ident), </del> <ins> modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.", </ins> ); <del> err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); </del> <ins> } else { err.span_note(sp, &modifies_rcvr_note); </ins> } }

Discussion:
In long method chains we might inadvertently call a method that is not meant to be chained. When this happens, the most likely error to occur is a type error involving . We should instead look if the rhs expression is a method chain and look at all the chained call's type to find where is introduced. Given Ideally the output would be closer to <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Hi, I'd like to try working on this :) claim