about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2024-09-26 17:26:05 -0700
committerMichael Howell <michael@notriddle.com>2024-09-26 18:17:52 -0700
commitc48b0d4eb404f856f8bf1d305818ce21cc125fc5 (patch)
tree586c0a383d83b62c50f929a688435f66cadb12ad
parent2bd1e894efde3b6be857ad345914a3b1cea51def (diff)
downloadrust-c48b0d4eb404f856f8bf1d305818ce21cc125fc5.tar.gz
rust-c48b0d4eb404f856f8bf1d305818ce21cc125fc5.zip
diagnostics: wrap fn cast suggestions in parens
Fixes #121632
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs29
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs (renamed from tests/ui/traits/issue-99875.rs)0
-rw-r--r--tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr (renamed from tests/ui/traits/issue-99875.stderr)12
-rw-r--r--tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.rs (renamed from tests/ui/traits/fn-trait-cast-diagnostic.rs)0
-rw-r--r--tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.stderr (renamed from tests/ui/traits/fn-trait-cast-diagnostic.stderr)0
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed15
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs15
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr19
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed10
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens.rs10
-rw-r--r--tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr15
12 files changed, 115 insertions, 11 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 19e2679ae4d..de95e32de10 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -33,7 +33,8 @@ use tracing::{debug, instrument};
 use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
 use super::suggestions::get_explanation_based_on_obligation;
 use super::{
-    ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
+    ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate,
+    UnsatisfiedConst,
 };
 use crate::error_reporting::TypeErrCtxt;
 use crate::error_reporting::infer::TyCategory;
