Rollup merge of #75613 - estebank:explain-mut-method, r=petrochenkov
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:
commit
48da6758e5
4 changed files with 70 additions and 0 deletions
|
@ -36,6 +36,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.suggest_missing_await(err, expr, expected, expr_ty);
|
self.suggest_missing_await(err, expr, expected, expr_ty);
|
||||||
self.suggest_missing_parentheses(err, expr);
|
self.suggest_missing_parentheses(err, expr);
|
||||||
self.note_need_for_fn_pointer(err, 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
|
// Requires that the two types unify, and prints an error message if
|
||||||
|
|
|
@ -5198,6 +5198,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`.
|
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
|
||||||
fn suggest_calling_boxed_future_when_appropriate(
|
fn suggest_calling_boxed_future_when_appropriate(
|
||||||
&self,
|
&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…
Reference in a new issue