Skip to content

Inconsistent lifetime rules with parameter patterns #86989

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

Open
cuviper opened this issue Jul 8, 2021 · 0 comments
Open

Inconsistent lifetime rules with parameter patterns #86989

cuviper opened this issue Jul 8, 2021 · 0 comments
Labels
A-lifetimes Area: Lifetimes / regions A-patterns Relating to patterns and pattern matching C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cuviper
Copy link
Member

cuviper commented Jul 8, 2021

Here's an example derived from rayon-rs/rayon#866:
playground

fn main() {
    let mut v = vec![vec![1, 2, 3], vec![4, 5, 6]];

    v.iter_mut().for_each(|mut x| {
        let mut c = x.clone();
        x = &mut c; // borrowed value does not live long enough
        x[0] = 0;
    });

    v.iter_mut().enumerate().for_each(|mut x| {
        let mut c = x.1.clone();
        x.1 = &mut c; // borrowed value does not live long enough
        x.1[0] = 0;
    });

    v.iter_mut().enumerate().for_each(|(_i, mut x)| {
        let mut c = x.clone();
        x = &mut c; // this works!
        x[0] = 0;
    });
}

The first two loops fail, because x has an "external" lifetime that c can't possibly satisfy. However, with the third pattern, x gets a local lifetime which can be assigned from c. @nikomatsakis explained it this way:

I think this has to do with the details of how the MIR desugaring works. I'm not sure it's intentional, but it's interesting... when you have (u, mut x) as the parameter pattern, the closure is effectively converted into this:

|tmp| {
     let (u, mut x) = tmp;
}

and so x is a local variable inside the closure. Therefore, it's lifetime is independent from tmp and it can be given a lifetime that includes the lifetime of c. The actual argument (tmp) has to have a lifetime that is "external" from the closure body (something the caller could reference).

If you don't have a pattern (or, rather, you have a trivial pattern like x) you get a hard error either way.

This feels unfortunate, but I'm trying to decide what fix I would want to apply. :)

In the original issue, @evergreen-trading-systems was surprised not to get an error in the destructured case, but I don't think that's something we could (or should) go back on now. It would be more interesting if even the trivial pattern could be made to work with a reduced lifetime.

@inquisitivecrystal inquisitivecrystal added A-lifetimes Area: Lifetimes / regions A-patterns Relating to patterns and pattern matching C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions A-patterns Relating to patterns and pattern matching C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

2 participants