Skip to content

Commit 98eb0c1

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 5b787ee commit 98eb0c1

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
@@ -3056,9 +3056,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30563056
}
30573057
ObligationCauseCode::SizedArgumentType(ty_span) => {
30583058
if let Some(span) = ty_span {
3059-
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
3059+
let trait_len = if let ty::PredicateKind::Clause(clause) =
3060+
predicate.kind().skip_binder()
30603061
&& let ty::ClauseKind::Trait(trait_pred) = clause
3061-
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
3062+
&& let ty::Dynamic(preds, ..) = trait_pred.self_ty().kind()
30623063
{
30633064
let span = if let Ok(snippet) =
30643065
self.tcx.sess.source_map().span_to_snippet(span)
@@ -3075,12 +3076,39 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30753076
"impl ".to_string(),
30763077
Applicability::MaybeIncorrect,
30773078
);
3078-
}
3079-
err.span_suggestion_verbose(
3080-
span.shrink_to_lo(),
3079+
preds
3080+
.iter()
3081+
.filter(|pred| {
3082+
// We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
3083+
// because the later doesn't need parentheses.
3084+
matches!(
3085+
pred.skip_binder(),
3086+
ty::ExistentialPredicate::Trait(_)
3087+
| ty::ExistentialPredicate::AutoTrait(_)
3088+
)
3089+
})
3090+
.count()
3091+
} else {
3092+
1
3093+
};
3094+
let sugg = if trait_len == 1 {
3095+
vec![(span.shrink_to_lo(), "&".to_string())]
3096+
} else if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3097+
&& snippet.starts_with('(')
3098+
{
3099+
// We don't want to suggest `&((dyn Foo + Bar))` when we have
3100+
// `(dyn Foo + Bar)`.
3101+
vec![(span.shrink_to_lo(), "&".to_string())]
3102+
} else {
3103+
vec![
3104+
(span.shrink_to_lo(), "&(".to_string()),
3105+
(span.shrink_to_hi(), ")".to_string()),
3106+
]
3107+
};
3108+
err.multipart_suggestion_verbose(
30813109
"function arguments must have a statically known size, borrowed types \
30823110
always have a known size",
3083-
"&",
3111+
sugg,
30843112
Applicability::MachineApplicable,
30853113
);
30863114
} 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)