From 25d065b2d476053102b05bbd5c4650a86ddc2c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 27 May 2023 15:43:26 +0800 Subject: [PATCH] Fix suggestions span for when expr is from macro expansions --- .../src/fn_ctxt/suggestions.rs | 31 ++++++---- ...10017-format-into-help-deletes-macro.fixed | 55 +++++++++++++++++ ...e-110017-format-into-help-deletes-macro.rs | 55 +++++++++++++++++ ...0017-format-into-help-deletes-macro.stderr | 59 +++++++++++++++++++ ...12007-leaked-writeln-macro-internals.fixed | 37 ++++++++++++ ...e-112007-leaked-writeln-macro-internals.rs | 37 ++++++++++++ ...2007-leaked-writeln-macro-internals.stderr | 50 ++++++++++++++++ 7 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs create mode 100644 tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs create mode 100644 tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3a4fe334f888a..6022839fe8945 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -982,14 +982,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, + ); + } } } } @@ -1177,10 +1182,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}`"), diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed new file mode 100644 index 0000000000000..b101cf1dcf57b --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed @@ -0,0 +1,55 @@ +// run-rustfix +#![allow(dead_code)] + + pub fn foo(x: &str) -> Result<(), Box> { + 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> { + Err(outer!(x)) + } + + macro_rules! entire_fn_outer { + () => { + entire_fn!(); + } + } + + macro_rules! entire_fn { + () => { + pub fn baz(x: &str) -> Result<(), Box> { + 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> { + nontrivial!(x) +} + + +fn main() {} diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs new file mode 100644 index 0000000000000..cfde912d8961e --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs @@ -0,0 +1,55 @@ +// run-rustfix +#![allow(dead_code)] + + pub fn foo(x: &str) -> Result<(), Box> { + 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> { + Err(outer!(x)) + } + + macro_rules! entire_fn_outer { + () => { + entire_fn!(); + } + } + + macro_rules! entire_fn { + () => { + pub fn baz(x: &str) -> Result<(), Box> { + 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> { + nontrivial!(x) +} + + +fn main() {} diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr new file mode 100644 index 0000000000000..e4834c0308bc8 --- /dev/null +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr @@ -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`, found `String` + | + = note: expected struct `Box` + 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` + | +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`, found `String` + | + = note: expected struct `Box` + 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` + | +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`, found `String` + | + = note: expected struct `Box` + 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` + | +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`, found `String` + | + = note: expected struct `Box` + 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` + | +LL | Err(format!("error: {}", $x).into()) + | +++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed new file mode 100644 index 0000000000000..29b6b8b868f56 --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +// https://github.com/rust-lang/rust/issues/112007 +fn bug_report(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: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + return baz!(w); + }; + Ok(()) +} + +fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs new file mode 100644 index 0000000000000..bd731e02bd1e9 --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] + +// https://github.com/rust-lang/rust/issues/112007 +fn bug_report(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: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + baz!(w) + } + Ok(()) +} + +fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr new file mode 100644 index 0000000000000..df2e06e8f3b76 --- /dev/null +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -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`.