From fd1006e014f08dfab9bddd260abe96b960227188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 20 Dec 2023 01:03:05 +0000 Subject: [PATCH] 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)) { | ++ + ``` --- .../src/traits/error_reporting/suggestions.rs | 40 ++++++++++++++++--- tests/ui/traits/bound/not-on-bare-trait.rs | 3 ++ .../ui/traits/bound/not-on-bare-trait.stderr | 21 +++++++++- 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 a1b896d225125..c13c2c598b075 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3031,9 +3031,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) @@ -3050,12 +3051,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`, + // 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 daf18c6702e46..9e717f3c045e3 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 976dd6a1bc532..edb6b1d934bd4 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`.