Skip to content

Lifetime inference failure #19875

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

Closed
tomaka opened this issue Dec 15, 2014 · 3 comments
Closed

Lifetime inference failure #19875

tomaka opened this issue Dec 15, 2014 · 3 comments

Comments

@tomaka
Copy link
Contributor

tomaka commented Dec 15, 2014

This code: (http://is.gd/tif86V)

struct Iter<'a>(&'a mut Vec<int>);

impl<'a> Iterator<&'a mut int> for Iter<'a> {
    fn next(&mut self) -> Option<&'a mut int> {
        self.0.as_mut_slice().get_mut(0)
    }
}

Produces this:

<anon>:5:16: 5:30 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
<anon>:5         self.0.as_mut_slice().get_mut(0)
                        ^~~~~~~~~~~~~~
<anon>:4:5: 6:6 help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<&'a mut int>
<anon>:4     fn next(&mut self) -> Option<&'a mut int> {
<anon>:5         self.0.as_mut_slice().get_mut(0)
<anon>:6     }

I don't think there is anything unsafe with what I want to do (it's the exact same signature as MutItems).

This code does work but is incompatible with the Iterator trait definition: (http://is.gd/rMwbe6)

struct Iter<'a>(&'a mut Vec<int>);

impl<'a> Iter<'a> {
    fn next<'c: 'a>(&'c mut self) -> Option<&'a mut int> {
        self.0.as_mut_slice().get_mut(0)
    }
}

Sorry if this is a duplicate.

@steveklabnik
Copy link
Member

You're going to have to write out the explicit lifetimes in this case. The 'inference' is just a set of simple rules: https://github.com/rust-lang/rfcs/blob/master/text/0141-lifetime-elision.md#the-rules

The elisison assigns the same lifetime to the self reference as the int reference, due to rule 3.

I'm not going to close this because I might be missing something, but that's what I see.

@japaric
Copy link
Member

japaric commented Dec 15, 2014

@tomaka Your code is not safe, and that's why it doesn't compile. If you call next() twice you'll end with two mutable references to the head of the vector.

// Calling `next` on an `Iterator` never freezes it, because of the signature of `next()`:
//    `next(&mut self) -> T`  // no lifetime "glue" between `self` and `T`
let head_mut: &mut T = iter.next();
let another_head_mut: &mut T = iter.next();

I don't think there is anything unsafe with what I want to do (it's the exact same signature as MutItems).

MutItems internally uses raw pointers for this reason, it's an unsafe operation.

This code does work but is incompatible with the Iterator trait definition

One possible (future) safe solution is HKT. The Iterator trait would need to change to:

trait Iterator<T> {
    // note: `T` is a "type constructor": lifetime -> concrete type
    fn next<'a>(&'a mut self) -> T<'a>;
}

With that definition and your implementation the iterator will "freeze" when next method is called, avoiding aliases to mutable memory.

let head_mut: &mut T = iter.next();  // `iter` gets frozen here
let another_head_mut: &mut T = iter.next();  //~ error: `iter` is already mutably borrowed

See this blog post (warning: old syntax) for more details.

@tomaka
Copy link
Contributor Author

tomaka commented Dec 15, 2014

Thanks

@tomaka tomaka closed this as completed Dec 15, 2014
lnicola pushed a commit to lnicola/rust that referenced this issue May 28, 2025
fix: Skip pattern analysis on type mismatches
lnicola pushed a commit to lnicola/rust that referenced this issue May 28, 2025
fix: Skip pattern analysis on type mismatches
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants