about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs42
-rw-r--r--tests/ui/suggestions/issue-104961.fixed16
-rw-r--r--tests/ui/suggestions/issue-104961.rs16
-rw-r--r--tests/ui/suggestions/issue-104961.stderr37
4 files changed, 104 insertions, 7 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 91da690a000..8ece53dd05c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -19,6 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_hir::{Expr, HirId};
@@ -1350,14 +1351,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
+                        // Issue #104961, we need to add parentheses properly for compond expressions
+                        // for example, `x.starts_with("hi".to_string() + "you")`
+                        // should be `x.starts_with(&("hi".to_string() + "you"))`
+                        let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; };
+                        let body = self.tcx.hir().body(body_id);
+                        let mut expr_finder = FindExprBySpan::new(span);
+                        expr_finder.visit_expr(body.value);
+                        let Some(expr) = expr_finder.result else { return false; };
+                        let needs_parens = match expr.kind {
+                            // parenthesize if needed (Issue #46756)
+                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+                            // parenthesize borrows of range literals (Issue #54505)
+                            _ if is_range_literal(expr) => true,
+                            _ => false,
+                        };
+
                         let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
-                        err.span_suggestion_verbose(
-                            span.shrink_to_lo(),
-                            &format!(
-                                "consider{} borrowing here",
-                                if is_mut { " mutably" } else { "" }
-                            ),
-                            format!("&{}", if is_mut { "mut " } else { "" }),
+                        let span = if needs_parens { span } else { span.shrink_to_lo() };
+                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
+                        let sugg_msg = &format!(
+                            "consider{} borrowing here",
+                            if is_mut { " mutably" } else { "" }
+                        );
+
+                        let suggestions = if !needs_parens {
+                            vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
+                        } else {
+                            vec![
+                                (span.shrink_to_lo(), format!("{}(", sugg_prefix)),
+                                (span.shrink_to_hi(), ")".to_string()),
+                            ]
+                        };
+                        err.multipart_suggestion_verbose(
+                            sugg_msg,
+                            suggestions,
                             Applicability::MaybeIncorrect,
                         );
                     }
diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed
new file mode 100644
index 00000000000..520d638b174
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+fn foo(x: &str) -> bool {
+    x.starts_with(&("hi".to_string() + " you"))
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn foo2(x: &str) -> bool {
+    x.starts_with(&"hi".to_string())
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn main() {
+    foo("hi you");
+    foo2("hi");
+}
diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs
new file mode 100644
index 00000000000..aeb787abb6f
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+fn foo(x: &str) -> bool {
+    x.starts_with("hi".to_string() + " you")
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn foo2(x: &str) -> bool {
+    x.starts_with("hi".to_string())
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn main() {
+    foo("hi you");
+    foo2("hi");
+}
diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr
new file mode 100644
index 00000000000..8cec6a3f827
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.stderr
@@ -0,0 +1,37 @@
+error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
+  --> $DIR/issue-104961.rs:4:19
+   |
+LL |     x.starts_with("hi".to_string() + " you")
+   |       ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = note: the trait bound `String: Pattern<'_>` is not satisfied
+   = note: required for `String` to implement `Pattern<'_>`
+note: required by a bound in `core::str::<impl str>::starts_with`
+  --> $SRC_DIR/core/src/str/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     x.starts_with(&("hi".to_string() + " you"))
+   |                   ++                         +
+
+error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
+  --> $DIR/issue-104961.rs:9:19
+   |
+LL |     x.starts_with("hi".to_string())
+   |       ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = note: the trait bound `String: Pattern<'_>` is not satisfied
+   = note: required for `String` to implement `Pattern<'_>`
+note: required by a bound in `core::str::<impl str>::starts_with`
+  --> $SRC_DIR/core/src/str/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     x.starts_with(&"hi".to_string())
+   |                   +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.