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

Diagnostics: suggest higher-rank trait bounds when implementing trait for &Type #69511

Closed
yoshuawuyts opened this issue Feb 27, 2020 · 3 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@yoshuawuyts
Copy link
Member

yoshuawuyts commented Feb 27, 2020

Failing Code

Consider the following code:

use std::io::{self, prelude::*};
use std::sync::Arc;

struct IoArc<T>(Arc<T>);

impl<T> Read for IoArc<T>
where
    &T: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&mut &*self.0).read(buf)
    }
}

playground

This fails with a pretty gnarly error about how &IoArc<T> doesn't have a
lifetime, parameter T doesn't live long enough, and we should consider adding
a lifetime. It (wrongly) suggest we may want to add a static lifetime. Which
is not the right solution.

Compiling playground v0.0.1 (/playground)
error[E0637]: `&` without an explicit lifetime name cannot be used here
 --> src/lib.rs:8:5
  |
8 |     &T: Read,
  |     ^ explicit lifetime name needed here

error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:6:1
   |
6  |   impl<T> Read for IoArc<T>
   |   ^    - help: consider adding an explicit lifetime bound `T: 'static`...
   |  _|
   | |
7  | | where
8  | |     &T: Read,
9  | | {
...  |
12 | |     }
13 | | }
   | |_^
   |
note: ...so that the reference type `&'static T` does not outlive the data it points at
  --> src/lib.rs:6:1
   |
6  | / impl<T> Read for IoArc<T>
7  | | where
8  | |     &T: Read,
9  | | {
...  |
12 | |     }
13 | | }
   | |_^

error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:10:5
   |
6  |   impl<T> Read for IoArc<T>
   |        - help: consider adding an explicit lifetime bound `T: 'static`...
...
10 | /     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
11 | |         (&mut &*self.0).read(buf)
12 | |     }
   | |_____^
   |
note: ...so that the reference type `&'static T` does not outlive the data it points at
  --> src/lib.rs:10:5
   |
10 | /     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
11 | |         (&mut &*self.0).read(buf)
12 | |     }
   | |_____^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0310`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

Working Code

Instead the resolution is to add a higher-rank trait bound, like this:

use std::io::{self, prelude::*};
use std::sync::Arc;

struct IoArc<T>(Arc<T>);

impl<T> Read for IoArc<T>
where
    for<'a> &'a T: Read, // <-- we added for<'a> to get a lifetime
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&mut &*self.0).read(buf)
    }
}

Diagnostics Suggestions

I understand that this is not a particularly common pattern, but the compiler
really isn't of much help when trying to figure this out. A better suggestion
here would have been:

Compiling playground v0.0.1 (/playground)
error[E0637]: `&` without an explicit lifetime name cannot be used here
 --> src/lib.rs:8:5
  |
8 |     &T: Read,
  |     ^ explicit lifetime name needed here

help: Consider adding a higher-rank trait bound:

 --> src/lib.rs:8:5
  |
8 |     for<'a> &'a T: Read,
  |

With if 'static is sometimes the right solution, perhaps two help texts would make sense:

help: ...or use a static lifetime:

 --> src/lib.rs:8:5
  |
8 |     &'static T: Read,
  |
@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 27, 2020
@yoshuawuyts yoshuawuyts changed the title Diagnostics: suggest higher-kinded trait bounds when implementing trait for &Type Diagnostics: suggest higher-ranked trait bounds when implementing trait for &Type Feb 27, 2020
@yoshuawuyts
Copy link
Member Author

As pointed out on twitter the correct terminology is "higher-rank trait bounds". Keeping terminology straight is difficult, haha.

@yoshuawuyts yoshuawuyts changed the title Diagnostics: suggest higher-ranked trait bounds when implementing trait for &Type Diagnostics: suggest higher-rank trait bounds when implementing trait for &Type Feb 27, 2020
@estebank
Copy link
Contributor

Related PR #69048

@estebank
Copy link
Contributor

estebank commented Jun 30, 2023

Current output:

error[[E0637]](https://doc.rust-lang.org/stable/error_codes/E0637.html): `&` without an explicit lifetime name cannot be used here
 --> src/main.rs:8:5
  |
8 |     &T: Read,
  |     ^ explicit lifetime name needed here
  |
help: consider introducing a higher-ranked lifetime here with `for<'a>`
 --> src/main.rs:8:5
  |
8 |     &T: Read,
  |     ^

error[[E0311]](https://doc.rust-lang.org/stable/error_codes/E0311.html): the parameter type `T` may not live long enough
 --> src/main.rs:8:9
  |
8 |     &T: Read,
  |         ^^^^ ...so that the reference type `&T` does not outlive the data it points at

It should be a structured suggestion instead, but the original ask has been fulfilled.

Edit: addressing the last bit in #113177.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants