Skip to content

Inconsistent lifetime rules with parameter patterns #86989

Open
@cuviper

Description

@cuviper

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lifetimesArea: Lifetimes / regionsA-patternsRelating to patterns and pattern matchingC-discussionCategory: Discussion or questions that doesn't represent real issues.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions