derive_more
derive_more copied to clipboard
`Self: 'static` bound gets mistakenly applied to references
In the following code, the Self: 'static
bound gets copied to the derived impl TryFrom<&mut Foo<V>> for (&mut Wrapper<V>) where Self: 'static
, which changes the bound from Foo<V>: 'static
to &mut Foo<V>: 'static
.
use derive_more;
#[derive(Debug)]
pub struct Wrapper<V>(V);
#[derive(derive_more::TryInto)]
#[try_into(ref, ref_mut)]
pub enum Foo<V> where Self: 'static { // This line fails
// pub enum Foo<V> where Foo<V>: 'static { // This line succeeds, after explicitly changing `Self` to `Foo<V>`
V(Wrapper<V>),
}
fn main() {
let x = Foo::<u8>::V(Wrapper(2));
let u8ref: &Wrapper<u8> = (&x).try_into().unwrap();
println!("{u8ref:?}");
}
And the resulting build fails with
error[E0597]: `x` does not live long enough
--> src/main.rs:20:31
|
19 | let x = Foo::<u8>::V(Wrapper(2));
| - binding `x` declared here
20 | let u8ref: &Wrapper<u8> = (&x).try_into().unwrap();
| ^^^^-----------
| |
| borrowed value does not live long enough
| argument requires that `x` is borrowed for `'static`
21 | println!("{u8ref:?}");
22 | }
| - `x` dropped here while still borrowed
https://www.rustexplorer.com/b#LyoKW2RlcGVuZGVuY2llc10KZGVyaXZlX21vcmUgPSAiKiIKKi8KCnVzZSBkZXJpdmVfbW9yZTsKCiNbZGVyaXZlKERlYnVnKV0KcHViIHN0cnVjdCBXcmFwcGVyPFY+KFYpOwoKI1tkZXJpdmUoZGVyaXZlX21vcmU6OlRyeUludG8pXQojW3RyeV9pbnRvKHJlZiwgcmVmX211dCldCnB1YiBlbnVtIEZvbzxWPiB3aGVyZSBTZWxmOiAnc3RhdGljIHsgIC8vIFRoaXMgbGluZSBmYWlscwovLyBwdWIgZW51bSBGb288Vj4gd2hlcmUgRm9vPFY+OiAnc3RhdGljIHsgIC8vIFRoaXMgbGluZSBzdWNjZWVkcywgYWZ0ZXIgZXhwbGljaXRseSBjaGFuZ2luZyBgU2VsZmAgdG8gYEZvbzxWPmAKICAgIFYoV3JhcHBlcjxWPiksCn0KCmZuIG1haW4oKSB7CiAgICBsZXQgeCA9IEZvbzo6PHU4Pjo6VihXcmFwcGVyKDIpKTsKICAgIGxldCB1OHJlZjogJldyYXBwZXI8dTg+ID0gKCZ4KS50cnlfaW50bygpLnVud3JhcCgpOwogICAgcHJpbnRsbiEoInt1OHJlZjo/fSIpOwp9
Hmm, that does seem like an annoying bug. Just double checking: is it also happening when using the 1.0.0-beta.6 release of derive_more?
Trying on 1.0.0-beta.6
, it's failing with a different issue:
error[E0107]: missing generics for enum `Foo`
--> src/main.rs:8:10
|
8 | pub enum Foo<V> where Self: 'static { // This line fails
| ^^^ expected 1 generic argument
|
note: enum defined here, with 1 generic parameter: `V`
--> src/main.rs:8:10
|
8 | pub enum Foo<V> where Self: 'static { // This line fails
| ^^^ -
help: add missing generic argument
|
8 | pub enum Foo<V><V> where Self: 'static { // This line fails
|
Expanding the macro manually I believe it's coming from this line:
type Error = ::derive_more::TryIntoError<Foo>;
Okay, so I took a quick look at this as part of my attempt to finally get ready to release 1.0.0
The error you get on on 1.0.0-beta.6 is a regression from 0.99, and #384 fixes that one.
The original issue you reported is not as easy to solve though (although possible to solve). The reason this happens is because we blindly copy all the constraints from the type definition to the trait implementation. This is normally fine, even in case of Self
being used. The thing that causes problems here is that the derive generates a TryFrom
implementation for the type in the variant, instead of a TryInto
implementation for the type on which the derive is placed ([this is recommended by the rust docs][1]). This means that Self
actually means something different when applied to the type, then when applied to the derived implementation. In your example it means Foo<V>
on the type, and &Wrapper<V>
on the impl
of the TryInto
trait.
The way to fix this in derive_more
is by replacing Self
in the bounds that we place on the impl
with the actual type. I don't think this is too difficult to do, but since this is no regression and fixing this does not consistute a breaking change, I don't think it makes sense to work on this now. Especially since there is a very easy workaround for this issue: Replacing Self
on the where
clause with the actual type.