Stream: t-compiler/wg-prioritization/alerts

Topic: I-prioritize #80161 Bug in borrow checker with 'while let'


triagebot (Dec 18 2020 at 21:57, on Zulip):

@WG-prioritization/alerts issue #80161 has been requested for prioritization.

Procedure

Camelid (Dec 18 2020 at 21:58, on Zulip):

I'm not certain this is a bug, but it does seem very confusing. Even if it isn't a bug, it seems the errors could be improved.

Joshua Nelson (Dec 19 2020 at 01:06, on Zulip):

P-medium maybe? I don't think there's any reason to make it p-high or p-low

Camelid (Dec 19 2020 at 03:39, on Zulip):

I feel like maybe P-high would be better: the code is pretty simple and I don't see why it shouldn't compile.

Camelid (Dec 19 2020 at 03:40, on Zulip):

But also: I'm surprised that others haven't run into this.

Camelid (Dec 19 2020 at 03:44, on Zulip):

camelid: Based on testing with Godbolt, it doesn't seem like this code has ever compiled.

Camelid (Dec 19 2020 at 03:44, on Zulip):

So P-medium is probably best after all.

Camelid (Dec 20 2020 at 22:24, on Zulip):

Is this even a bug?

Camelid (Dec 20 2020 at 22:24, on Zulip):

It seems like such simple code that it's weird that it could cause a borrowck bug.

Léo Lanteri Thauvin (Dec 20 2020 at 22:26, on Zulip):

Aren't the worst bugs the bugs you don't expect? x)

Camelid (Dec 20 2020 at 22:26, on Zulip):

I feel like we need input from someone who knows borrowck well. Maybe @lcnr knows? :)

Léo Lanteri Thauvin (Dec 20 2020 at 22:28, on Zulip):

Could this be related to match guards in some way?

Camelid (Dec 20 2020 at 22:28, on Zulip):

How so?

Camelid (Dec 20 2020 at 22:28, on Zulip):

(deleted - wrong topic)

Camelid (Dec 20 2020 at 22:29, on Zulip):

Too many issues to prioritize :)

Léo Lanteri Thauvin (Dec 20 2020 at 22:31, on Zulip):

I know match guards have some special quirks

Camelid (Dec 20 2020 at 22:33, on Zulip):

Bingo!

Léo Lanteri Thauvin (Dec 20 2020 at 22:34, on Zulip):

Removing the deref works?

Camelid (Dec 20 2020 at 22:34, on Zulip):

About to post...

Camelid (Dec 20 2020 at 22:35, on Zulip):

Reposting:

This is interesting: if you change the loop-and-match code to not use match guards, and instead use if-else, you get the same or a very similar borrow-check error to the while let code:

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

impl ListNode {
    #[inline]
    fn new(val: i32) -> Self {
        ListNode { next: None, val }
    }
}

pub fn remove_elements(mut head: Option<Box<ListNode>>, val: i32) -> Option<Box<ListNode>> {
    let mut current = &mut head;
    loop {
        match current {
            None => break,
            Some(node) => {
                if node.val == val {
                    *current = node.next.take();
                } else {
                    current = &mut node.next;
                }
            }
        }
    }
    head
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0503]: cannot use `*current` because it was mutably borrowed
  --> src/lib.rs:18:13
   |
18 |             None => break,
   |             ^^^^
   |             |
   |             use of borrowed `current.0`
   |             borrow later used here
19 |             Some(node) => {
   |                  ---- borrow of `current.0` occurs here

error[E0499]: cannot borrow `current.0` as mutable more than once at a time
  --> src/lib.rs:19:18
   |
19 |             Some(node) => {
   |                  ^^^^ mutable borrow starts here in previous iteration of loop

error[E0506]: cannot assign to `*current` because it is borrowed
  --> src/lib.rs:21:21
   |
19 |             Some(node) => {
   |                  ---- borrow of `*current` occurs here
20 |                 if node.val == val {
21 |                     *current = node.next.take();
   |                     ^^^^^^^^
   |                     |
   |                     assignment to borrowed `*current` occurs here
   |                     borrow later used here

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0499, E0503, E0506.
For more information about an error, try `rustc --explain E0499`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

Still not sure if it's a bug though.

Léo Lanteri Thauvin (Dec 20 2020 at 22:42, on Zulip):

Maybe it's just how while-let works

Léo Lanteri Thauvin (Dec 20 2020 at 23:07, on Zulip):

Léo Lanteri Thauvin said:

I know match guards have some special quirks

Maybe related: https://github.com/rust-lang/rust/blob/c609b2eaf323186a1167ec1a9ffa69a7d4a5b1b9/compiler/rustc_mir_build/src/build/matches/mod.rs#L1570-L1649

Léo Lanteri Thauvin (Dec 20 2020 at 23:10, on Zulip):

Maybe Matthew Jasper knows

apiraino (Dec 23 2020 at 11:29, on Zulip):

I think a P-medium if we want to keep on the radar somehow. Doesn't look like a huge problematic code

(personally I tend to change my code if the borrowchecker is not happy - I often can't tell if the ownership rules are misbehaving or rather it's me. Therefore I assume the latter case...)

Last update: Apr 10 2021 at 22:45UTC