Skip to content

Commit

Permalink
Account for multiple trait bounds in bare trait object suggestion
Browse files Browse the repository at this point in the history
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)) {
   |            ++          +
```
  • Loading branch information
estebank committed Dec 20, 2023
1 parent eb4b2e9 commit fd1006e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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<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 {
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/traits/bound/not-on-bare-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
21 changes: 19 additions & 2 deletions tests/ui/traits/bound/not-on-bare-trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

0 comments on commit fd1006e

Please sign in to comment.