about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs31
-rw-r--r--tests/ui/typeck/issue-110017-format-into-help-deletes-macro.fixed55
-rw-r--r--tests/ui/typeck/issue-110017-format-into-help-deletes-macro.rs55
-rw-r--r--tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr59
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed37
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs37
-rw-r--r--tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr50
7 files changed, 314 insertions, 10 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3a4fe334f88..6022839fe89 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 00000000000..b101cf1dcf5
--- /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<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() {}
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 00000000000..cfde912d896
--- /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<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() {}
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 00000000000..e4834c0308b
--- /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<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`.
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 00000000000..29b6b8b868f
--- /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: 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() {}
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 00000000000..bd731e02bd1
--- /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: 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() {}
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 00000000000..df2e06e8f3b
--- /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`.