@@ -378,14 +379,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             if let (ty::FnPtr(..), ty::FnDef(..)) =
                                 (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
                             {
-                                err.span_suggestion(
-                                    span.shrink_to_hi(),
+                                // Wrap method receivers and `&`-references in parens
+                                let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
+                                    vec![
+                                        (span.shrink_to_lo(), format!("(")),
+                                        (span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
+                                    ]
+                                } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
+                                    let mut expr_finder = FindExprBySpan::new(span, self.tcx);
+                                    expr_finder.visit_expr(body.value);
+                                    if let Some(expr) = expr_finder.result &&
+                                        let hir::ExprKind::AddrOf(_, _, expr) = expr.kind {
+                                        vec![
+                                            (expr.span.shrink_to_lo(), format!("(")),
+                                            (expr.span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
+                                        ]
+                                    } else {
+                                        vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
+                                    }
+                                } else {
+                                    vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
+                                };
+                                err.multipart_suggestion(
                                     format!(
                                         "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
                                         cand.print_trait_sugared(),
                                         cand.self_ty(),
                                     ),
-                                    format!(" as {}", cand.self_ty()),
+                                    suggestion,
                                     Applicability::MaybeIncorrect,
                                 );
                                 true
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 6b4c0e9c0b9..2071abefbe1 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -4076,7 +4076,6 @@ ui/traits/issue-96664.rs
 ui/traits/issue-96665.rs
 ui/traits/issue-97576.rs
 ui/traits/issue-97695-double-trivial-bound.rs
-ui/traits/issue-99875.rs
 ui/traits/next-solver/coherence/issue-102048.rs
 ui/traits/next-solver/issue-118950-root-region.rs
 ui/traits/object/issue-33140-traitobject-crate.rs
diff --git a/tests/ui/traits/issue-99875.rs b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs
index cf73fd8d31f..cf73fd8d31f 100644
--- a/tests/ui/traits/issue-99875.rs
+++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs
diff --git a/tests/ui/traits/issue-99875.stderr b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr
index 29e87571561..0666da4c707 100644
--- a/tests/ui/traits/issue-99875.stderr
+++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
-  --> $DIR/issue-99875.rs:12:11
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:12:11
    |
 LL |     takes(function);
    |     ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
@@ -7,7 +7,7 @@ LL |     takes(function);
    |     required by a bound introduced by this call
    |
 note: required by a bound in `takes`
-  --> $DIR/issue-99875.rs:9:18
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
@@ -16,17 +16,17 @@ help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`,
 LL |     takes(function as fn(Argument) -> Return);
    |                    +++++++++++++++++++++++++
 
-error[E0277]: the trait bound `{closure@$DIR/issue-99875.rs:14:11: 14:34}: Trait` is not satisfied
-  --> $DIR/issue-99875.rs:14:11
+error[E0277]: the trait bound `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}: Trait` is not satisfied
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11
    |
 LL |     takes(|_: Argument| -> Return { todo!() });
-   |     ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `{closure@$DIR/issue-99875.rs:14:11: 14:34}`
+   |     ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}`
    |     |
    |     required by a bound introduced by this call
    |
    = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
 note: required by a bound in `takes`
-  --> $DIR/issue-99875.rs:9:18
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.rs b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.rs
index e20aa210e58..e20aa210e58 100644
--- a/tests/ui/traits/fn-trait-cast-diagnostic.rs
+++ b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.rs
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.stderr b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.stderr
index 6851dcdd504..6851dcdd504 100644
--- a/tests/ui/traits/fn-trait-cast-diagnostic.stderr
+++ b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.stderr
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed
new file mode 100644
index 00000000000..e54963d01e8
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed
@@ -0,0 +1,15 @@
+//@ run-rustfix
+
+trait Foo {}
+
+impl Foo for fn() {}
+
+trait Bar {
+    fn do_stuff(&self) where Self: Foo {}
+}
+impl<T> Bar for T {}
+
+fn main() {
+    (main as fn()).do_stuff();
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs
new file mode 100644
index 00000000000..89c1295613c
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs
@@ -0,0 +1,15 @@
+//@ run-rustfix
+
+trait Foo {}
+
+impl Foo for fn() {}
+
+trait Bar {
+    fn do_stuff(&self) where Self: Foo {}
+}
+impl<T> Bar for T {}
+
+fn main() {
+    main.do_stuff();
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr
new file mode 100644
index 00000000000..2fc1523a193
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `fn() {main}: Foo` is not satisfied
+  --> $DIR/suggest-wrap-parens-method.rs:13:10
+   |
+LL |     main.do_stuff();
+   |          ^^^^^^^^ the trait `Foo` is not implemented for fn item `fn() {main}`
+   |
+note: required by a bound in `Bar::do_stuff`
+  --> $DIR/suggest-wrap-parens-method.rs:8:36
+   |
+LL |     fn do_stuff(&self) where Self: Foo {}
+   |                                    ^^^ required by this bound in `Bar::do_stuff`
+help: the trait `Foo` is implemented for fn pointer `fn()`, try casting using `as`
+   |
+LL |     (main as fn()).do_stuff();
+   |     +     ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed b/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed
new file mode 100644
index 00000000000..0bc8792b04e
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed
@@ -0,0 +1,10 @@
+//@ run-rustfix
+
+trait Foo {}
+
+impl Foo for fn() {}
+
+fn main() {
+    let _x: &dyn Foo = &(main as fn());
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs b/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs
new file mode 100644
index 00000000000..ffe0826c035
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs
@@ -0,0 +1,10 @@
+//@ run-rustfix
+
+trait Foo {}
+
+impl Foo for fn() {}
+
+fn main() {
+    let _x: &dyn Foo = &main;
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr b/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr
new file mode 100644
index 00000000000..b71debac715
--- /dev/null
+++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `fn() {main}: Foo` is not satisfied
+  --> $DIR/suggest-wrap-parens.rs:8:24
+   |
+LL |     let _x: &dyn Foo = &main;
+   |                        ^^^^^ the trait `Foo` is not implemented for fn item `fn() {main}`
+   |
+   = note: required for the cast from `&fn() {main}` to `&dyn Foo`
+help: the trait `Foo` is implemented for fn pointer `fn()`, try casting using `as`
+   |
+LL |     let _x: &dyn Foo = &(main as fn());
+   |                         +     ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.