Skip to content

Commit ff88787

Browse files
committed
check for write macro and write_fmt with err msg
added ui test blessed stderrs fixed typo reblessed
1 parent 2036fdd commit ff88787

File tree

4 files changed

+125
-13
lines changed

4 files changed

+125
-13
lines changed

Diff for: compiler/rustc_hir_typeck/src/method/suggest.rs

+42-10
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
245245
None
246246
}
247247

248+
fn suggest_missing_writer(
249+
&self,
250+
rcvr_ty: Ty<'tcx>,
251+
args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
252+
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
253+
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
254+
let mut err =
255+
struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
256+
err.span_note(
257+
args.0.span,
258+
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
259+
);
260+
if let ExprKind::Lit(_) = args.0.kind {
261+
err.span_help(
262+
args.0.span.shrink_to_lo(),
263+
"a writer is needed before this format string",
264+
);
265+
};
266+
267+
err
268+
}
269+
248270
pub fn report_no_match_method_error(
249271
&self,
250272
mut span: Span,
@@ -323,16 +345,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
323345
}
324346
}
325347

326-
let mut err = struct_span_err!(
327-
tcx.sess,
328-
span,
329-
E0599,
330-
"no {} named `{}` found for {} `{}` in the current scope",
331-
item_kind,
332-
item_name,
333-
rcvr_ty.prefix_string(self.tcx),
334-
ty_str_reported,
335-
);
348+
let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| {
349+
tcx.is_diagnostic_item(sym::write_macro, def_id)
350+
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
351+
}) && item_name.name == Symbol::intern("write_fmt");
352+
let mut err = if is_write
353+
&& let Some(args) = args
354+
{
355+
self.suggest_missing_writer(rcvr_ty, args)
356+
} else {
357+
struct_span_err!(
358+
tcx.sess,
359+
span,
360+
E0599,
361+
"no {} named `{}` found for {} `{}` in the current scope",
362+
item_kind,
363+
item_name,
364+
rcvr_ty.prefix_string(self.tcx),
365+
ty_str_reported,
366+
)
367+
};
336368
if tcx.sess.source_map().is_multiline(sugg_span) {
337369
err.span_label(sugg_span.with_hi(span.lo()), "");
338370
}

Diff for: tests/ui/macros/missing-writer.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Check error for missing writer in writeln! and write! macro
2+
fn main() {
3+
let x = 1;
4+
let y = 2;
5+
write!("{}_{}", x, y);
6+
//~^ ERROR format argument must be a string literal
7+
//~| HELP you might be missing a string literal to format with
8+
//~| ERROR cannot write into `&'static str`
9+
//~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
10+
//~| HELP a writer is needed before this format string
11+
writeln!("{}_{}", x, y);
12+
//~^ ERROR format argument must be a string literal
13+
//~| HELP you might be missing a string literal to format with
14+
//~| ERROR cannot write into `&'static str`
15+
//~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
16+
//~| HELP a writer is needed before this format string
17+
}

Diff for: tests/ui/macros/missing-writer.stderr

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: format argument must be a string literal
2+
--> $DIR/missing-writer.rs:5:21
3+
|
4+
LL | write!("{}_{}", x, y);
5+
| ^
6+
|
7+
help: you might be missing a string literal to format with
8+
|
9+
LL | write!("{}_{}", "{} {}", x, y);
10+
| ++++++++
11+
12+
error: format argument must be a string literal
13+
--> $DIR/missing-writer.rs:11:23
14+
|
15+
LL | writeln!("{}_{}", x, y);
16+
| ^
17+
|
18+
help: you might be missing a string literal to format with
19+
|
20+
LL | writeln!("{}_{}", "{} {}", x, y);
21+
| ++++++++
22+
23+
error[E0599]: cannot write into `&'static str`
24+
--> $DIR/missing-writer.rs:5:12
25+
|
26+
LL | write!("{}_{}", x, y);
27+
| -------^^^^^^^------- method not found in `&str`
28+
|
29+
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
30+
--> $DIR/missing-writer.rs:5:12
31+
|
32+
LL | write!("{}_{}", x, y);
33+
| ^^^^^^^
34+
help: a writer is needed before this format string
35+
--> $DIR/missing-writer.rs:5:12
36+
|
37+
LL | write!("{}_{}", x, y);
38+
| ^
39+
40+
error[E0599]: cannot write into `&'static str`
41+
--> $DIR/missing-writer.rs:11:14
42+
|
43+
LL | writeln!("{}_{}", x, y);
44+
| ---------^^^^^^^------- method not found in `&str`
45+
|
46+
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
47+
--> $DIR/missing-writer.rs:11:14
48+
|
49+
LL | writeln!("{}_{}", x, y);
50+
| ^^^^^^^
51+
help: a writer is needed before this format string
52+
--> $DIR/missing-writer.rs:11:14
53+
|
54+
LL | writeln!("{}_{}", x, y);
55+
| ^
56+
57+
error: aborting due to 4 previous errors
58+
59+
For more information about this error, try `rustc --explain E0599`.

Diff for: tests/ui/suggestions/mut-borrow-needed-by-trait.stderr

+7-3
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,22 @@ note: required by a bound in `BufWriter`
2121
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
2222

2323
error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
24-
--> $DIR/mut-borrow-needed-by-trait.rs:21:5
24+
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
2525
|
2626
LL | writeln!(fp, "hello world").unwrap();
27-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
27+
| ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
2828
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
2929
|
3030
= note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
3131
|
32+
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
33+
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
34+
|
35+
LL | writeln!(fp, "hello world").unwrap();
36+
| ^^
3237
= note: the following trait bounds were not satisfied:
3338
`&dyn std::io::Write: std::io::Write`
3439
which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
35-
= note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
3640

3741
error: aborting due to 3 previous errors
3842

0 commit comments

Comments
 (0)