Skip to content

Commit fff5f99

Browse files
committed
Don't reject *multiple* relaxed bounds, reject *duplicate* ones.
Having multiple relaxed bounds like `?Sized + ?Iterator` is actually *fine*. We actually want to reject *duplicate* relaxed bounds like `?Sized + ?Sized` because these most certainly represent a user error. Note that this doesn't mean that we accept more code because a bound like `?Iterator` is still invalid as it's not relaxing a *default* trait and the only way to define / use more default bounds is under the experimental and internal feature `more_maybe_bounds` plus `lang_items` plus unstable flag `-Zexperimental-default-bounds`. Ultimately, this simply *reframes* the diagnostic. The scope of `more_maybe_bounds` / `-Zexperimental-default-bounds` remains unchanged as well.
1 parent 83bea88 commit fff5f99

18 files changed

+381
-196
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,6 @@ hir_analysis_missing_type_params =
368368
*[other] parameters
369369
} must be specified on the object type
370370
371-
hir_analysis_multiple_relaxed_default_bounds =
372-
type parameter has more than one relaxed default bound, only one is supported
373-
374371
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
375372
376373
hir_analysis_must_implement_not_function = not a function

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,6 @@ pub(crate) struct CopyImplOnTypeWithDtor {
277277
pub span: Span,
278278
}
279279

280-
#[derive(Diagnostic)]
281-
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)]
282-
pub(crate) struct MultipleRelaxedDefaultBounds {
283-
#[primary_span]
284-
pub spans: Vec<Span>,
285-
}
286-
287280
#[derive(Diagnostic)]
288281
#[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)]
289282
pub(crate) struct CopyImplOnNonAdt {

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn search_bounds_for<'tcx>(
8585
}
8686
}
8787

88-
fn collect_unbounds<'tcx>(
88+
fn collect_maybe_bounds<'tcx>(
8989
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
9090
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
9191
) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> {
@@ -204,9 +204,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
204204
return;
205205
}
206206
} else {
207-
// Report invalid unbounds on sizedness-bounded generic parameters.
208-
let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates);
209-
self.check_and_report_invalid_unbounds_on_param(unbounds);
207+
// Report invalid maybe-bounds on sizedness-bounded generic parameters.
208+
let maybe_bounds = collect_maybe_bounds(hir_bounds, self_ty_where_predicates);
209+
self.check_and_report_invalid_relaxed_bounds_on_param(maybe_bounds);
210210
}
211211

212212
let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,47 +34,53 @@ use crate::fluent_generated as fluent;
3434
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
3535

3636
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
37-
/// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
38-
pub(crate) fn check_and_report_invalid_unbounds_on_param(
37+
/// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
38+
//
39+
// FIXME(more_maybe_bounds, @fmease): This validation function is only called in contexts where
40+
// we perform "sized elaboration". This means, it doesn't get called for trait object types and
41+
// supertrait bounds! Ideally, we would do these checks in `Self::lower_poly_trait_ref`!
42+
pub(crate) fn check_and_report_invalid_relaxed_bounds_on_param(
3943
&self,
40-
unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
44+
relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
4145
) {
4246
let tcx = self.tcx();
4347

44-
let sized_did = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
48+
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
4549

46-
let mut unique_bounds = FxIndexSet::default();
47-
let mut seen_repeat = false;
48-
for unbound in &unbounds {
49-
if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
50-
seen_repeat |= !unique_bounds.insert(unbound_def_id);
50+
for bound in &relaxed_bounds {
51+
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
52+
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
5153
}
5254
}
5355

54-
if unbounds.len() > 1 {
55-
let err = errors::MultipleRelaxedDefaultBounds {
56-
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
57-
};
58-
59-
if seen_repeat {
60-
tcx.dcx().emit_err(err);
61-
} else if !tcx.features().more_maybe_bounds() {
62-
tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit();
63-
};
56+
for (trait_def_id, spans) in grouped_bounds {
57+
if spans.len() > 1 {
58+
let name = tcx.item_name(trait_def_id);
59+
self.dcx()
60+
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
61+
.with_code(E0203)
62+
.emit();
63+
}
6464
}
6565

66-
for unbound in unbounds {
67-
if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
68-
&& (did == sized_did || tcx.is_default_trait(did))
66+
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
67+
68+
for bound in relaxed_bounds {
69+
if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
70+
&& (def_id == sized_def_id || tcx.is_default_trait(def_id))
6971
{
7072
continue;
7173
}
72-
73-
let message = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
74-
true => "bound modifier `?` can only be applied to default traits like `Sized`",
75-
false => "bound modifier `?` can only be applied to `Sized`",
76-
};
77-
let diag = self.dcx().struct_span_err(unbound.span, message);
74+
self.dcx().span_err(
75+
bound.span,
76+
if tcx.sess.opts.unstable_opts.experimental_default_bounds
77+
|| tcx.features().more_maybe_bounds()
78+
{
79+
"bound modifier `?` can only be applied to default traits like `Sized`"
80+
} else {
81+
"bound modifier `?` can only be applied to `Sized`"
82+
},
83+
);
7884
}
7985
}
8086

tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,7 @@ trait Trait4 where Self: ?Trait1 {}
1010
fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
1111
//~^ ERROR `?Trait` is not permitted in trait object types
1212
fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
13-
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
14-
//~| ERROR bound modifier `?` can only be applied to `Sized`
15-
//~| ERROR bound modifier `?` can only be applied to `Sized`
16-
17-
trait Trait {}
18-
// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions
19-
fn baz<T: ?Trait + ?Trait>(_ : T) {}
20-
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
21-
//~| ERROR bound modifier `?` can only be applied to `Sized`
13+
//~^ ERROR bound modifier `?` can only be applied to `Sized`
2214
//~| ERROR bound modifier `?` can only be applied to `Sized`
2315

2416
fn main() {}

tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,6 @@ LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
2525
= help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
2626
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2727

28-
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
29-
--> $DIR/feature-gate-more-maybe-bounds.rs:12:11
30-
|
31-
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
32-
| ^^^^^^^ ^^^^^^^
33-
|
34-
= help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
35-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
36-
3728
error: bound modifier `?` can only be applied to `Sized`
3829
--> $DIR/feature-gate-more-maybe-bounds.rs:12:11
3930
|
@@ -46,25 +37,6 @@ error: bound modifier `?` can only be applied to `Sized`
4637
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
4738
| ^^^^^^^
4839

49-
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
50-
--> $DIR/feature-gate-more-maybe-bounds.rs:19:11
51-
|
52-
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
53-
| ^^^^^^ ^^^^^^
54-
55-
error: bound modifier `?` can only be applied to `Sized`
56-
--> $DIR/feature-gate-more-maybe-bounds.rs:19:11
57-
|
58-
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
59-
| ^^^^^^
60-
61-
error: bound modifier `?` can only be applied to `Sized`
62-
--> $DIR/feature-gate-more-maybe-bounds.rs:19:20
63-
|
64-
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
65-
| ^^^^^^
66-
67-
error: aborting due to 9 previous errors
40+
error: aborting due to 5 previous errors
6841

69-
Some errors have detailed explanations: E0203, E0658.
70-
For more information about an error, try `rustc --explain E0203`.
42+
For more information about this error, try `rustc --explain E0658`.

tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr renamed to tests/ui/trait-bounds/bad-suggestion-for-repeated-unsized-bound-127441.stderr

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
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
1+
error[E0203]: duplicate relaxed bounds
2+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:12:12
33
|
44
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
55
| ^^^^^^ ^^^^^^
66

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
7+
error[E0203]: duplicate relaxed bounds
8+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:16:12
99
|
1010
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
1111
| ^^^^^^ ^^^^^^
1212

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
13+
error[E0203]: duplicate relaxed bounds
14+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:20:12
1515
|
1616
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
1717
| ^^^^^^ ^^^^^^
1818

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
19+
error[E0203]: duplicate relaxed bounds
20+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:27:17
2121
|
2222
LL | fn foo6(_: impl ?Sized + ?Sized) {}
2323
| ^^^^^^ ^^^^^^
2424

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
25+
error[E0203]: duplicate relaxed bounds
26+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:31:17
2727
|
2828
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
2929
| ^^^^^^ ^^^^^^
3030

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
31+
error[E0203]: duplicate relaxed bounds
32+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:35:17
3333
|
3434
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
3535
| ^^^^^^ ^^^^^^
3636

3737
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:23
38+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:9:23
3939
|
4040
LL | fn foo1<T: ?Sized>(a: T) {}
4141
| - ^ doesn't have a size known at compile-time
@@ -54,7 +54,7 @@ LL | fn foo1<T: ?Sized>(a: &T) {}
5454
| +
5555

5656
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:32
57+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:12:32
5858
|
5959
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
6060
| - ^ doesn't have a size known at compile-time
@@ -73,7 +73,7 @@ LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
7373
| +
7474

7575
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:40
76+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:16:40
7777
|
7878
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
7979
| - ^ doesn't have a size known at compile-time
@@ -92,7 +92,7 @@ LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
9292
| +
9393

9494
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:41
95+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:20:41
9696
|
9797
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
9898
| - ^ doesn't have a size known at compile-time
@@ -111,7 +111,7 @@ LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
111111
| +
112112

113113
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:12
114+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:24:12
115115
|
116116
LL | fn foo5(_: impl ?Sized) {}
117117
| ^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {}
131131
| +
132132

133133
error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
134-
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12
134+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:27:12
135135
|
136136
LL | fn foo6(_: impl ?Sized + ?Sized) {}
137137
| ^^^^^^^^^^^^^^^^^^^^
@@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {}
151151
| +
152152

153153
error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
154-
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12
154+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:31:12
155155
|
156156
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
157157
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
171171
| +
172172

173173
error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
174-
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12
174+
--> $DIR/bad-suggestion-for-repeated-unsized-bound-127441.rs:35:12
175175
|
176176
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
177177
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
2+
//~^ ERROR duplicate relaxed `Sized` bounds
3+
//~| ERROR duplicate relaxed `Iterator` bounds
4+
//~| ERROR bound modifier `?` can only be applied to `Sized`
5+
//~| ERROR bound modifier `?` can only be applied to `Sized`
6+
7+
trait Trait {
8+
// We used to say "type parameter has more than one relaxed default bound"
9+
// even on *associated types* like here. Test that we no longer do that.
10+
type Type: ?Sized + ?Sized;
11+
//~^ ERROR duplicate relaxed `Sized` bounds
12+
//~| ERROR duplicate relaxed `Sized` bounds
13+
}
14+
15+
// We used to emit an additional error about "multiple relaxed default bounds".
16+
// However, multiple relaxed bounds are actually *fine* if they're distinct.
17+
// Ultimately, we still reject this, so we're fine.
18+
fn not_dupes<T: ?Sized + ?Iterator>() {}
19+
//~^ ERROR bound modifier `?` can only be applied to `Sized`
20+
21+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0203]: duplicate relaxed `Sized` bounds
2+
--> $DIR/duplicate-relaxed-bounds.rs:1:13
3+
|
4+
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
5+
| ^^^^^^ ^^^^^^
6+
7+
error[E0203]: duplicate relaxed `Iterator` bounds
8+
--> $DIR/duplicate-relaxed-bounds.rs:1:31
9+
|
10+
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
11+
| ^^^^^^^^^ ^^^^^^^^^
12+
13+
error: bound modifier `?` can only be applied to `Sized`
14+
--> $DIR/duplicate-relaxed-bounds.rs:1:31
15+
|
16+
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
17+
| ^^^^^^^^^
18+
19+
error: bound modifier `?` can only be applied to `Sized`
20+
--> $DIR/duplicate-relaxed-bounds.rs:1:43
21+
|
22+
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
23+
| ^^^^^^^^^
24+
25+
error: bound modifier `?` can only be applied to `Sized`
26+
--> $DIR/duplicate-relaxed-bounds.rs:18:26
27+
|
28+
LL | fn not_dupes<T: ?Sized + ?Iterator>() {}
29+
| ^^^^^^^^^
30+
31+
error[E0203]: duplicate relaxed `Sized` bounds
32+
--> $DIR/duplicate-relaxed-bounds.rs:10:16
33+
|
34+
LL | type Type: ?Sized + ?Sized;
35+
| ^^^^^^ ^^^^^^
36+
37+
error[E0203]: duplicate relaxed `Sized` bounds
38+
--> $DIR/duplicate-relaxed-bounds.rs:10:16
39+
|
40+
LL | type Type: ?Sized + ?Sized;
41+
| ^^^^^^ ^^^^^^
42+
|
43+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
44+
45+
error: aborting due to 7 previous errors
46+
47+
For more information about this error, try `rustc --explain E0203`.

0 commit comments

Comments
 (0)