Rollup merge of #127717 - gurry:127441-stray-impl-sugg, r=compiler-errors
Fix malformed suggestion for repeated maybe unsized bounds Fixes #127441 Now when we encounter something like `foo(a : impl ?Sized + ?Sized)`, instead of suggesting removal of both bounds and leaving `foo(a: impl )` behind, we suggest changing the first bound to `Sized` and removing the second bound, resulting in `foo(a: impl Sized)`. Although the issue was reported for impl trait types, it also occurred with regular param bounds. So if we encounter `foo<T: ?Sized + ?Sized>(a: T)` we now detect that all the bounds are `?Sized` and therefore emit the suggestion to remove the entire predicate `: ?Sized + ?Sized` resulting in `foo<T>(a: T)`. Lastly, if we encounter a situation where some of the bounds are something other than `?Sized`, then we emit separate removal suggestions for each `?Sized` bound. E.g. if we see `foo(a: impl ?Sized + Bar + ?Sized)` or `foo<T: ?Sized + Bar + ?Sized>(a: T)` we emit suggestions such that the user will be left with `foo(a : impl Bar)` or `foo<T: Bar>(a: T)` respectively.
This commit is contained in:
commit
2ff33bb1df
@ -763,7 +763,7 @@ pub fn bounds_span_for_suggestions(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||||
let predicate = &self.predicates[pos];
|
let predicate = &self.predicates[pos];
|
||||||
let span = predicate.span();
|
let span = predicate.span();
|
||||||
|
|
||||||
@ -806,15 +806,21 @@ pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) ->
|
|||||||
return self.span_for_predicate_removal(predicate_pos);
|
return self.span_for_predicate_removal(predicate_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = bounds[bound_pos].span();
|
let bound_span = bounds[bound_pos].span();
|
||||||
if bound_pos == 0 {
|
if bound_pos < bounds.len() - 1 {
|
||||||
// where T: ?Sized + Bar, Foo: Bar,
|
// If there's another bound after the current bound
|
||||||
// ^^^^^^^^^
|
// include the following '+' e.g.:
|
||||||
span.to(bounds[1].span().shrink_to_lo())
|
//
|
||||||
|
// `T: Foo + CurrentBound + Bar`
|
||||||
|
// ^^^^^^^^^^^^^^^
|
||||||
|
bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
|
||||||
} else {
|
} else {
|
||||||
// where T: Bar + ?Sized, Foo: Bar,
|
// If the current bound is the last bound
|
||||||
// ^^^^^^^^^
|
// include the preceding '+' E.g.:
|
||||||
bounds[bound_pos - 1].span().shrink_to_hi().to(span)
|
//
|
||||||
|
// `T: Foo + Bar + CurrentBound`
|
||||||
|
// ^^^^^^^^^^^^^^^
|
||||||
|
bound_span.with_lo(bounds[bound_pos - 1].span().hi())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (pos, bound) in predicate.bounds.iter().enumerate() {
|
let unsized_bounds = predicate
|
||||||
let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
|
.bounds
|
||||||
continue;
|
.iter()
|
||||||
};
|
.enumerate()
|
||||||
if poly.trait_ref.trait_def_id() != def_id {
|
.filter(|(_, bound)| {
|
||||||
continue;
|
if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound
|
||||||
}
|
&& poly.trait_ref.trait_def_id() == def_id
|
||||||
if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 {
|
{
|
||||||
// For `impl ?Sized` with no other bounds, suggest `impl Sized` instead.
|
true
|
||||||
let bound_span = bound.span();
|
} else {
|
||||||
if bound_span.can_be_used_for_suggestions() {
|
false
|
||||||
let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1));
|
}
|
||||||
suggestions.push((
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if unsized_bounds.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg));
|
||||||
|
|
||||||
|
if predicate.bounds.len() == unsized_bounds.len() {
|
||||||
|
// All the bounds are unsized bounds, e.g.
|
||||||
|
// `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`,
|
||||||
|
// so in this case:
|
||||||
|
// - if it's an impl trait predicate suggest changing the
|
||||||
|
// the first bound to sized and removing the rest
|
||||||
|
// - Otherwise simply suggest removing the entire predicate
|
||||||
|
if predicate.origin == PredicateOrigin::ImplTrait {
|
||||||
|
let first_bound = unsized_bounds[0].1;
|
||||||
|
let first_bound_span = first_bound.span();
|
||||||
|
if first_bound_span.can_be_used_for_suggestions() {
|
||||||
|
let question_span =
|
||||||
|
first_bound_span.with_hi(first_bound_span.lo() + BytePos(1));
|
||||||
|
push_suggestion(
|
||||||
question_span,
|
question_span,
|
||||||
String::new(),
|
|
||||||
SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
|
SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
|
||||||
));
|
);
|
||||||
|
|
||||||
|
for (pos, _) in unsized_bounds.iter().skip(1) {
|
||||||
|
let sp = generics.span_for_bound_removal(where_pos, *pos);
|
||||||
|
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let sp = generics.span_for_predicate_removal(where_pos);
|
||||||
|
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Some of the bounds are other than unsized.
|
||||||
|
// So push separate removal suggestion for each unsized bound
|
||||||
|
for (pos, _) in unsized_bounds {
|
||||||
let sp = generics.span_for_bound_removal(where_pos, pos);
|
let sp = generics.span_for_bound_removal(where_pos, pos);
|
||||||
suggestions.push((
|
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||||
sp,
|
|
||||||
String::new(),
|
|
||||||
SuggestChangingConstraintsMessage::RemoveMaybeUnsized,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
// Regression test for #127441
|
||||||
|
|
||||||
|
// Tests that we make the correct suggestion
|
||||||
|
// in case there are more than one `?Sized`
|
||||||
|
// bounds on a function parameter
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
fn foo1<T: ?Sized>(a: T) {}
|
||||||
|
//~^ ERROR he size for values of type `T` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo2<T: ?Sized + ?Sized>(a: T) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR the size for values of type `T` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR he size for values of type `T` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR the size for values of type `T` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo5(_: impl ?Sized) {}
|
||||||
|
//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo6(_: impl ?Sized + ?Sized) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
|
||||||
|
|
||||||
|
fn foo7(_: impl ?Sized + ?Sized + Debug) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
|
||||||
|
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,192 @@
|
|||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
|
||||||
|
|
|
||||||
|
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
|
||||||
|
|
|
||||||
|
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
|
||||||
|
|
|
||||||
|
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
|
||||||
|
|
|
||||||
|
LL | fn foo6(_: impl ?Sized + ?Sized) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
|
||||||
|
|
|
||||||
|
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
|
||||||
|
|
|
||||||
|
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
|
||||||
|
| ^^^^^^ ^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20
|
||||||
|
|
|
||||||
|
LL | fn foo1<T: ?Sized>(a: T) {}
|
||||||
|
| - ^ doesn't have a size known at compile-time
|
||||||
|
| |
|
||||||
|
| this type parameter needs to be `Sized`
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||||
|
|
|
||||||
|
LL - fn foo1<T: ?Sized>(a: T) {}
|
||||||
|
LL + fn foo1<T>(a: T) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo1<T: ?Sized>(a: &T) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29
|
||||||
|
|
|
||||||
|
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
|
||||||
|
| - ^ doesn't have a size known at compile-time
|
||||||
|
| |
|
||||||
|
| this type parameter needs to be `Sized`
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||||
|
|
|
||||||
|
LL - fn foo2<T: ?Sized + ?Sized>(a: T) {}
|
||||||
|
LL + fn foo2<T>(a: T) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37
|
||||||
|
|
|
||||||
|
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
|
||||||
|
| - ^ doesn't have a size known at compile-time
|
||||||
|
| |
|
||||||
|
| this type parameter needs to be `Sized`
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider restricting type parameters
|
||||||
|
|
|
||||||
|
LL - fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
|
||||||
|
LL + fn foo3<T: Debug>(a: T) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38
|
||||||
|
|
|
||||||
|
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
|
||||||
|
| - ^ doesn't have a size known at compile-time
|
||||||
|
| |
|
||||||
|
| this type parameter needs to be `Sized`
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider restricting type parameters
|
||||||
|
|
|
||||||
|
LL - fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
|
||||||
|
LL + fn foo4<T: Debug >(a: T) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9
|
||||||
|
|
|
||||||
|
LL | fn foo5(_: impl ?Sized) {}
|
||||||
|
| ^ ----------- this type parameter needs to be `Sized`
|
||||||
|
| |
|
||||||
|
| doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider replacing `?Sized` with `Sized`
|
||||||
|
|
|
||||||
|
LL - fn foo5(_: impl ?Sized) {}
|
||||||
|
LL + fn foo5(_: impl Sized) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo5(_: &impl ?Sized) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9
|
||||||
|
|
|
||||||
|
LL | fn foo6(_: impl ?Sized + ?Sized) {}
|
||||||
|
| ^ -------------------- this type parameter needs to be `Sized`
|
||||||
|
| |
|
||||||
|
| doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider restricting type parameters
|
||||||
|
|
|
||||||
|
LL - fn foo6(_: impl ?Sized + ?Sized) {}
|
||||||
|
LL + fn foo6(_: impl Sized) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo6(_: &impl ?Sized + ?Sized) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9
|
||||||
|
|
|
||||||
|
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
|
||||||
|
| ^ ---------------------------- this type parameter needs to be `Sized`
|
||||||
|
| |
|
||||||
|
| doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider restricting type parameters
|
||||||
|
|
|
||||||
|
LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {}
|
||||||
|
LL + fn foo7(_: impl Debug) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
|
||||||
|
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9
|
||||||
|
|
|
||||||
|
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
|
||||||
|
| ^ ---------------------------- this type parameter needs to be `Sized`
|
||||||
|
| |
|
||||||
|
| doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: consider restricting type parameters
|
||||||
|
|
|
||||||
|
LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
|
||||||
|
LL + fn foo8(_: impl Debug ) {}
|
||||||
|
|
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {}
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0203, E0277.
|
||||||
|
For more information about an error, try `rustc --explain E0203`.
|
Loading…
Reference in New Issue
Block a user