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

Self: 'static bound gets mistakenly applied to references #335

Open
mauricelam opened this issue Jan 24, 2024 · 3 comments
Open

Self: 'static bound gets mistakenly applied to references #335

mauricelam opened this issue Jan 24, 2024 · 3 comments

Comments

@mauricelam
Copy link

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

@JelteF
Copy link
Owner

JelteF commented Jan 25, 2024

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?

@JelteF JelteF added the bug label Jan 31, 2024
@JelteF JelteF added this to the 1.1.0 milestone Jan 31, 2024
@mauricelam
Copy link
Author

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>;

@JelteF
Copy link
Owner

JelteF commented Jul 4, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants