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

Lack of variance information for subtypes in error messages (E0495) #58771

Closed
mitsuhiko opened this issue Feb 27, 2019 · 4 comments
Closed

Lack of variance information for subtypes in error messages (E0495) #58771

mitsuhiko opened this issue Feb 27, 2019 · 4 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions 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

@mitsuhiko
Copy link
Contributor

mitsuhiko commented Feb 27, 2019

We tried to build some more complex traits and this lead to a situation where the compiler would refuse to compile the trait implementation for a certain type. The reason for this turned out to be that an embedded unsafe cell somewhere deep inside the type made it invariant.

Here is an example of this:

use std::cell::UnsafeCell;
use std::rc::Rc;

type Invariant<T> = UnsafeCell<T>;
type Covariant<T> = T;

//type Wrapper<T> = Invariant<T>;
type Wrapper<T> = Covariant<T>;

trait AsSelf<'slf> {
    type Ref: ?Sized;

    fn as_self(&'slf self) -> &Self::Ref;
}

struct Foo<'a>(Wrapper<&'a str>);

impl<'slf, 'd: 'slf> AsSelf<'slf> for Foo<'d> {
    type Ref = Foo<'slf>;

    fn as_self(&'slf self) -> &Self::Ref {
        self
    }
}

This compiles, but if Wrapper<T> is changed to the Invariant version, then it refuses to compile with this error:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'slf` due to conflicting requirements
  --> src/lib.rs:21:42
   |
21 |       fn as_self(&'slf self) -> &Self::Ref {
   |  __________________________________________^
22 | |         self
23 | |     }
   | |_____^
   |
note: first, the lifetime cannot outlive the lifetime 'slf as defined on the impl at 18:6...
  --> src/lib.rs:18:6
   |
18 | impl<'slf, 'd: 'slf> AsSelf<'slf> for Foo<'d> {
   |      ^^^^
   = note: ...so that the types are compatible:
           expected AsSelf<'slf>
              found AsSelf<'_>
note: but, the lifetime must be valid for the lifetime 'd as defined on the impl at 18:12...
  --> src/lib.rs:18:12
   |
18 | impl<'slf, 'd: 'slf> AsSelf<'slf> for Foo<'d> {
   |            ^^
   = note: ...so that the expression is assignable:
           expected &'slf Foo<'_>
              found &'slf Foo<'d>

error: aborting due to previous error

This is a pretty gnarly situation one finds itself in because a) the compiler says rustc --explain E0495 but there is no extended help for E0495 and b) the actual problem here is rooted in variance and subtyping and not necessarily lifetimes as such. Would it be possible to indicate that the compiler considers Wrapper<T> invariant because it contains an UnsafeCell<T> (or &mut T) and maybe even where and link to the variance docs? This would help tremendously understanding what's happening here.

I think this is somewhat related to #51243 and #42516

@jonas-schievink jonas-schievink added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 27, 2019
@estebank
Copy link
Contributor

estebank commented Sep 5, 2019

Output with nll enabled:

error: lifetime may not live long enough
  --> src/lib.rs:24:9
   |
20 | impl<'slf, 'd: 'slf> AsSelf<'slf> for Foo<'d> {
   |      ----  -- lifetime `'d` defined here
   |      |
   |      lifetime `'slf` defined here
...
24 |         self
   |         ^^^^ returning this value requires that `'slf` must outlive `'d`

Giving the return type an explicit lifetime 'd makes it compile.

@pnkfelix pnkfelix added the A-lifetimes Area: Lifetimes / regions label Nov 19, 2019
@Aaron1011
Copy link
Member

Aaron1011 commented Dec 4, 2019

From what I can tell, we never use the word 'variance' in any compiler output, or in the Rust Book. The only references appear in the Nomicon and rustc-guide.

If we want to have the compiler explain these kinds of error messages in terms of variance (and I don't really know how else we would do it), we might want to consider moving the 'Subtyping and Variance' chapter into the Rust Book itself. While variance is an advanced topic, users can encounter it without using any unsafe at all (as this issue demonstrates). I think it would be a bad idea to have the compiler emit an error message (when no unsafe is involved) that you can't understand without reading that Nomicon.

@compiler-errors
Copy link
Member

Error message now:

error: lifetime may not live long enough
  --> src/lib.rs:24:9
   |
20 | impl<'slf, 'd: 'slf> AsSelf<'slf> for Foo<'d> {
   |      ----  -- lifetime `'d` defined here
   |      |
   |      lifetime `'slf` defined here
...
24 |         self
   |         ^^^^ associated function was supposed to return data with lifetime `'d` but it is returning data with lifetime `'slf`
   |
   = help: consider adding the following bound: `'slf: 'd`
   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

... which explains variance. Closing this.

@mitsuhiko
Copy link
Contributor Author

@compiler-errors in that example the suggestion "consider adding the following bound: `'slf: 'd`" does not seem very helpful, particularly because 'd: 'slf. I wonder if that could be removed?

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 A-lifetimes Area: Lifetimes / regions 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

6 participants