diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 246b23f11b68b..40c2c011efc29 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -203,6 +203,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return guar; } + // Check for the write!/writeln! macro special case + let is_write_fmt = item_name.name == sym::write_fmt; + let is_write_macro = + expr_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| { + self.tcx.is_diagnostic_item(sym::write_macro, def_id) + || self.tcx.is_diagnostic_item(sym::writeln_macro, def_id) + }); + + if is_write_fmt && is_write_macro { + // This is a write!/writeln! macro call with write_fmt method error + let mut file = None; + let mut err = struct_span_code_err!( + self.dcx(), + span, + E0599, + "cannot write into `{}`", + self.tcx.short_string(rcvr_ty, &mut file) + ); + *err.long_ty_path() = file; + err.note("type does not implement the `write_fmt` method"); + err.help("try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope"); + return err.emit(); + } + match error { MethodError::NoMatch(mut no_match_data) => self.report_no_match_method_error( span, diff --git a/tests/ui/E0599-write-macro/io-write-fmt-method-error.rs b/tests/ui/E0599-write-macro/io-write-fmt-method-error.rs new file mode 100644 index 0000000000000..1b3d66f49f778 --- /dev/null +++ b/tests/ui/E0599-write-macro/io-write-fmt-method-error.rs @@ -0,0 +1,23 @@ +// Issue #139051 - Test for the case where io::Write would be more appropriate +// +// Test that when using write! on a type that doesn't implement std::io::Write trait, +// we get a clear error message suggesting to import the appropriate trait. +// +// edition:2021 +// ignore-msvc +// ignore-emscripten +// run-fail +// check-pass + +fn main() { + // Simple struct that doesn't implement std::io::Write + struct MyIoStruct { + value: i32, + } + + let mut s = MyIoStruct { value: 42 }; + + // This should generate E0599 with the improved error message + // suggesting io::Write instead + write!(s, "Hello, world!"); //~ ERROR cannot write into `MyIoStruct` +} diff --git a/tests/ui/E0599-write-macro/io-write-fmt-method-error.stderr b/tests/ui/E0599-write-macro/io-write-fmt-method-error.stderr new file mode 100644 index 0000000000000..23fd2c6d982ad --- /dev/null +++ b/tests/ui/E0599-write-macro/io-write-fmt-method-error.stderr @@ -0,0 +1,13 @@ +error[E0599]: cannot write into `MyIoStruct` + --> $DIR/io-write-fmt-method-error.rs:22:5 + | +LL | write!(s, "Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/E0599-write-macro/write-fmt-method-error.rs b/tests/ui/E0599-write-macro/write-fmt-method-error.rs new file mode 100644 index 0000000000000..3cb80f8c1aff6 --- /dev/null +++ b/tests/ui/E0599-write-macro/write-fmt-method-error.rs @@ -0,0 +1,24 @@ +// Issue #139051 - Ensure we don't get confusing suggestions for E0599 +// on write!/writeln! macros +// +// Test that when using write!/writeln! macros with a type that doesn't implement +// std::fmt::Write trait, we get a clear error message without irrelevant suggestions. +// +// edition:2021 +// ignore-msvc +// ignore-emscripten +// run-fail +// check-pass + +fn main() { + // Simple struct that doesn't implement std::fmt::Write + struct MyStruct { + value: i32, + } + + let mut s = MyStruct { value: 42 }; + + // This should generate E0599 with the improved error message + // and not suggest irrelevant methods like write_str or push_str + write!(s, "Hello, world!"); //~ ERROR cannot write into `MyStruct` +} diff --git a/tests/ui/E0599-write-macro/write-fmt-method-error.stderr b/tests/ui/E0599-write-macro/write-fmt-method-error.stderr new file mode 100644 index 0000000000000..11a7ed0686925 --- /dev/null +++ b/tests/ui/E0599-write-macro/write-fmt-method-error.stderr @@ -0,0 +1,13 @@ +error[E0599]: cannot write into `MyStruct` + --> $DIR/write-fmt-method-error.rs:23:5 + | +LL | write!(s, "Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/E0599-write-macro/writeln-fmt-method-error.rs b/tests/ui/E0599-write-macro/writeln-fmt-method-error.rs new file mode 100644 index 0000000000000..a9d5b6a7f8288 --- /dev/null +++ b/tests/ui/E0599-write-macro/writeln-fmt-method-error.rs @@ -0,0 +1,24 @@ +// Issue #139051 - Ensure we don't get confusing suggestions for E0599 +// on write!/writeln! macros +// +// Test that when using write!/writeln! macros with a type that doesn't implement +// std::fmt::Write trait, we get a clear error message without irrelevant suggestions. +// +// edition:2021 +// ignore-msvc +// ignore-emscripten +// run-fail +// check-pass + +fn main() { + // Simple struct that doesn't implement std::fmt::Write + struct MyStruct { + value: i32, + } + + let mut s = MyStruct { value: 42 }; + + // This should generate E0599 with the improved error message + // and not suggest irrelevant methods like write_str or push_str + writeln!(s, "Hello, world!"); //~ ERROR cannot write into `MyStruct` +} diff --git a/tests/ui/E0599-write-macro/writeln-fmt-method-error.stderr b/tests/ui/E0599-write-macro/writeln-fmt-method-error.stderr new file mode 100644 index 0000000000000..93d1aee8c4f80 --- /dev/null +++ b/tests/ui/E0599-write-macro/writeln-fmt-method-error.stderr @@ -0,0 +1,13 @@ +error[E0599]: cannot write into `MyStruct` + --> $DIR/writeln-fmt-method-error.rs:23:5 + | +LL | writeln!(s, "Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/macros/missing-writer.rs b/tests/ui/macros/missing-writer.rs index 7df965c3684e2..a74703e7da23f 100644 --- a/tests/ui/macros/missing-writer.rs +++ b/tests/ui/macros/missing-writer.rs @@ -6,12 +6,12 @@ fn main() { //~^ ERROR format argument must be a string literal //~| HELP you might be missing a string literal to format with //~| ERROR cannot write into `&'static str` - //~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - //~| HELP a writer is needed before this format string + //~| NOTE type does not implement the `write_fmt` method + //~| HELP try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope writeln!("{}_{}", x, y); //~^ ERROR format argument must be a string literal //~| HELP you might be missing a string literal to format with //~| ERROR cannot write into `&'static str` - //~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - //~| HELP a writer is needed before this format string + //~| NOTE type does not implement the `write_fmt` method + //~| HELP try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope } diff --git a/tests/ui/macros/missing-writer.stderr b/tests/ui/macros/missing-writer.stderr index 86dfe7d65ea62..aa8ca1c6b11c4 100644 --- a/tests/ui/macros/missing-writer.stderr +++ b/tests/ui/macros/missing-writer.stderr @@ -21,38 +21,24 @@ LL | writeln!("{}_{}", "{} {}", x, y); | ++++++++ error[E0599]: cannot write into `&'static str` - --> $DIR/missing-writer.rs:5:12 + --> $DIR/missing-writer.rs:5:5 | LL | write!("{}_{}", x, y); - | -------^^^^^^^------- method not found in `&str` + | ^^^^^^^^^^^^^^^^^^^^^ | -note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/missing-writer.rs:5:12 - | -LL | write!("{}_{}", x, y); - | ^^^^^^^ -help: a writer is needed before this format string - --> $DIR/missing-writer.rs:5:12 - | -LL | write!("{}_{}", x, y); - | ^ + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: cannot write into `&'static str` - --> $DIR/missing-writer.rs:11:14 + --> $DIR/missing-writer.rs:11:5 | LL | writeln!("{}_{}", x, y); - | ---------^^^^^^^------- method not found in `&str` + | ^^^^^^^^^^^^^^^^^^^^^^^ | -note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/missing-writer.rs:11:14 - | -LL | writeln!("{}_{}", x, y); - | ^^^^^^^ -help: a writer is needed before this format string - --> $DIR/missing-writer.rs:11:14 - | -LL | writeln!("{}_{}", x, y); - | ^ + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs index 66e1e77c905e0..f1711d0b2671b 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -18,5 +18,5 @@ fn main() { //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - writeln!(fp, "hello world").unwrap(); //~ ERROR the method + writeln!(fp, "hello world").unwrap(); //~ ERROR cannot write into `BufWriter<&dyn std::io::Write>` } diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 09a9b1d3b3482..79a1d0d5727f0 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -20,20 +20,15 @@ LL | let fp = BufWriter::new(fp); note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL -error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 +error[E0599]: cannot write into `BufWriter<&dyn std::io::Write>` + --> $DIR/mut-borrow-needed-by-trait.rs:21:5 | LL | writeln!(fp, "hello world").unwrap(); - | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 - | -LL | writeln!(fp, "hello world").unwrap(); - | ^^ - = note: the following trait bounds were not satisfied: - `&dyn std::io::Write: std::io::Write` - which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` + = note: type does not implement the `write_fmt` method + = help: try adding `use std::fmt::Write;` or `use std::io::Write;` to bring the appropriate trait into scope + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors