Skip to content

Commit 5e91e35

Browse files
committed
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)) { | ++ + ```
1 parent d3e5bfc commit 5e91e35

File tree

3 files changed

+56
-8
lines changed

3 files changed

+56
-8
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -3031,9 +3031,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30313031
}
30323032
ObligationCauseCode::SizedArgumentType(ty_span) => {
30333033
if let Some(span) = ty_span {
3034-
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
3034+
let trait_len = if let ty::PredicateKind::Clause(clause) =
3035+
predicate.kind().skip_binder()
30353036
&& let ty::ClauseKind::Trait(trait_pred) = clause
3036-
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
3037+
&& let ty::Dynamic(preds, ..) = trait_pred.self_ty().kind()
30373038
{
30383039
let span = if let Ok(snippet) =
30393040
self.tcx.sess.source_map().span_to_snippet(span)
@@ -3050,12 +3051,39 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30503051
"impl ".to_string(),
30513052
Applicability::MaybeIncorrect,
30523053
);
3053-
}
3054-
err.span_suggestion_verbose(
3055-
span.shrink_to_lo(),
3054+
preds
3055+
.iter()
3056+
.filter(|pred| {
3057+
// We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
3058+
// because the later doesn't need parentheses.
3059+
matches!(
3060+
pred.skip_binder(),
3061+
ty::ExistentialPredicate::Trait(_)
3062+
| ty::ExistentialPredicate::AutoTrait(_)
3063+
)
3064+
})
3065+
.count()
3066+
} else {
3067+
1
3068+
};
3069+
let sugg = if trait_len == 1 {
3070+
vec![(span.shrink_to_lo(), "&".to_string())]
3071+
} else if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3072+
&& snippet.starts_with('(')
3073+
{
3074+
// We don't want to suggest `&((dyn Foo + Bar))` when we have
3075+
// `(dyn Foo + Bar)`.
3076+
vec![(span.shrink_to_lo(), "&".to_string())]
3077+
} else {
3078+
vec![
3079+
(span.shrink_to_lo(), "&(".to_string()),
3080+
(span.shrink_to_hi(), ")".to_string()),
3081+
]
3082+
};
3083+
err.multipart_suggestion_verbose(
30563084
"function arguments must have a statically known size, borrowed types \
30573085
always have a known size",
3058-
"&",
3086+
sugg,
30593087
Applicability::MachineApplicable,
30603088
);
30613089
} else {

tests/ui/traits/bound/not-on-bare-trait.rs

+3
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ fn foo(_x: Foo + Send) {
99
//~| WARN trait objects without an explicit `dyn` are deprecated
1010
//~| WARN this is accepted in the current edition
1111
}
12+
fn bar(_x: (dyn Foo + Send)) {
13+
//~^ ERROR the size for values of type
14+
}
1215

1316
fn main() {}

tests/ui/traits/bound/not-on-bare-trait.stderr

+19-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,26 @@ LL | fn foo(_x: impl Foo + Send) {
3434
| ++++
3535
help: function arguments must have a statically known size, borrowed types always have a known size
3636
|
37-
LL | fn foo(_x: &Foo + Send) {
37+
LL | fn foo(_x: &(Foo + Send)) {
38+
| ++ +
39+
40+
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
41+
--> $DIR/not-on-bare-trait.rs:12:8
42+
|
43+
LL | fn bar(_x: (dyn Foo + Send)) {
44+
| ^^ doesn't have a size known at compile-time
45+
|
46+
= help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
47+
= help: unsized fn params are gated as an unstable feature
48+
help: you can use `impl Trait` as the argument type
49+
|
50+
LL | fn bar(_x: impl (dyn Foo + Send)) {
51+
| ++++
52+
help: function arguments must have a statically known size, borrowed types always have a known size
53+
|
54+
LL | fn bar(_x: &(dyn Foo + Send)) {
3855
| +
3956

40-
error: aborting due to 1 previous error; 1 warning emitted
57+
error: aborting due to 2 previous errors; 1 warning emitted
4158

4259
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)