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)) {
   |            ++          +
```
This commit is contained in:
Esteban Küber 2023-12-20 01:03:05 +00:00
parent 0487500776
commit 8551cab7b7
3 changed files with 56 additions and 8 deletions

View File

@ -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 {

View File

@ -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() {}

View File

@ -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`.