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.