Skip to content

Commit e13eb37

Browse files
committed
Fix malformed suggestion for repeated maybe unsized bounds
1 parent b1de36f commit e13eb37

File tree

4 files changed

+295
-29
lines changed

4 files changed

+295
-29
lines changed

compiler/rustc_hir/src/hir.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ impl<'hir> Generics<'hir> {
723723
)
724724
}
725725

726-
fn span_for_predicate_removal(&self, pos: usize) -> Span {
726+
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
727727
let predicate = &self.predicates[pos];
728728
let span = predicate.span();
729729

@@ -766,15 +766,21 @@ impl<'hir> Generics<'hir> {
766766
return self.span_for_predicate_removal(predicate_pos);
767767
}
768768

769-
let span = bounds[bound_pos].span();
770-
if bound_pos == 0 {
771-
// where T: ?Sized + Bar, Foo: Bar,
772-
// ^^^^^^^^^
773-
span.to(bounds[1].span().shrink_to_lo())
769+
let bound_span = bounds[bound_pos].span();
770+
if bound_pos < bounds.len() - 1 {
771+
// If there's another bound after the current bound
772+
// include the following '+' e.g.:
773+
//
774+
// `T: Foo + CurrentBound + Bar`
775+
// ^^^^^^^^^^^^^^^
776+
bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
774777
} else {
775-
// where T: Bar + ?Sized, Foo: Bar,
776-
// ^^^^^^^^^
777-
bounds[bound_pos - 1].span().shrink_to_hi().to(span)
778+
// If the current bound is the last bound
779+
// include the preceding '+' E.g.:
780+
//
781+
// `T: Foo + Bar + CurrentBound`
782+
// ^^^^^^^^^^^^^^^
783+
bound_span.with_lo(bounds[bound_pos - 1].span().hi())
778784
}
779785
}
780786
}

compiler/rustc_middle/src/ty/diagnostics.rs

+49-20
Original file line numberDiff line numberDiff line change
@@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound(
188188
continue;
189189
};
190190

