- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
Closed
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemArea: Trait systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
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.
Metadata
Metadata
Assignees
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemArea: Trait systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.