about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2023-12-20 01:03:05 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-01-03 18:59:42 +0000
commit8551cab7b75ab8f9c51b1d5a847031093b79b546 (patch)
tree634b99c6f69f3ffb1cc0a8f075c5e75548605782
parent048750077676190a0733112d8f700e76a0553f60 (diff)
downloadrust-8551cab7b75ab8f9c51b1d5a847031093b79b546.tar.gz
rust-8551cab7b75ab8f9c51b1d5a847031093b79b546.zip
Account for multiple trait bounds in bare trait object suggestion
Note the parentheses in the last suggestion:

```
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
  --> $DIR/not-on-bare-trait.rs:7:8
   |
LL | fn foo(_x: Foo + Send) {
   |        ^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
   = help: unsized fn params are gated as an unstable feature
help: you can use `impl Trait` as the argument type
   |
LL | fn foo(_x: impl Foo + Send) {
   |            ++++
help: function arguments must have a statically known size, borrowed types always have a known size
   |
LL | fn foo(_x: &(Foo + Send)) {
   |            ++          +
```
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs40
-rw-r--r--tests/ui/traits/bound/not-on-bare-trait.rs3
-rw-r--r--tests/ui/traits/bound/not-on-bare-trait.stderr21
3 files changed, 56 insertions, 8 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 f63314081d6..b768108e24c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3202,9 +3202,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ObligationCauseCode::SizedArgumentType(ty_span) => {
                 if let Some(span) = ty_span {
-                    if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+                    let trait_len = if let ty::PredicateKind::Clause(clause) =
+                        predicate.kind().skip_binder()
                         && let ty::ClauseKind::Trait(trait_pred) = clause
-                        && let ty::Dynamic(..) = trait_pred.self_ty().kind()
+                        && let ty::Dynamic(preds, ..) = trait_pred.self_ty().kind()
                     {
                         let span = if let Ok(snippet) =
                             self.tcx.sess.source_map().span_to_snippet(span)
@@ -3221,12 +3222,39 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             "impl ".to_string(),
                             Applicability::MaybeIncorrect,
                         );
-                    }
-                    err.span_suggestion_verbose(
-                        span.shrink_to_lo(),
+                        preds
+                            .iter()
+                            .filter(|pred| {
+                                // We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
+                                // because the later doesn't need parentheses.
+                                matches!(
+                                    pred.skip_binder(),
+                                    ty::ExistentialPredicate::Trait(_)
+                                        | ty::ExistentialPredicate::AutoTrait(_)
+                                )
+                            })
+                            .count()
+                    } else {
+                        1
+                    };
+                    let sugg = if trait_len == 1 {
+                        vec![(span.shrink_to_lo(), "&".to_string())]
+                    } else if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+                        && snippet.starts_with('(')
+                    {
+                        // We don't want to suggest `&((dyn Foo + Bar))` when we have
+                        // `(dyn Foo + Bar)`.
+                        vec![(span.shrink_to_lo(), "&".to_string())]
+                    } else {
+                        vec![
+                            (span.shrink_to_lo(), "&(".to_string()),
+                            (span.shrink_to_hi(), ")".to_string()),
+                        ]
+                    };
+                    err.multipart_suggestion_verbose(
                         "function arguments must have a statically known size, borrowed types \
                          always have a known size",
-                        "&",
+                        sugg,
                         Applicability::MachineApplicable,
                     );
                 } else {
diff --git a/tests/ui/traits/bound/not-on-bare-trait.rs b/tests/ui/traits/bound/not-on-bare-trait.rs
index daf18c6702e..9e717f3c045 100644
--- a/tests/ui/traits/bound/not-on-bare-trait.rs
+++ b/tests/ui/traits/bound/not-on-bare-trait.rs
@@ -9,5 +9,8 @@ fn foo(_x: Foo + Send) {
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
 }
+fn bar(_x: (dyn Foo + Send)) {
+    //~^ ERROR the size for values of type
+}
 
 fn main() {}
diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr
index 976dd6a1bc5..edb6b1d934b 100644
--- a/tests/ui/traits/bound/not-on-bare-trait.stderr
+++ b/tests/ui/traits/bound/not-on-bare-trait.stderr
@@ -34,9 +34,26 @@ LL | fn foo(_x: impl Foo + Send) {
    |            ++++
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
-LL | fn foo(_x: &Foo + Send) {
+LL | fn foo(_x: &(Foo + Send)) {
+   |            ++          +
+
+error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
+  --> $DIR/not-on-bare-trait.rs:12:8
+   |
+LL | fn bar(_x: (dyn Foo + Send)) {
+   |        ^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
+   = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn bar(_x: impl (dyn Foo + Send)) {
+   |            ++++
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn bar(_x: &(dyn Foo + Send)) {
    |            +
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0277`.