191-
for (pos, bound) in predicate.bounds.iter().enumerate() {
192-
let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
193-
continue;
194-
};
195-
if poly.trait_ref.trait_def_id() != def_id {
196-
continue;
197-
}
198-
if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 {
199-
// For `impl ?Sized` with no other bounds, suggest `impl Sized` instead.
200-
let bound_span = bound.span();
201-
if bound_span.can_be_used_for_suggestions() {
202-
let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1));
203-
suggestions.push((
191+
let unsized_bounds = predicate
192+
.bounds
193+
.iter()
194+
.enumerate()
195+
.filter(|(_, bound)| {
196+
if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound
197+
&& poly.trait_ref.trait_def_id() == def_id
198+
{
199+
true
200+
} else {
201+
false
202+
}
203+
})
204+
.collect::<Vec<_>>();
205+
206+
if unsized_bounds.is_empty() {
207+
continue;
208+
}
209+
210+
let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg));
211+
212+
if predicate.bounds.len() == unsized_bounds.len() {
213+
// All the bounds are unsized bounds, e.g.
214+
// `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`,
215+
// so in this case:
216+
// - if it's an impl trait predicate suggest changing the
217+
// the first bound to sized and removing the rest
218+
// - Otherwise simply suggest removing the entire predicate
219+
if predicate.origin == PredicateOrigin::ImplTrait {
220+
let first_bound = unsized_bounds[0].1;
221+
let first_bound_span = first_bound.span();
222+
if first_bound_span.can_be_used_for_suggestions() {
223+
let question_span =
224+
first_bound_span.with_hi(first_bound_span.lo() + BytePos(1));
225+
push_suggestion(
204226
question_span,
205-
String::new(),
206227
SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
207-
));
228+
);
229+
230+
for (pos, _) in unsized_bounds.iter().skip(1) {
231+
let sp = generics.span_for_bound_removal(where_pos, *pos);
232+
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
233+
}
208234
}
209235
} else {
236+
let sp = generics.span_for_predicate_removal(where_pos);
237+
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
238+
}
239+
} else {
240+
// Some of the bounds are other than unsized.
241+
// So push separate removal suggestion for each unsized bound
242+
for (pos, _) in unsized_bounds {
210243
let sp = generics.span_for_bound_removal(where_pos, pos);
211-
suggestions.push((
212-
sp,
213-
String::new(),
214-
SuggestChangingConstraintsMessage::RemoveMaybeUnsized,
215-
));
244+
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
216245
}
217246
}
218247
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Regression test for #127441
2+
3+
// Tests that we make the correct suggestion
4+
// in case there are more than one `?Sized`
5+
// bounds on a function parameter
6+
7+
use std::fmt::Debug;
8+
9+
fn foo1<T: ?Sized>(a: T) {}
10+
//~^ ERROR he size for values of type `T` cannot be known at compilation time
11+
12+
fn foo2<T: ?Sized + ?Sized>(a: T) {}
13+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
14+
//~| ERROR the size for values of type `T` cannot be known at compilation time
15+
16+
fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
17+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
18+
//~| ERROR he size for values of type `T` cannot be known at compilation time
19+
20+
fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
21+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
22+
//~| ERROR the size for values of type `T` cannot be known at compilation time
23+
24+
fn foo5(_: impl ?Sized) {}
25+
//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
26+
27+
fn foo6(_: impl ?Sized + ?Sized) {}
28+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
29+
//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
30+
31+
fn foo7(_: impl ?Sized + ?Sized + Debug) {}
32+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
33+
//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
34+
35+
fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
36+
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
37+
//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
2+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
3+
|
4+
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
5+
| ^^^^^^ ^^^^^^
6+
7+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
8+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
9+
|
10+
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
11+
| ^^^^^^ ^^^^^^
12+
13+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
14+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
15+
|
16+
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
17+
| ^^^^^^ ^^^^^^
18+
19+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
20+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
21+
|
22+
LL | fn foo6(_: impl ?Sized + ?Sized) {}
23+
| ^^^^^^ ^^^^^^
24+
25+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
26+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
27+
|
28+
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
29+
| ^^^^^^ ^^^^^^
30+
31+
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
32+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
33+
|
34+
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
35+
| ^^^^^^ ^^^^^^
36+
37+
error[E0277]: the size for values of type `T` cannot be known at compilation time
38+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20
39+
|
40+
LL | fn foo1<T: ?Sized>(a: T) {}
41+
| - ^ doesn't have a size known at compile-time
42+
| |
43+
| this type parameter needs to be `Sized`
44+
|
45+
= help: unsized fn params are gated as an unstable feature
46+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
47+
|
48+
LL - fn foo1<T: ?Sized>(a: T) {}
49+
LL + fn foo1<T>(a: T) {}
50+
|
51+
help: function arguments must have a statically known size, borrowed types always have a known size
52+
|
53+
LL | fn foo1<T: ?Sized>(a: &T) {}
54+
| +
55+
56+
error[E0277]: the size for values of type `T` cannot be known at compilation time
57+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29
58+
|
59+
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
60+
| - ^ doesn't have a size known at compile-time
61+
| |
62+
| this type parameter needs to be `Sized`
63+
|
64+
= help: unsized fn params are gated as an unstable feature
65+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
66+
|
67+
LL - fn foo2<T: ?Sized + ?Sized>(a: T) {}
68+
LL + fn foo2<T>(a: T) {}
69+
|
70+
help: function arguments must have a statically known size, borrowed types always have a known size
71+
|
72+
LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
73+
| +
74+
75+
error[E0277]: the size for values of type `T` cannot be known at compilation time
76+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37
77+
|
78+
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
79+
| - ^ doesn't have a size known at compile-time
80+
| |
81+
| this type parameter needs to be `Sized`
82+
|
83+
= help: unsized fn params are gated as an unstable feature
84+
help: consider restricting type parameters
85+
|
86+
LL - fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
87+
LL + fn foo3<T: Debug>(a: T) {}
88+
|
89+
help: function arguments must have a statically known size, borrowed types always have a known size
90+
|
91+
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
92+
| +
93+
94+
error[E0277]: the size for values of type `T` cannot be known at compilation time
95+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38
96+
|
97+
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
98+
| - ^ doesn't have a size known at compile-time
99+
| |
100+
| this type parameter needs to be `Sized`
101+
|
102+
= help: unsized fn params are gated as an unstable feature
103+
help: consider restricting type parameters
104+
|
105+
LL - fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
106+
LL + fn foo4<T: Debug >(a: T) {}
107+
|
108+
help: function arguments must have a statically known size, borrowed types always have a known size
109+
|
110+
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
111+
| +
112+
113+
error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
114+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9
115+
|
116+
LL | fn foo5(_: impl ?Sized) {}
117+
| ^ ----------- this type parameter needs to be `Sized`
118+
| |
119+
| doesn't have a size known at compile-time
120+
|
121+
= help: unsized fn params are gated as an unstable feature
122+
help: consider replacing `?Sized` with `Sized`
123+
|
124+
LL - fn foo5(_: impl ?Sized) {}
125+
LL + fn foo5(_: impl Sized) {}
126+
|
127+
help: function arguments must have a statically known size, borrowed types always have a known size
128+
|
129+
LL | fn foo5(_: &impl ?Sized) {}
130+
| +
131+
132+
error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
133+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9
134+
|
135+
LL | fn foo6(_: impl ?Sized + ?Sized) {}
136+
| ^ -------------------- this type parameter needs to be `Sized`
137+
| |
138+
| doesn't have a size known at compile-time
139+
|
140+
= help: unsized fn params are gated as an unstable feature
141+
help: consider restricting type parameters
142+
|
143+
LL - fn foo6(_: impl ?Sized + ?Sized) {}
144+
LL + fn foo6(_: impl Sized) {}
145+
|
146+
help: function arguments must have a statically known size, borrowed types always have a known size
147+
|
148+
LL | fn foo6(_: &impl ?Sized + ?Sized) {}
149+
| +
150+
151+
error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
152+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9
153+
|
154+
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
155+
| ^ ---------------------------- this type parameter needs to be `Sized`
156+
| |
157+
| doesn't have a size known at compile-time
158+
|
159+
= help: unsized fn params are gated as an unstable feature
160+
help: consider restricting type parameters
161+
|
162+
LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {}
163+
LL + fn foo7(_: impl Debug) {}
164+
|
165+
help: function arguments must have a statically known size, borrowed types always have a known size
166+
|
167+
LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
168+
| +
169+
170+
error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
171+
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9
172+
|
173+
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
174+
| ^ ---------------------------- this type parameter needs to be `Sized`
175+
| |
176+
| doesn't have a size known at compile-time
177+
|
178+
= help: unsized fn params are gated as an unstable feature
179+
help: consider restricting type parameters
180+
|
181+
LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
182+
LL + fn foo8(_: impl Debug ) {}
183+
|
184+
help: function arguments must have a statically known size, borrowed types always have a known size
185+
|
186+
LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {}
187+
| +
188+
189+
error: aborting due to 14 previous errors
190+
191+
Some errors have detailed explanations: E0203, E0277.
192+
For more information about an error, try `rustc --explain E0203`.

0 commit comments

Comments
 (0)