Skip to content

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

Description

@zackw

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemC-enhancementCategory: 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.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions