Change:
The suggestion converts the code to: which is invalid. It should suggest: The suggestion works correctly for non-macro string values. This suggestion was introduced in . No response
It cannot be reproduced on .
I'm able to reproduce it locally. It seems to be suggesting a change in : (note the path) I assume that this is due to macro expansion. It might not be working on the playground because the playground doesn't have the component installed but that's a total guess.
The presence of only affects the human-readable rendering. The important part to me is the JSON output which has even without rust-src. Ideally it would be something closer to what it looks like with :
It seems to affect all macro expansions ():
Is the solution to just disable this suggestion for macro-expanded code? As an aside, perhaps the playground should get , especially because of its prevalence in sharing code which might need the additional context.
I think it's possible to achieve the desired output found in the description, although I'm not sure how exactly. Typically, you would use on the span to peel away the layers of macro invocations, though for that you would need to provide a parent to mark the end of the chain. doesn't need such a stopper but here its use would be incorrect if the macro call itself (e.g. ) was inside of a macro expansion. Since we don't have a parent (afaiaa), earlier I briefly tried to create a parent for via I think but that didn't work. Maybe could work, not sure. This approach is a catch-22 I believe.
Yeah, would that be the desired solution though? Can this be generalized to all the other type mismatch suggestions?
That's a good question. It was mostly an experiment to see if this specific issue can be solved with .

Discussion:
}; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { <del> err.multipart_suggestion( "you might have meant to return this value", vec![ (expr.span.shrink_to_lo(), "return ".to_string()), (expr.span.shrink_to_hi(), ";".to_string()), ], Applicability::MaybeIncorrect, ); </del> <ins> if let Some(node) = self.tcx.hir().find(fn_id) && let Some(owner_node) = node.as_owner() && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) { err.multipart_suggestion( "you might have meant to return this value", vec![ (span.shrink_to_lo(), "return ".to_string()), (span.shrink_to_hi(), ";".to_string()), ], Applicability::MaybeIncorrect, ); } </ins> } } }

), )) { <ins> let mut span = expr.span; while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() { span = parent_callsite; } </ins> let sugg = if expr.precedence().order() >= PREC_POSTFIX { <del> vec![(expr.span.shrink_to_hi(), ".into()".to_owned())] </del> <ins> vec![(span.shrink_to_hi(), ".into()".to_owned())] </ins> } else { <del> vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())] </del> <ins> vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())] </ins> }; diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),

<ins> // run-rustfix #![allow(dead_code)] pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(format!("error: {x}").into()) //~^ ERROR mismatched types } macro_rules! outer { ($x: expr) => { inner!($x) } } macro_rules! inner { ($x: expr) => { format!("error: {}", $x).into() //~^ ERROR mismatched types } } fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(outer!(x)) } macro_rules! entire_fn_outer { () => { entire_fn!(); } } macro_rules! entire_fn { () => { pub fn baz(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(format!("error: {x}").into()) //~^ ERROR mismatched types } } } entire_fn_outer!(); macro_rules! nontrivial { ($x: expr) => { Err(format!("error: {}", $x).into()) //~^ ERROR mismatched types } } pub fn qux(x: &str) -> Result<(), Box<dyn std::error::Error>> { nontrivial!(x) } fn main() {} </ins>

<ins> // run-rustfix #![allow(dead_code)] pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(format!("error: {x}")) //~^ ERROR mismatched types } macro_rules! outer { ($x: expr) => { inner!($x) } } macro_rules! inner { ($x: expr) => { format!("error: {}", $x) //~^ ERROR mismatched types } } fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(outer!(x)) } macro_rules! entire_fn_outer { () => { entire_fn!(); } } macro_rules! entire_fn { () => { pub fn baz(x: &str) -> Result<(), Box<dyn std::error::Error>> { Err(format!("error: {x}")) //~^ ERROR mismatched types } } } entire_fn_outer!(); macro_rules! nontrivial { ($x: expr) => { Err(format!("error: {}", $x)) //~^ ERROR mismatched types } } pub fn qux(x: &str) -> Result<(), Box<dyn std::error::Error>> { nontrivial!(x) } fn main() {} </ins>

<ins> error[E0308]: mismatched types --> $DIR/issue-110017-format-into-help-deletes-macro.rs:5:10 | LL |      Err(format!("error: {x}")) |          ^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String` | = note: expected struct `Box<dyn std::error::Error>` found struct `String` = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>` | LL |      Err(format!("error: {x}").into()) |                               +++++++ error[E0308]: mismatched types --> $DIR/issue-110017-format-into-help-deletes-macro.rs:23:10 | LL |      Err(outer!(x)) |          ^^^^^^^^^ expected `Box<dyn Error>`, found `String` | = note: expected struct `Box<dyn std::error::Error>` found struct `String` = note: this error originates in the macro `format` which comes from the expansion of the macro `outer` (in Nightly builds, run with -Z macro-backtrace for more info) help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>` | LL |          format!("error: {}", $x).into() |                                  +++++++ error[E0308]: mismatched types --> $DIR/issue-110017-format-into-help-deletes-macro.rs:41:2 | LL |  entire_fn_outer!(); |  ^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String` | = note: expected struct `Box<dyn std::error::Error>` found struct `String` = note: this error originates in the macro `format` which comes from the expansion of the macro `entire_fn_outer` (in Nightly builds, run with -Z macro-backtrace for more info) help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>` | LL |              Err(format!("error: {x}").into()) |                                       +++++++ error[E0308]: mismatched types --> $DIR/issue-110017-format-into-help-deletes-macro.rs:51:5 | LL |     nontrivial!(x) |     ^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String` | = note: expected struct `Box<dyn std::error::Error>` found struct `String` = note: this error originates in the macro `format` which comes from the expansion of the macro `nontrivial` (in Nightly builds, run with -Z macro-backtrace for more info) help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>` | LL |         Err(format!("error: {}", $x).into()) |                                     +++++++ error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. </ins>

<ins> // run-rustfix #![allow(dead_code)] // https://github.com/rust-lang/rust/issues/112007 fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { return writeln!(w, "but not here"); //~^ ERROR mismatched types }; Ok(()) } macro_rules! baz { ($w: expr) => { bar!($w) } } macro_rules! bar { ($w: expr) => { writeln!($w, "but not here") //~^ ERROR mismatched types } } fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { return baz!(w); }; Ok(()) } fn main() {} </ins>

<ins> // run-rustfix #![allow(dead_code)] // https://github.com/rust-lang/rust/issues/112007 fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { writeln!(w, "but not here") //~^ ERROR mismatched types } Ok(()) } macro_rules! baz { ($w: expr) => { bar!($w) } } macro_rules! bar { ($w: expr) => { writeln!($w, "but not here") //~^ ERROR mismatched types } } fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { baz!(w) } Ok(()) } fn main() {} </ins>

<ins> error[E0308]: mismatched types --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9 | LL | /     if true { LL | |         writeln!(w, "`;?` here ->")?; LL | |     } else { LL | |         writeln!(w, "but not here") | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` LL | | LL | |     } | |_____- expected this to be `()` | = note: expected unit type `()` found enum `Result<(), std::fmt::Error>` = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a semicolon here | LL |     }; |      + help: you might have meant to return this value | LL |         return writeln!(w, "but not here"); |         ++++++                            + error[E0308]: mismatched types --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9 | LL | /     if true { LL | |         writeln!(w, "`;?` here ->")?; LL | |     } else { LL | |         baz!(w) | |         ^^^^^^^ expected `()`, found `Result<(), Error>` LL | |     } | |_____- expected this to be `()` | = note: expected unit type `()` found enum `Result<(), std::fmt::Error>` = note: this error originates in the macro `writeln` which comes from the expansion of the macro `baz` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a semicolon here | LL |     }; |      + help: you might have meant to return this value | LL |         return baz!(w); |         ++++++        + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. </ins>