Auto merge of #112043 - jieyouxu:suggestion_macro_expansion_source_callsites, r=cjgillot

Fix suggestion spans for expr from macro expansions

### Issue #112007: rustc shows expanded `writeln!` macro in code suggestion

#### Before This PR

```
help: consider using a semicolon here
  |
6 |     };
  |      +
help: you might have meant to return this value
 --> C:\Users\hayle\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\macros\mod.rs:557:9
  |
55|         return $dst.write_fmt($crate::format_args_nl!($($arg)*));
  |         ++++++                                                  +
```

#### After This PR

```
help: consider using a semicolon here
   |
LL |     };
   |      +
help: you might have meant to return this value
   |
LL |         return writeln!(w, "but not here");
   |         ++++++                            +
```

### Issue #110017: `format!` `.into()` suggestion deletes the `format` macro

#### Before This PR

```
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
 --> /Users/eric/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/macros.rs:121:12
  |
12|         res.into()
  |            +++++++
```

#### After This PR

```
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
   |
LL |     Err(format!("error: {x}").into())
   |                              +++++++
```

---

Fixes #112007.
Fixes #110017.
This commit is contained in:
bors 2023-08-03 10:01:16 +00:00
commit c115ec11d2
7 changed files with 314 additions and 10 deletions

View File

@ -994,14 +994,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let ty = self.normalize(expr.span, ty);
if self.can_coerce(found, ty) {
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,
);
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,
);
}
}
}
}
@ -1185,10 +1190,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
))
{
let mut span = expr.span;
while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite()
{
span = parent_callsite;
}
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else {
vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())]
};
diag.multipart_suggestion(
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),

View File

@ -0,0 +1,55 @@
// 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() {}

View File

@ -0,0 +1,55 @@
// 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() {}

View File

@ -0,0 +1,59 @@
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`.

View File

@ -0,0 +1,37 @@
// 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() {}

View File

@ -0,0 +1,37 @@
// 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() {}

View File

@ -0,0 +1,50 @@
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`.