Skip to content

Commit 84f9da4

Browse files
authored
Rollup merge of rust-lang#144167 - zachs18:rangebounds-not-unsized-reason, r=tgross35
Document why `Range*<&T> as RangeBounds<T>` impls are not `T: ?Sized`, and give an alternative. `Range*<&T> as RangeBounds<T>` impls have been tried to be relaxed to `T: ?Sized` at least twice: * rust-lang#61584 * rust-lang#64327 I also was just about to make another PR to do it again until I `./x.py test library/alloc` and rediscovered the type inference regression, then searched around and found the previous PRs. Hence this PR instead so hopefully that doesn't keep happening 😛. These impls cannot be relaxed for two reasons: 1. Type inference regressions: See ``@SimonSapin's`` explanation from a previous PR: rust-lang#61584 (comment) 2. It's a breaking change: `impl RangeBounds<MyUnsizedType> for std::ops::Range<&MyUnsizedType>` is allowed after the coherence rebalance ([playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f704a6fe53bfc33e55b2fc246d895ec2)), and relaxing these impls would conflict with that downstream impl. This PR adds doc-comments explaining that not having `T: ?Sized` is intentional[^1], and gives an explicit alternative: `(Bound<&T>, Bound<&T>)`. Technically, the impls for the unstable new `std::range` types could be relaxed, as they are still unstable so the change would not be breaking, but having them be different in this regard seems worse (and the non-iterable `RangeTo/RangeToInclusive` range types are shared between the "new" and "old" so cannot be changed anyway), and then the type inference regression would pop up in whatever edition the new range types stabilize in. The "see \<link\> for discussion of those issues" is intentionally left as a non-doc comment just for whoever may try to relax these impls again in the future, but if it is preferred to have the link in the docs I can add that. Closes rust-lang#107196 (as wontfix) CC rust-lang#64027 [^1]: "intentional" is maybe a bit of strong wording, should it instead say something like "was stabilized without it and it would be breaking to change it now"?
2 parents 207afb9 + 6179b3d commit 84f9da4

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

core/src/ops/range.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,12 @@ impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) {
11411141
}
11421142
}
11431143

1144+
// This impl intentionally does not have `T: ?Sized`;
1145+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
1146+
//
1147+
/// If you need to use this implementation where `T` is unsized,
1148+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
1149+
/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
11441150
#[stable(feature = "collections_range", since = "1.28.0")]
11451151
impl<T> RangeBounds<T> for RangeFrom<&T> {
11461152
fn start_bound(&self) -> Bound<&T> {
@@ -1151,6 +1157,12 @@ impl<T> RangeBounds<T> for RangeFrom<&T> {
11511157
}
11521158
}
11531159

1160+
// This impl intentionally does not have `T: ?Sized`;
1161+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
1162+
//
1163+
/// If you need to use this implementation where `T` is unsized,
1164+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
1165+
/// i.e. replace `..end` with `(Bound::Unbounded, Bound::Excluded(end))`.
11541166
#[stable(feature = "collections_range", since = "1.28.0")]
11551167
impl<T> RangeBounds<T> for RangeTo<&T> {
11561168
fn start_bound(&self) -> Bound<&T> {
@@ -1161,6 +1173,12 @@ impl<T> RangeBounds<T> for RangeTo<&T> {
11611173
}
11621174
}
11631175

1176+
// This impl intentionally does not have `T: ?Sized`;
1177+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
1178+
//
1179+
/// If you need to use this implementation where `T` is unsized,
1180+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
1181+
/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
11641182
#[stable(feature = "collections_range", since = "1.28.0")]
11651183
impl<T> RangeBounds<T> for Range<&T> {
11661184
fn start_bound(&self) -> Bound<&T> {
@@ -1171,6 +1189,12 @@ impl<T> RangeBounds<T> for Range<&T> {
11711189
}
11721190
}
11731191

1192+
// This impl intentionally does not have `T: ?Sized`;
1193+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
1194+
//
1195+
/// If you need to use this implementation where `T` is unsized,
1196+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
1197+
/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
11741198
#[stable(feature = "collections_range", since = "1.28.0")]
11751199
impl<T> RangeBounds<T> for RangeInclusive<&T> {
11761200
fn start_bound(&self) -> Bound<&T> {
@@ -1181,6 +1205,12 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> {
11811205
}
11821206
}
11831207

1208+
// This impl intentionally does not have `T: ?Sized`;
1209+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
1210+
//
1211+
/// If you need to use this implementation where `T` is unsized,
1212+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
1213+
/// i.e. replace `..=end` with `(Bound::Unbounded, Bound::Included(end))`.
11841214
#[stable(feature = "collections_range", since = "1.28.0")]
11851215
impl<T> RangeBounds<T> for RangeToInclusive<&T> {
11861216
fn start_bound(&self) -> Bound<&T> {

core/src/range.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ impl<T> RangeBounds<T> for Range<T> {
167167
}
168168
}
169169

170+
// This impl intentionally does not have `T: ?Sized`;
171+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
172+
//
173+
/// If you need to use this implementation where `T` is unsized,
174+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
175+
/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
170176
#[unstable(feature = "new_range_api", issue = "125687")]
171177
impl<T> RangeBounds<T> for Range<&T> {
172178
fn start_bound(&self) -> Bound<&T> {
@@ -346,6 +352,12 @@ impl<T> RangeBounds<T> for RangeInclusive<T> {
346352
}
347353
}
348354

355+
// This impl intentionally does not have `T: ?Sized`;
356+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
357+
//
358+
/// If you need to use this implementation where `T` is unsized,
359+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
360+
/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
349361
#[unstable(feature = "new_range_api", issue = "125687")]
350362
impl<T> RangeBounds<T> for RangeInclusive<&T> {
351363
fn start_bound(&self) -> Bound<&T> {
@@ -491,6 +503,12 @@ impl<T> RangeBounds<T> for RangeFrom<T> {
491503
}
492504
}
493505

506+
// This impl intentionally does not have `T: ?Sized`;
507+
// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
508+
//
509+
/// If you need to use this implementation where `T` is unsized,
510+
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
511+
/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
494512
#[unstable(feature = "new_range_api", issue = "125687")]
495513
impl<T> RangeBounds<T> for RangeFrom<&T> {
496514
fn start_bound(&self) -> Bound<&T> {

0 commit comments

Comments
 (0)