Skip to content

Commit c115ec1

Browse files
committed
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.
2 parents a922d1c + 25d065b commit c115ec1

7 files changed

+314
-10
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+21-10
Original file line numberDiff line numberDiff line change
@@ -994,14 +994,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
994994
};
995995
let ty = self.normalize(expr.span, ty);
996996
if self.can_coerce(found, ty) {
997-
err.multipart_suggestion(
998-
"you might have meant to return this value",
999-
vec![
1000-
(expr.span.shrink_to_lo(), "return ".to_string()),
1001-
(expr.span.shrink_to_hi(), ";".to_string()),
1002-
],
1003-
Applicability::MaybeIncorrect,
1004-
);
997+
if let Some(node) = self.tcx.hir().find(fn_id)
998+
&& let Some(owner_node) = node.as_owner()
999+
&& let Some(span) = expr.span.find_ancestor_inside(owner_node.span())
1000+
{
1001+
err.multipart_suggestion(
1002+
"you might have meant to return this value",
1003+
vec![
1004+
(span.shrink_to_lo(), "return ".to_string()),
1005+
(span.shrink_to_hi(), ";".to_string()),
1006+
],
1007+
Applicability::MaybeIncorrect,
1008+
);
1009+
}
10051010
}
10061011
}
10071012
}
@@ -1185,10 +1190,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11851190
),
11861191
))
11871192
{
1193+
let mut span = expr.span;
1194+
while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite()
1195+
{
1196+
span = parent_callsite;
1197+
}
1198+
11881199
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
1189-
vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
1200+
vec![(span.shrink_to_hi(), ".into()".to_owned())]
11901201
} else {
1191-
vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
1202+
vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())]
11921203
};
11931204
diag.multipart_suggestion(
11941205
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> {
5+
Err(format!("error: {x}").into())
6+
//~^ ERROR mismatched types
7+
}
8+
9+
macro_rules! outer {
10+
($x: expr) => {
11+
inner!($x)
12+
}
13+
}
14+
15+
macro_rules! inner {
16+
($x: expr) => {
17+
format!("error: {}", $x).into()
18+
//~^ ERROR mismatched types
19+
}
20+
}
21+
22+
fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
23+
Err(outer!(x))
24+
}
25+
26+
macro_rules! entire_fn_outer {
27+
() => {
28+
entire_fn!();
29+
}
30+
}
31+
32+
macro_rules! entire_fn {
33+
() => {
34+
pub fn baz(x: &str) -> Result<(), Box<dyn std::error::Error>> {
35+
Err(format!("error: {x}").into())
36+
//~^ ERROR mismatched types
37+
}
38+
}
39+
}
40+
41+
entire_fn_outer!();
42+
43+
macro_rules! nontrivial {
44+
($x: expr) => {
45+
Err(format!("error: {}", $x).into())
46+
//~^ ERROR mismatched types
47+
}
48+
}
49+
50+
pub fn qux(x: &str) -> Result<(), Box<dyn std::error::Error>> {
51+
nontrivial!(x)
52+
}
53+
54+
55+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> {
5+
Err(format!("error: {x}"))
6+
//~^ ERROR mismatched types
7+
}
8+
9+
macro_rules! outer {
10+
($x: expr) => {
11+
inner!($x)
12+
}
13+
}
14+
15+
macro_rules! inner {
16+
($x: expr) => {
17+
format!("error: {}", $x)
18+
//~^ ERROR mismatched types
19+
}
20+
}
21+
22+
fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
23+
Err(outer!(x))
24+
}
25+
26+
macro_rules! entire_fn_outer {
27+
() => {
28+
entire_fn!();
29+
}
30+
}
31+
32+
macro_rules! entire_fn {
33+
() => {
34+
pub fn baz(x: &str) -> Result<(), Box<dyn std::error::Error>> {
35+
Err(format!("error: {x}"))
36+
//~^ ERROR mismatched types
37+
}
38+
}
39+
}
40+
41+
entire_fn_outer!();
42+
43+
macro_rules! nontrivial {
44+
($x: expr) => {
45+
Err(format!("error: {}", $x))
46+
//~^ ERROR mismatched types
47+
}
48+
}
49+
50+
pub fn qux(x: &str) -> Result<(), Box<dyn std::error::Error>> {
51+
nontrivial!(x)
52+
}
53+
54+
55+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-110017-format-into-help-deletes-macro.rs:5:10
3+
|
4+
LL | Err(format!("error: {x}"))
5+
| ^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String`
6+
|
7+
= note: expected struct `Box<dyn std::error::Error>`
8+
found struct `String`
9+
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
10+
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
11+
|
12+
LL | Err(format!("error: {x}").into())
13+
| +++++++
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/issue-110017-format-into-help-deletes-macro.rs:23:10
17+
|
18+
LL | Err(outer!(x))
19+
| ^^^^^^^^^ expected `Box<dyn Error>`, found `String`
20+
|
21+
= note: expected struct `Box<dyn std::error::Error>`
22+
found struct `String`
23+
= 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)
24+
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
25+
|
26+
LL | format!("error: {}", $x).into()
27+
| +++++++
28+
29+
error[E0308]: mismatched types
30+
--> $DIR/issue-110017-format-into-help-deletes-macro.rs:41:2
31+
|
32+
LL | entire_fn_outer!();
33+
| ^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String`
34+
|
35+
= note: expected struct `Box<dyn std::error::Error>`
36+
found struct `String`
37+
= 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)
38+
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
39+
|
40+
LL | Err(format!("error: {x}").into())
41+
| +++++++
42+
43+
error[E0308]: mismatched types
44+
--> $DIR/issue-110017-format-into-help-deletes-macro.rs:51:5
45+
|
46+
LL | nontrivial!(x)
47+
| ^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String`
48+
|
49+
= note: expected struct `Box<dyn std::error::Error>`
50+
found struct `String`
51+
= 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)
52+
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
53+
|
54+
LL | Err(format!("error: {}", $x).into())
55+
| +++++++
56+
57+
error: aborting due to 4 previous errors
58+
59+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
// https://github.com/rust-lang/rust/issues/112007
5+
fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
6+
if true {
7+
writeln!(w, "`;?` here ->")?;
8+
} else {
9+
return writeln!(w, "but not here");
10+
//~^ ERROR mismatched types
11+
};
12+
Ok(())
13+
}
14+
15+
macro_rules! baz {
16+
($w: expr) => {
17+
bar!($w)
18+
}
19+
}
20+
21+
macro_rules! bar {
22+
($w: expr) => {
23+
writeln!($w, "but not here")
24+
//~^ ERROR mismatched types
25+
}
26+
}
27+
28+
fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
29+
if true {
30+
writeln!(w, "`;?` here ->")?;
31+
} else {
32+
return baz!(w);
33+
};
34+
Ok(())
35+
}
36+
37+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
// https://github.com/rust-lang/rust/issues/112007
5+
fn bug_report<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
6+
if true {
7+
writeln!(w, "`;?` here ->")?;
8+
} else {
9+
writeln!(w, "but not here")
10+
//~^ ERROR mismatched types
11+
}
12+
Ok(())
13+
}
14+
15+
macro_rules! baz {
16+
($w: expr) => {
17+
bar!($w)
18+
}
19+
}
20+
21+
macro_rules! bar {
22+
($w: expr) => {
23+
writeln!($w, "but not here")
24+
//~^ ERROR mismatched types
25+
}
26+
}
27+
28+
fn foo<W: std::fmt::Write>(w: &mut W) -> std::fmt::Result {
29+
if true {
30+
writeln!(w, "`;?` here ->")?;
31+
} else {
32+
baz!(w)
33+
}
34+
Ok(())
35+
}
36+
37+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9
3+
|
4+
LL | / if true {
5+
LL | | writeln!(w, "`;?` here ->")?;
6+
LL | | } else {
7+
LL | | writeln!(w, "but not here")
8+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>`
9+
LL | |
10+
LL | | }
11+
| |_____- expected this to be `()`
12+
|
13+
= note: expected unit type `()`
14+
found enum `Result<(), std::fmt::Error>`
15+
= note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
16+
help: consider using a semicolon here
17+
|
18+
LL | };
19+
| +
20+
help: you might have meant to return this value
21+
|
22+
LL | return writeln!(w, "but not here");
23+
| ++++++ +
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9
27+
|
28+
LL | / if true {
29+
LL | | writeln!(w, "`;?` here ->")?;
30+
LL | | } else {
31+
LL | | baz!(w)
32+
| | ^^^^^^^ expected `()`, found `Result<(), Error>`
33+
LL | | }
34+
| |_____- expected this to be `()`
35+
|
36+
= note: expected unit type `()`
37+
found enum `Result<(), std::fmt::Error>`
38+
= 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)
39+
help: consider using a semicolon here
40+
|
41+
LL | };
42+
| +
43+
help: you might have meant to return this value
44+
|
45+
LL | return baz!(w);
46+
| ++++++ +
47+
48+
error: aborting due to 2 previous errors
49+
50+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)