mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 11:33:04 +00:00
Auto merge of #84353 - estebank:as-ref-mir, r=davidtwco
Suggest `.as_ref()` on borrow error involving `Option`/`Result` When encountering a E0382 borrow error involving an `Option` or `Result` provide a suggestion to use `.as_ref()` on the prior move location to avoid the move. Fix #84165.
This commit is contained in:
commit
6df26f897c
@ -197,7 +197,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
|
||||
FnSelfUseKind::Normal {
|
||||
self_arg,
|
||||
implicit_into_iter,
|
||||
is_option_or_result,
|
||||
} => {
|
||||
if implicit_into_iter {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
@ -215,6 +219,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
),
|
||||
);
|
||||
}
|
||||
if is_option_or_result {
|
||||
err.span_suggestion_verbose(
|
||||
fn_call_span.shrink_to_lo(),
|
||||
"consider calling `.as_ref()` to borrow the type's contents",
|
||||
"as_ref().".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages.
|
||||
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
|
||||
|
@ -573,7 +573,13 @@ pub(super) enum UseSpans<'tcx> {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub(super) enum FnSelfUseKind<'tcx> {
|
||||
/// A normal method call of the form `receiver.foo(a, b, c)`
|
||||
Normal { self_arg: Ident, implicit_into_iter: bool },
|
||||
Normal {
|
||||
self_arg: Ident,
|
||||
implicit_into_iter: bool,
|
||||
/// Whether the self type of the method call has an `.as_ref()` method.
|
||||
/// Used for better diagnostics.
|
||||
is_option_or_result: bool,
|
||||
},
|
||||
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
|
||||
FnOnceCall,
|
||||
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
|
||||
@ -900,7 +906,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
fn_call_span.desugaring_kind(),
|
||||
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
|
||||
);
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
|
||||
let parent_self_ty = parent
|
||||
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, ..) => Some(def.did),
|
||||
_ => None,
|
||||
});
|
||||
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
|
||||
tcx.is_diagnostic_item(sym::option_type, def_id)
|
||||
|| tcx.is_diagnostic_item(sym::result_type, def_id)
|
||||
});
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
|
||||
});
|
||||
|
||||
return FnSelfUse {
|
||||
|
13
src/test/ui/suggestions/as-ref-2.fixed
Normal file
13
src/test/ui/suggestions/as-ref-2.fixed
Normal file
@ -0,0 +1,13 @@
|
||||
// run-rustfix
|
||||
|
||||
struct Struct;
|
||||
|
||||
fn bar(_: &Struct) -> Struct {
|
||||
Struct
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Some(Struct);
|
||||
let _x: Option<Struct> = foo.as_ref().map(|s| bar(&s));
|
||||
let _y = foo; //~ERROR use of moved value: `foo`
|
||||
}
|
13
src/test/ui/suggestions/as-ref-2.rs
Normal file
13
src/test/ui/suggestions/as-ref-2.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// run-rustfix
|
||||
|
||||
struct Struct;
|
||||
|
||||
fn bar(_: &Struct) -> Struct {
|
||||
Struct
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Some(Struct);
|
||||
let _x: Option<Struct> = foo.map(|s| bar(&s));
|
||||
let _y = foo; //~ERROR use of moved value: `foo`
|
||||
}
|
23
src/test/ui/suggestions/as-ref-2.stderr
Normal file
23
src/test/ui/suggestions/as-ref-2.stderr
Normal file
@ -0,0 +1,23 @@
|
||||
error[E0382]: use of moved value: `foo`
|
||||
--> $DIR/as-ref-2.rs:12:14
|
||||
|
|
||||
LL | let foo = Some(Struct);
|
||||
| --- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait
|
||||
LL | let _x: Option<Struct> = foo.map(|s| bar(&s));
|
||||
| ---------------- `foo` moved due to this method call
|
||||
LL | let _y = foo;
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
note: this function takes ownership of the receiver `self`, which moves `foo`
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
|
||||
LL | pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
|
||||
| ^^^^
|
||||
help: consider calling `.as_ref()` to borrow the type's contents
|
||||
|
|
||||
LL | let _x: Option<Struct> = foo.as_ref().map(|s| bar(&s));
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,25 +1,20 @@
|
||||
struct Foo;
|
||||
|
||||
fn takes_ref(_: &Foo) {}
|
||||
|
||||
fn main() {
|
||||
let ref opt = Some(Foo);
|
||||
opt.map(|arg| takes_ref(arg));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let ref opt: Result<_, ()> = Ok(Foo);
|
||||
opt.map(|arg| takes_ref(arg));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let x: &Option<usize> = &Some(3);
|
||||
let y: Option<&usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, &usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
// note: do not suggest because of `E: usize`
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
let ref opt = Some(Foo);
|
||||
opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
|
||||
opt.and_then(|arg| Some(takes_ref(arg))); //~ ERROR mismatched types [E0308]
|
||||
let ref opt: Result<_, ()> = Ok(Foo);
|
||||
opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
|
||||
opt.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308]
|
||||
let x: &Option<usize> = &Some(3);
|
||||
let y: Option<&usize> = x; //~ ERROR mismatched types [E0308]
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, &usize> = x;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
// note: do not suggest because of `E: usize`
|
||||
let x: &Result<usize, usize> = &Ok(3);
|
||||
let y: Result<&usize, usize> = x; //~ ERROR mismatched types [E0308]
|
||||
}
|
||||
|
@ -1,70 +1,70 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:6:27
|
||||
--> $DIR/as-ref.rs:7:29
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| --- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| --- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:8:37
|
||||
--> $DIR/as-ref.rs:8:39
|
||||
|
|
||||
LL | opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
| -------- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
LL | opt.and_then(|arg| Some(takes_ref(arg)));
|
||||
| -------- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:11:27
|
||||
--> $DIR/as-ref.rs:10:29
|
||||
|
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| --- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
LL | opt.map(|arg| takes_ref(arg));
|
||||
| --- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().map`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:13:35
|
||||
--> $DIR/as-ref.rs:11:37
|
||||
|
|
||||
LL | opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
| -------- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
LL | opt.and_then(|arg| Ok(takes_ref(arg)));
|
||||
| -------- ^^^ expected `&Foo`, found struct `Foo`
|
||||
| |
|
||||
| help: consider using `as_ref` instead: `as_ref().and_then`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:16:27
|
||||
--> $DIR/as-ref.rs:13:29
|
||||
|
|
||||
LL | let y: Option<&usize> = x;
|
||||
| -------------- ^
|
||||
| | |
|
||||
| | expected enum `Option`, found `&Option<usize>`
|
||||
| | help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `x.as_ref()`
|
||||
| expected due to this
|
||||
LL | let y: Option<&usize> = x;
|
||||
| -------------- ^
|
||||
| | |
|
||||
| | expected enum `Option`, found `&Option<usize>`
|
||||
| | help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `x.as_ref()`
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected enum `Option<&usize>`
|
||||
found reference `&Option<usize>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:19:35
|
||||
--> $DIR/as-ref.rs:15:37
|
||||
|
|
||||
LL | let y: Result<&usize, &usize> = x;
|
||||
| ---------------------- ^ expected enum `Result`, found reference
|
||||
| |
|
||||
| expected due to this
|
||||
LL | let y: Result<&usize, &usize> = x;
|
||||
| ---------------------- ^ expected enum `Result`, found reference
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected enum `Result<&usize, &usize>`
|
||||
found reference `&Result<usize, usize>`
|
||||
help: you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
|
||||
|
|
||||
LL | let y: Result<&usize, &usize> = x.as_ref();
|
||||
| ^^^^^^^^^^
|
||||
LL | let y: Result<&usize, &usize> = x.as_ref();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/as-ref.rs:23:34
|
||||
--> $DIR/as-ref.rs:19:36
|
||||
|
|
||||
LL | let y: Result<&usize, usize> = x;
|
||||
| --------------------- ^ expected enum `Result`, found reference
|
||||
| |
|
||||
| expected due to this
|
||||
LL | let y: Result<&usize, usize> = x;
|
||||
| --------------------- ^ expected enum `Result`, found reference
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected enum `Result<&usize, usize>`
|
||||
found reference `&Result<usize, usize>`
|
||||
|
Loading…
Reference in New Issue
Block a user