Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest borrowing when doing if let Some(_) from non-Copy ADT #63988

Closed
estebank opened this issue Aug 29, 2019 · 3 comments · Fixed by #73534
Closed

Suggest borrowing when doing if let Some(_) from non-Copy ADT #63988

estebank opened this issue Aug 29, 2019 · 3 comments · Fixed by #73534
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@estebank
Copy link
Contributor

Just got this error:

error[E0382]: borrow of moved value: `x`
    --> src/librustc_mir/hair/pattern/_match.rs:1614:53
     |
1611 |                         if let Some(range) = x {
     |                                     ----- value moved here
...
1614 |                         debug!("intersection {:?}", x);
     |                                                     ^ value borrowed here after partial move
     |
     = note: move occurs because value has type `hair::pattern::_match::IntRange<'_>`, which does not implement the `Copy` trait

error: aborting due to previous error

It should suggest to borrow x.

@estebank estebank added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` labels Aug 29, 2019
@ayazhafiz
Copy link
Contributor

@estebank can you elaborate on the message you expect to see here? Something like

error[E0382]: borrow of moved value: `x`
    --> src/librustc_mir/hair/pattern/_match.rs:1614:53
     |
1611 |                         if let Some(range) = x {
     |                                     ----- value moved here
...
1614 |                         debug!("intersection {:?}", x);
     |                                                     ^ value borrowed here after partial move
     |
     = note: move occurs because value has type `hair::pattern::_match::IntRange<'_>`, which does not implement the `Copy` trait
       Consider borrowing `x` rather than moving it.

perhaps?

@estebank
Copy link
Contributor Author

estebank commented Sep 3, 2019

@ayazhafiz I believe we should aim at:

error[E0382]: borrow of moved value: `x`
    --> src/librustc_mir/hair/pattern/_match.rs:1614:53
     |
1611 |                         if let Some(range) = x {
     |                                     -----    - help: consider borrowing here: `&x`
     |                                     |
     |                                     value moved here
...
1614 |                         debug!("intersection {:?}", x);
     |                                                     ^ value borrowed here after partial move
     |
     = note: move occurs because value has type `hair::pattern::_match::IntRange<'_>`, which does not implement the `Copy` trait

@ayazhafiz
Copy link
Contributor

I took a look at this today. I am a first-time contributor to this project and would like to contribute this enhancement, but I'm not sure how much work this will end up requiring. Here are some notes/leads I've noticed; I'm hoping someone may be able to provide suggestions, and at the very least I hope this is helpful for anyone else wishing to tackle this.

Consider the example provided in the first comment of this issue (abbreviated for example):

error[E0382]: borrow of moved value: `x`
    --> src/librustc_mir/hair/pattern/_match.rs:1614:53
     |
1611 |                         if let Some(range) = x {
     |                                     ----- value moved here
...
1614 |                         debug!("intersection {:?}", x);
     |                                                     ^ value borrowed here after partial move

This error message is generated by MirBorrowckCtxt#report_use_of_moved_or_uninitialized:

pub(super) fn report_use_of_moved_or_uninitialized(
&mut self,
location: Location,
desired_action: InitializationRequiringAction,
(moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span),
mpi: MovePathIndex,
) {

This function knows about the erroring span (where the value is borrowed after a move; x in debug!("intersection {:?}", x) in the example above) and the location of where the value was moved (range in the example above).

It's not immediately clear to me that it's easy to recover the span of the RHS of Some(range) = x from here, which is the span we want to give a suggestion for. However, MirBorrowckCtxt seems to know about move sites, and about where values are moved out of:

pub struct MoveData<'tcx> {
pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>,
pub moves: IndexVec<MoveOutIndex, MoveOut>,

/// `MoveOut` represents a point in a program that moves out of some
/// L-value; i.e., "creates" uninitialized memory.
///
/// With respect to dataflow analysis:
/// - Generated by moves and declaration of uninitialized variables.
/// - Killed by assignments to the memory.
#[derive(Copy, Clone)]
pub struct MoveOut {
/// path being moved
pub path: MovePathIndex,
/// location of move
pub source: Location,
}

I have a feeling that a MoveOut.source is what we're looking for (I assume it would describe the moving out of x in Some(range) = x), but am not entirely certain of that. It's also not yet clear to me how to convert a MoveOut source into a Span that can be used to give a suggestion.

Looking from the top-down is interesting but doesn't seem too useful. One of the lower-stack callers that generates this error is MirBorrowckCtxt#consume_rvalue:

fn consume_rvalue(
&mut self,
location: Location,
(rvalue, span): (&'cx Rvalue<'tcx>, Span),
flow_state: &Flows<'cx, 'tcx>,
) {
match *rvalue {
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
let access_kind = match bk {
BorrowKind::Shallow => {
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
},
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))
}
}
};
self.access_place(
location,
(place, span),
access_kind,
LocalMutationIsAllowed::No,
flow_state,
);
let action = if bk == BorrowKind::Shallow {
InitializationRequiringAction::MatchOn
} else {
InitializationRequiringAction::Borrow
};
self.check_if_path_or_subpath_is_moved(
location,
action,
(place.as_ref(), span),
flow_state,
);
}

Which does exactly what it sounds like, consuming an rvalue (seemingly x in debug!("intersection {:?}", x) in the example above) and checking for any errors. This doesn't seem too helpful for this problem because the actual checking of move sites isn't done until higher up the call stack, particularly in MirBorrowckCtxt#report_use_of_moved_or_uninitialized.

Right now, I think looking at MirBorrowckCtxt#report_use_of_moved_or_uninitialized and the MoveOut struct are the most likely paths to get closer to solving this. I definitely have many knowledge gaps, and am likely misunderstanding a lot, so any suggestions would be appreciated. Otherwise, I hope it can provide some baseline information for anyone else interested in this.

@estebank estebank added D-papercut Diagnostics: An error or lint that needs small tweaks. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. labels Oct 5, 2019
estebank added a commit to estebank/rust that referenced this issue Jun 20, 2020
When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
Manishearth added a commit to Manishearth/rust that referenced this issue Jun 21, 2020
…tthewjasper

Provide suggestions for some moved value errors

When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
Manishearth added a commit to Manishearth/rust that referenced this issue Jun 22, 2020
…tthewjasper

Provide suggestions for some moved value errors

When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
Manishearth added a commit to Manishearth/rust that referenced this issue Jun 26, 2020
…tthewjasper

Provide suggestions for some moved value errors

When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
Manishearth added a commit to Manishearth/rust that referenced this issue Jun 26, 2020
…tthewjasper

Provide suggestions for some moved value errors

When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
Manishearth added a commit to Manishearth/rust that referenced this issue Jun 26, 2020
…tthewjasper

Provide suggestions for some moved value errors

When encountering an used moved value where the previous move happened
in a `match` or `if let` pattern, suggest using `ref`. Fix rust-lang#63988.

When encountering a `&mut` value that is used in multiple iterations of
a loop, suggest reborrowing it with `&mut *`. Fix rust-lang#62112.
@bors bors closed this as completed in 520461f Jun 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants