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

Can't use bound lifetime parameter 'self on &self in trait impl #8355

Closed
lilyball opened this issue Aug 6, 2013 · 2 comments
Closed

Can't use bound lifetime parameter 'self on &self in trait impl #8355

lilyball opened this issue Aug 6, 2013 · 2 comments

Comments

@lilyball
Copy link
Contributor

lilyball commented Aug 6, 2013

A lifetime parameter declared on the impl line of a trait cannot be used on &self in the function impls. This is rather problematic when the lifetime parameter is needed as part of the trait type parameters.

Here's an example:

pub struct Repeat<T> {
    priv val: T
}

impl<'self, T> Iterator<&'self T> for Repeat<T> {
    #[inline]
    fn next(&'self mut self) -> Option<&'self T> {
        Some(&self.val)
    }
}

impl<T> Repeat<T> {
    #[inline]
    fn new(val: T) -> Repeat<T> {
        Repeat{val: val}
    }
}

Compiling this gives the error

Untitled.rs:7:4: 9:5 error: method `next` has an incompatible type: expected concrete lifetime, but found bound lifetime parameter &
Untitled.rs:7     fn next(&'self mut self) -> Option<&'self T> {
Untitled.rs:8         Some(&self.val)
Untitled.rs:9     }
Untitled.rs:7:49: 9:5 note: expected concrete lifetime is the lifetime &'self  as defined on the block at 7:49
Untitled.rs:7     fn next(&'self mut self) -> Option<&'self T> {
Untitled.rs:8         Some(&self.val)
Untitled.rs:9     }
error: aborting due to previous error

Removing the 'self on &'self mut self also doesn't work. Nor does trying to use fn next<'r>(&'r mut self) ...

@nikomatsakis
Copy link
Contributor

This is not a bug, in the sense that the type system is working as designed. I do not think you can design an iterator that owns content and gives out pointers to it, at least not using the current iterator trait. To do so, you'd have to modify the iterator trait to always give out &T (where T is its type parameter), which rules out "by-move" iterators.

In this case, though, I think you don't need any lifetimes. I would implement Repeat as:

pub struct Repeat<T> { val: T }

impl<T:Clone> Iterator<T> for Repeat<T> {
    fn next(&self) -> Option<T> { Some(self.val.clone()) }
} 

If val is not copyable, you can always make Repeat::new(&the_value). I'm going to close this issue.

Type system geekery follows: If we did want to extend the type system to permit the kinds of things you are attempting to do -- and similar problems have arisen in other contexts -- I am honestly not sure how best to do it. The lifetime 'self here corresponds to the lifetime of the callee, which is not "in scope" at the impl site -- it is only in scope at a particular call site. That's why the system is designed as it is. To make this work, presumably you would need some version of higher-kinded types, though how it could be unobtrusively packaged is a bit unclear to me. In that case, the type T that is iterated over would not just be a type but actually a lifetime => T type function. Gah.

@lilyball
Copy link
Contributor Author

The implementation of Repeat isn't particularly significant, I only used that because it was a trivial way to show the problem. The real issue here is my attempt to produce a .chunk_iter() iterator adaptor, that either yields up &[A] or yields a sub-iterator that iterates one chunk. Both approaches require the ability to attach a lifetime to &self and use that lifetime in the return value of the next() function.

I fully admit that I don't perfectly grok lifetimes yet. What would be the fallout of allowing arbitrary lifetime bounds to be added to a trait function impl, i.e. fn next<'r>(&'r self) -> Option<&'r [A]>?

flip1995 pushed a commit to flip1995/rust that referenced this issue Feb 24, 2022
Don't lint `needless_borrow` in method receiver positions

fixes rust-lang#8408
fixes rust-lang#8407
fixes rust-lang#8391
fixes rust-lang#8367
fixes rust-lang#8380

This is a temporary fix for `needless_borrow`. The proper fix is included in rust-lang#8355.

This should probably be merged into rustc before beta branches on Friday. This issue has been reported six or seven times in the past couple of weeks.

changelog: Fix various issues with `needless_borrow` n´. Note to changelog writer: those issues might have been introduced in this release cycle, so this might not matter in the changelog.
flip1995 pushed a commit to flip1995/rust that referenced this issue Jun 30, 2022
Add lint `explicit_auto_deref` take 2

fixes: rust-lang#234
fixes: rust-lang#8367
fixes: rust-lang#8380

Still things to do:

* ~~This currently only lints `&*<expr>` when it doesn't trigger `needless_borrow`.~~
* ~~This requires a borrow after a deref to trigger. So `*<expr>` changing `&&T` to `&T` won't be caught.~~
* The `deref` and `deref_mut` trait methods aren't linted.
* Neither ~~field accesses~~, nor method receivers are linted.
* ~~This probably shouldn't lint reborrowing.~~
* Full slicing to deref should probably be handled here as well. e.g. `&vec[..]` when just `&vec` would do

changelog: new lint `explicit_auto_deref`
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

2 participants