Skip to content

Use of match ergonomics affect borrow checking #127238

@hniksic

Description

@hniksic

This code fails to compile due to a borrow check error:

fn insert(v: &mut Option<u32>) -> Option<&u32> {
    if let Some(r) = &v {
        return Some(r)
    }
    *v = next_token();
    v.as_ref()
}

fn next_token() -> Option<u32> {
    unimplemented!()
}

Playground

The compiler complains that "cannot assign to *v because it is borrowed", which is a well-known borrow checker limitation. However, I was surprised to discover that it compiles using ref matching in if let:

fn insert(v: &mut Option<u32>) -> Option<&u32> {
    if let Some(ref r) = v {
        return Some(r)
    }
    *v = next_token();
    v.as_ref()
}

Playground

I would expect the former code to desugar to the latter, as per "match ergonomics". In other words, I'd expect both examples to be accepted by the compiler, or both to be rejected (ideally the former).

This issue is not intended as a report regarding the borrow checker limitation that will be fixed by Polonius. It is about the perceived equivalence of match-ergonomics match and the manually written one, which I'd expect to lead to the same borrow-checking outcomes.

Meta

This is on rustc 1.79.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions