Skip to content
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

Region inference fails for closure parameter #17004

Closed
bkoropoff opened this issue Sep 5, 2014 · 5 comments
Closed

Region inference fails for closure parameter #17004

bkoropoff opened this issue Sep 5, 2014 · 5 comments
Labels
A-closures Area: Closures (`|…| { … }`)

Comments

@bkoropoff
Copy link
Contributor

Test

enum Chain<'a:'b, 'b> {
    Base(&'a int),
    Rec(&'a int, &'b Chain<'a,'b>)
}

fn call_with_rec<'a, 'b>(c: Chain<'a, 'b>,
                         x: &'a int,
                         f: <'c>|Chain<'a, 'c>|) {
    f(Rec(x, &c))
}

fn main() {
    let x = 0i;
    let y = 0i;

    call_with_rec(Base(&x), &y, |mut inner| {
        loop {
            match inner {
                Base(&x) => {
                    println!("Base({})", x);
                    break;
                },
                Rec(&x, &p) => {
                    println!("Rec({})", x);
                    inner = p;
                }
            }
        }
    });
}

Output

test.rs:18:19: 18:24 error: cannot infer an appropriate lifetime due to conflicting requirements
test.rs:18             match inner {
                             ^~~~~
test.rs:18:19: 18:24 note: first, the lifetime cannot outlive the expression at 18:18...
test.rs:18             match inner {
                             ^~~~~
test.rs:18:19: 18:24 note: ...so type `Chain<'_,'_>` of expression is valid during the expression
test.rs:18             match inner {
                             ^~~~~
test.rs:16:45: 29:6 note: but, the lifetime must be valid for an anonymous lifetime defined on the block at 16:44...
test.rs:16     call_with_rec(Base(&x), &y, |mut inner| {
test.rs:17         loop {
test.rs:18             match inner {
test.rs:19                 Base(&x) => {
test.rs:20                     println!("Base({})", x);
test.rs:21                     break;
           ...
test.rs:25:21: 25:26 note: ...so that the reference type `Chain<'_,'_>` does not outlive the data it points at
test.rs:25                     inner = p;
                               ^~~~~

Workaround

The program compiles successfully if the closure is converted into a named function.

enum Chain<'a:'b, 'b> {
    Base(&'a int),
    Rec(&'a int, &'b Chain<'a,'b>)
}

fn call_with_rec<'a, 'b>(c: Chain<'a, 'b>,
                         x: &'a int,
                         f: <'c>|Chain<'a, 'c>|) {
    f(Rec(x, &c))
}

fn helper<'a, 'b>(mut inner: Chain<'a, 'b>) {
    loop {
        match inner {
            Base(&x) => {
                println!("Base({})", x);
                break;
            },
            Rec(&x, &p) => {
                println!("Rec({})", x);
                inner = p;
            }
        }
    }
}

fn main() {
    let x = 0i;
    let y = 0i;

    call_with_rec(Base(&x), &y, helper);
}

cc @nikomatsakis

I'm not sure if inference is intended to work in this scenario. It's not particularly serious since there's an easy workaround.

@steveklabnik steveklabnik added the A-closures Area: Closures (`|…| { … }`) label Jan 27, 2015
@steveklabnik
Copy link
Member

I'm not sure if this is still relevant with the closure changes or not. @nikomatsakis ?

@bluss
Copy link
Member

bluss commented May 30, 2015

I updated the code to Rust 1.0 as well as i could. Seems to produce the same errors. (playpen link)

enum Chain<'a:'b, 'b> {
    Base(&'a i32),
    Rec(&'a i32, &'b Chain<'a,'b>)
}

fn call_with_rec<'a, 'b, F>(c: Chain<'a, 'b>,
                         x: &'a i32,
                         f: F) where F: for<'c> Fn(Chain<'a, 'c>) {
    f(Chain::Rec(x, &c))
}

fn main() {
    let x = 0;
    let y = 0;

    call_with_rec(Chain::Base(&x), &y, |mut inner| {
        loop {
            match inner {
                Chain::Base(&x) => {
                    println!("Base({})", x);
                    break;
                },
                Chain::Rec(&x, &p) => {
                    println!("Rec({})", x);
                    inner = p;
                }
            }
        }
    });
}

@steveklabnik
Copy link
Member

The updated version now fails with 'cannot move out of borrowed content', which feels right.

@bkoropoff if you're still seeing this in some form, please let me know, but closing until then.

@pnkfelix
Copy link
Member

pnkfelix commented Dec 5, 2018

hmm. At this bug was originally filed, didn't we infer Copy for data types? Which would mean the appropriate update to 1.0 code would include a #[derive(Copy, Clone)] ?

@pnkfelix
Copy link
Member

pnkfelix commented Dec 5, 2018

having said that, this attempt to update the code in the aforementioned manner also does not seem to replicate the bug anymore. Huzzah?

play

use self::Chain::{Base, Rec};

#[derive(Copy, Clone)]
enum Chain<'a:'b, 'b> {
    Base(&'a i32),
    Rec(&'a i32, &'b Chain<'a,'b>)
}

fn call_with_rec<'a, 'b, F: for <'c> Fn(Chain<'a, 'c>)>(c: Chain<'a, 'b>,
                         x: &'a i32,
                         f: F) {
    f(Rec(x, &c))
}

fn helper<'a, 'b>(mut inner: Chain<'a, 'b>) {
    loop {
        match inner {
            Base(&x) => {
                println!("Base({})", x);
                break;
            },
            Rec(&x, &p) => {
                println!("Rec({})", x);
                inner = p;
            }
        }
    }
}

fn main() {
    let x = 0i32;
    let y = 0i32;

    call_with_rec(Base(&x), &y, helper);

    call_with_rec(Base(&x), &y, |mut inner| {
       loop {
            match inner {
                Base(&x) => {
                    println!("Base({})", x);
                    break;
                },
                Rec(&x, &p) => {
                    println!("Rec({})", x);
                    inner = p;
                }
            }
        }
    })
}

lnicola pushed a commit to lnicola/rust that referenced this issue Jun 23, 2024
Try caching macro calls more aggressively in Semantics
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`)
Projects
None yet
Development

No branches or pull requests

4 participants