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

E0623 gives very confusing message #91831

Open
Timmmm opened this issue Dec 12, 2021 · 2 comments
Open

E0623 gives very confusing message #91831

Timmmm opened this issue Dec 12, 2021 · 2 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html) D-confusing Diagnostics: Confusing error or lint that should be reworked. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Timmmm
Copy link
Contributor

Timmmm commented Dec 12, 2021

Given the following code:

fn bar(writer: &mut Writer) {
    baz(writer.indent());
    writer.write("world");
}

fn baz(writer: &mut Writer) {
    writer.write("hello");
}

pub struct Writer<'a> {
    target: &'a mut String,
    indent: usize,
}

impl<'a> Writer<'a> {
    fn indent(&'a mut self) -> &'a mut Self {
        &mut Self {
            target: self.target,
            indent: self.indent + 1,
        }
    }

    fn write(&mut self, s: &str) {
        for _ in 0..self.indent {
            self.target.push(' ');
        }
        self.target.push_str(s);
        self.target.push('\n');
    }
}

The current output is:

error[E0623]: lifetime mismatch
 --> src/writer.rs:2:16
  |
1 | fn bar(writer: &mut Writer) {
  |                -----------
  |                |
  |                these two types are declared with different lifetimes...
2 |     baz(writer.indent());
  |                ^^^^^^ ...but data from `writer` flows into `writer` here

This is really confusing. The error mentions two types, but then it only points to one type. And then it says "data from writer flows into writer". What? The data flows into itself?

@Timmmm Timmmm added 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 Dec 12, 2021
@BGR360
Copy link
Contributor

BGR360 commented Dec 21, 2021

Minimal repro (playground):

struct Foo<'a>(&'a i32);

impl<'a> Foo<'a> {
    fn modify(&'a mut self) {}
}

fn bar(foo: &mut Foo) {
    foo.modify();
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:8:9
  |
7 | fn bar(foo: &mut Foo) {
  |             --------
  |             |
  |             these two types are declared with different lifetimes...
8 |     foo.modify();
  |         ^^^^^^ ...but data from `foo` flows into `foo` here
  • Getting rid of the 'a on &'a mut self makes it compile.
  • Getting rid of the mut on &'a mut self makes it compile.
  • Getting rid of the lifetime parameter on Foo makes it compile.

If we put explicit lifetime annotations in bar's function signature, we still get the same error:

fn bar<'a, 'b>(foo: &'a mut Foo<'b>) {
    foo.modify();
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:8:9
  |
7 | fn bar<'a, 'b>(foo: &'a mut Foo<'b>) {
  |                     ---------------
  |                     |
  |                     these two types are declared with different lifetimes...
8 |     foo.modify();
  |         ^^^^^^ ...but data from `foo` flows into `foo` here

However, if we annotate only Foo, then we get a much better error:

fn bar<'a>(foo: &mut Foo<'a>) {
    foo.modify();
}
error[E0621]: explicit lifetime required in the type of `foo`
 --> src/lib.rs:8:9
  |
7 | fn bar<'a>(foo: &mut Foo<'a>) {
  |                 ------------ help: add explicit lifetime `'a` to the type of `foo`: `&'a mut Foo<'a>`
8 |     foo.modify();
  |         ^^^^^^ lifetime `'a` required

And indeed, that is the true fix (playgound):

fn bar<'a>(foo: &'a mut Foo<'a>) {
    foo.modify();
}

As I mentioned above, the error is contingent upon Foo::modify taking in a mutable reference. Perhaps this is due to the invariance of &mut. Very tricky.

In any case, I think we should try to find a way to display a message that is very similar to the add explicit lifetime message.

@rustbot label +D-confusing +D-terse +D-newcomer-roadblock +A-lifetimes

@rustbot rustbot added A-lifetimes Area: Lifetimes / regions D-confusing Diagnostics: Confusing error or lint that should be reworked. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. labels Dec 21, 2021
@BGR360
Copy link
Contributor

BGR360 commented Dec 27, 2021

See #89336 for some work being done to improve messaging on variance.

@Aaron1011 Aaron1011 added the A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html) label Dec 27, 2021
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 A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html) D-confusing Diagnostics: Confusing error or lint that should be reworked. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. 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

4 participants