Add explanation for &mut self
method call when expecting -> Self
When a user tries to use a method as if it returned a new value of the same type as its receiver, we will emit a type error. Try to detect this and provide extra explanation that the method modifies the receiver in-place. This has confused people in the wild, like in https://users.rust-lang.org/t/newbie-why-the-commented-line-stops-the-snippet-from-compiling/47322
This commit is contained in:
parent
3df25ae186
commit
ac73474c7d
@ -35,6 +35,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
|
||||
self.suggest_missing_await(err, expr, expected, expr_ty);
|
||||
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
||||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
}
|
||||
|
||||
// Requires that the two types unify, and prints an error message if
|
||||
|
@ -5176,6 +5176,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn note_internal_mutation_in_method(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) {
|
||||
if found != self.tcx.types.unit {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
|
||||
if self
|
||||
.typeck_results
|
||||
.borrow()
|
||||
.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(),
|
||||
}
|
||||
),
|
||||
);
|
||||
sp.push_span_label(
|
||||
rcvr.span,
|
||||
"you probably want to use this value after calling the method...".to_string(),
|
||||
);
|
||||
err.span_note(
|
||||
sp,
|
||||
&format!("method `{}` modifies its receiver in-place", path_segment.ident),
|
||||
);
|
||||
err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
|
||||
}
|
||||
}
|
||||
|
||||
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
|
||||
fn suggest_calling_boxed_future_when_appropriate(
|
||||
&self,
|
||||
|
@ -0,0 +1,4 @@
|
||||
fn main() {}
|
||||
fn foo(mut s: String) -> String {
|
||||
s.push_str("asdf") //~ ERROR mismatched types
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/chain-method-call-mutation-in-place.rs:3:5
|
||||
|
|
||||
LL | fn foo(mut s: String) -> String {
|
||||
| ------ expected `std::string::String` because of return type
|
||||
LL | s.push_str("asdf")
|
||||
| ^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `()`
|
||||
|
|
||||
note: method `push_str` modifies its receiver in-place
|
||||
--> $DIR/chain-method-call-mutation-in-place.rs:3:7
|
||||
|
|
||||
LL | s.push_str("asdf")
|
||||
| - ^^^^^^^^ this call modifies `s` in-place
|
||||
| |
|
||||
| you probably want to use this value after calling the method...
|
||||
= note: ...instead of the `()` output of method `push_str`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user