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

Confusing error message when a trait bound is unsatisfied due to lack of mutability #63619

Closed
zackw opened this issue Aug 15, 2019 · 2 comments · Fixed by #65077
Closed

Confusing error message when a trait bound is unsatisfied due to lack of mutability #63619

zackw opened this issue Aug 15, 2019 · 2 comments · Fixed by #65077
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-traits Area: Trait system 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

@zackw
Copy link
Contributor

zackw commented Aug 15, 2019

In this code, fp should have been declared as a mutable reference, and the compiler gives you a nice clear error message saying so:

use std::env::args;
use std::fs::File;
use std::io::{stdout, Write};

fn main() {
    let mut args = args();
    let _ = args.next();
    let dest = args.next();

    let h1; let h2; let h3;

    let fp: &dyn Write = match dest {
        Some(path) => { h1 = File::create(path).unwrap(); &h1 },
        None => { h2 = stdout(); h3 = h2.lock(); &h3 }
    };

    writeln!(fp, "hello world").unwrap();
}

error[E0596]: cannot borrow `*fp` as mutable, as it is behind a `&` reference
  --> test.rs:17:14
   |
12 |     let fp: &dyn Write = match dest {
   |         -- help: consider changing this to be a mutable reference:
   |            `&mut dyn std::io::Write`
...
17 |     writeln!(fp, "hello world").unwrap();
   |              ^^ `fp` is a `&` reference, so the data it refers to
   |                 cannot be borrowed as mutable

But you have a BufWriter in between writeln! and the match, you get a different and very confusing error message:

use std::env::args;
use std::fs::File;
use std::io::{stdout, Write, BufWriter};

fn main() {
    let mut args = args();
    let _ = args.next();
    let dest = args.next();

    let h1; let h2; let h3;

    let fp: &dyn Write = match dest {
        Some(path) => { h1 = File::create(path).unwrap(); &h1 },
        None => { h2 = stdout(); h3 = h2.lock(); &h3 }
    };

    let fp = BufWriter::new(fp);

    writeln!(fp, "hello world").unwrap();
}

error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write`
              is not satisfied
  --> test.rs:17:14
   |
17 |     let fp = BufWriter::new(fp);
   |              ^^^^^^^^^^^^^^ the trait `std::io::Write`
   |           is not implemented for `&dyn std::io::Write`
   |
   = note: required by `std::io::BufWriter::<W>::new`

How can it possibly be that "the trait std::io::Write is not implemented for &dyn std::io::Write" ?! Well, in fact, it's the exact same problem as the first sample code, and the error message is literally true. &dyn std::io::Write doesn't implement std::io::Write, but &mut dyn std::io::Write does.

Could the compiler perhaps print an additional note when &T doesn't satisfy a trait bound, but &mut T would have, explaining that this might be the problem? Or vice versa, of course.

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints A-traits Area: Trait system 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 Aug 15, 2019
@zackw
Copy link
Contributor Author

zackw commented Aug 15, 2019

It's also maybe worth mentioning that you get two additional error messages from the second example program, both of which are useless noise -- the second error repeats the first one with slightly different caret highlighting, and the third error complains (at the point of the writeln!) that std::io::BufWriter<&dyn std::io::Write> doesn't implement std::io::Write either. But it would have implemented Write if its type argument did, so it's all the same problem and really it would be nice if the compiler could be clever enough to just print one error.

@estebank
Copy link
Contributor

estebank commented Oct 3, 2019

CC #37914

Centril added a commit to Centril/rust that referenced this issue Oct 7, 2019
@bors bors closed this as completed in 8ee24f6 Oct 10, 2019
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-traits Area: Trait system 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

Successfully merging a pull request may close this issue.

3 participants