Skip to content

lifetime inference regression in closure #47524

Closed

Description

@cuviper

The owning_ref crate has a couple test failures starting with Rust 1.23, which worked fine on 1.22. It is fixed by Kimundi/owning-ref-rs#43, but I wanted to see if this is a deliberate compiler change. The only compatibility note for 1.23 that sounds like it might be related is regarding #45852, but I'm not sure.

Reduced example, playground:

fn map<F, T, U>(x: &T, f: F) -> &U
where
    F: FnOnce(&T) -> &U,
{
    f(x)
}

fn borrow<'a>(a: &'a &[i32; 2]) -> &'a i32 {
    &a[0]
}

fn main() {
    let foo = [413, 612];
    let bar = &foo;

    map(&bar, borrow); // OK

    map(&bar, |a: &&[i32; 2]| &a[0]); // does not live long enough
}

This example works on 1.22, but fails on 1.23 through nightly:

error[E0597]: `a[..]` does not live long enough
  --> src/main.rs:18:32
   |
18 |     map(&bar, |a: &&[i32; 2]| &a[0]); // does not live long enough
   |                                ^^^^- borrowed value only lives until here
   |                                |
   |                                does not live long enough
   |
note: borrowed value must be valid for the anonymous lifetime #2 defined on the body at 18:15...
  --> src/main.rs:18:15
   |
18 |     map(&bar, |a: &&[i32; 2]| &a[0]); // does not live long enough
   |               ^^^^^^^^^^^^^^^^^^^^^

xref: https://bugzilla.redhat.com/show_bug.cgi?id=1535396

Activity

  1. added
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Jan 17, 2018
  2. self-assigned this
    on Jan 18, 2018
  3. nikomatsakis commented on Jan 18, 2018

    @nikomatsakis
    Contributor

    triage: P-high

    Regressions BAD‼️

  4. nikomatsakis commented on Jan 20, 2018

    @nikomatsakis
    Contributor

    I wonder if this could have been caused by #45072

  5. nikomatsakis commented on Jan 20, 2018

    @nikomatsakis
    Contributor

    That PR was merged on Nov 5, 2017.

    Rust 1.22 was released Nov 22.

    So I guess not.

  6. cuviper commented on Jan 20, 2018

    @cuviper
    MemberAuthor

    If you're comparing dates, don't forget the skew of the beta branch. Or you can click on the PR commit and github shows the tags containing it -- 666687a shows only 1.23.0.

  7. nikomatsakis commented on Jan 20, 2018

    @nikomatsakis
    Contributor

    Worth mentioning: the problem is fixed by NLL

  8. nikomatsakis commented on Jan 20, 2018

    @nikomatsakis
    Contributor

    @cuviper oh, really? Then that is probably the culprit. Gotta go, more later.

  9. nikomatsakis commented on Jan 20, 2018

    @nikomatsakis
    Contributor

    OK, so, I think this is a bug and a genuine regression, but it's one that will kinda be a pain to fix in the existing system. The NLL system is newer and shinier and it can handle this scenario more gracefully. I'm tempted to say let's wait and fix this by moving to NLL, but then I do hate regressions. Have to think about it, there might be an easy fix in the existing, lexical system.

    Detailed, jargon-full account of what's happening

    OK, so, here's what's happening. The older system could be incoherent, but in this case, it would have ignored the expected type and assigned the closure a type that was equivalent to the type that the standalone function (in the fix patch) has. The newer system respects the expected type, and winds up with a type like for<'a> &'a &'b X -- note that 'b is not bound in the closure. It's some region from the surrounding function. The shortcomings in our lexical region inference wind up calling this an error, though due to the implied bounds we ought to accept it. It may be possible to fix that. In contrast, in the newer, shiny NLL system, those annotations that got inferred by typeck are ignored. The closure is assigned the most flexible regions it can get, and everything works out fine.

  10. nikomatsakis commented on Feb 15, 2018

    @nikomatsakis
    Contributor

    triage: P-medium

    Discussed in the @rust-lang/compiler meeting. The summary is:

    • This is a genuine bug and regression.
    • It is however fixed in NLL.
    • It's a pain in the neck to fix in the existing system and doesn't seem to be affecting many crates.

    Therefore, we are going to downgrade to P-medium and mark this as blocked on NLL.

  11. added and removed
    P-highHigh priority
    on Feb 15, 2018
  12. added
    A-NLLArea: Non-lexical lifetimes (NLL)
    and removed
    A-NLLArea: Non-lexical lifetimes (NLL)
    on Feb 15, 2018
  13. added a commit that references this issue on Mar 11, 2019
    65cb35a
  14. added 3 commits that reference this issue on Apr 22, 2019
    bf0ea60
    c21fbfe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-NLLArea: Non-lexical lifetimes (NLL)A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.fixed-by-NLLBugs fixed, but only when NLL is enabled.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions