Stabilize associated type bounds (RFC 2289)
This PR stabilizes associated type bounds, which were laid out in [RFC 2289]. This gives us a shorthand to express nested type bounds that would otherwise need to be expressed with nested `impl Trait` or broken into several `where` clauses.
### What are we stabilizing?
We're stabilizing the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. `T: Trait<Assoc: Bounds...>`. See [RFC 2289] for motivation.
In all position, the associated type bound syntax expands into a set of two (or more) bounds, and never anything else (see "How does this differ[...]" section for more info).
Associated type bounds are stabilized in four positions:
* **`where` clauses (and APIT)** - This is equivalent to breaking up the bound into two (or more) `where` clauses. For example, `where T: Trait<Assoc: Bound>` is equivalent to `where T: Trait, <T as Trait>::Assoc: Bound`.
* **Supertraits** - Similar to above, `trait CopyIterator: Iterator<Item: Copy> {}`. This is almost equivalent to breaking up the bound into two (or more) `where` clauses; however, the bound on the associated item is implied whenever the trait is used. See #112573/#112629.
* **Associated type item bounds** - This allows constraining the *nested* rigid projections that are associated with a trait's associated types. e.g. `trait Trait { type Assoc: Trait2<Assoc2: Copy>; }`.
* **opaque item bounds (RPIT, TAIT)** - This allows constraining associated types that are associated with the opaque without having to *name* the opaque. For example, `impl Iterator<Item: Copy>` defines an iterator whose item is `Copy` without having to actually name that item bound.
The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in #120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds.
### How does this differ from the RFC?
Compared to the RFC, the current implementation *always* desugars associated type bounds to sets of `ty::Clause`s internally. Specifically, it does *not* introduce a position-dependent desugaring as laid out in [RFC 2289], and in particular:
* It does *not* desugar to anonymous associated items in associated type item bounds.
* It does *not* desugar to nested RPITs in RPIT bounds, nor nested TAITs in TAIT bounds.
This position-dependent desugaring laid out in the RFC existed simply to side-step limitations of the trait solver, which have mostly been fixed in #120584. The desugaring laid out in the RFC also added unnecessary complication to the design of the feature, and introduces its own limitations to, for example:
* Conditionally lowering to nested `impl Trait` in certain positions such as RPIT and TAIT means that we inherit the limitations of RPIT/TAIT, namely lack of support for higher-ranked opaque inference. See this code example: https://github.com/rust-lang/rust/pull/120752#issuecomment-1979412531.
* Introducing anonymous associated types makes traits no longer object safe, since anonymous associated types are not nameable, and all associated types must be named in `dyn` types.
This last point motivates why this PR is *not* stabilizing support for associated type bounds in `dyn` types, e.g, `dyn Assoc<Item: Bound>`. Why? Because `dyn` types need to have *concrete* types for all associated items, this would necessitate a distinct lowering for associated type bounds, which seems both complicated and unnecessary compared to just requiring the user to write `impl Trait` themselves. See #120719.
### Implementation history:
Limited to the significant behavioral changes and fixes and relevant PRs, ping me if I left something out--
* #57428
* #108063
* #110512
* #112629
* #120719
* #120584Closes#52662
[RFC 2289]: https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
Vec::try_with_capacity
Related to #91913
Implements try_with_capacity for `Vec`, `VecDeque`, and `String`. I can follow it up with more collections if desired.
`Vec::try_with_capacity()` is functionally equivalent to the current stable:
```rust
let mut v = Vec::new();
v.try_reserve_exact(n)?
```
However, `try_reserve` calls non-inlined `finish_grow`, which requires old and new `Layout`, and is designed to reallocate memory. There is benefit to using `try_with_capacity`, besides syntax convenience, because it generates much smaller code at the call site with a direct call to the allocator. There's codegen test included.
It's also a very desirable functionality for users of `no_global_oom_handling` (Rust-for-Linux), since it makes a very commonly used function available in that environment (`with_capacity` is used much more frequently than all `(try_)reserve(_exact)`).
Add support for making lib features internal
We have the notion of an "internal" lang feature: a feature that is never intended to be stabilized, and using which can cause ICEs and other issues without that being considered a bug.
This extends that idea to lib features as well. It is an alternative to https://github.com/rust-lang/rust/pull/115623: instead of using an attribute to declare lib features internal, we simply do this based on the name. Everything ending in `_internals` or `_internal` is considered internal.
Then we rename `core_intrinsics` to `core_intrinsics_internal`, which fixes https://github.com/rust-lang/rust/issues/115597.
Expand in-place iteration specialization to Flatten, FlatMap and ArrayChunks
This enables the following cases to collect in-place:
```rust
let v = vec![[0u8; 4]; 1024]
let v: Vec<_> = v.into_iter().flatten().collect();
let v: Vec<Option<NonZeroUsize>> = vec![NonZeroUsize::new(0); 1024];
let v: Vec<_> = v.into_iter().flatten().collect();
let v = vec![u8; 4096];
let v: Vec<_> = v.into_iter().array_chunks::<4>().collect();
```
Especially the nicheful-option-flattening should be useful in real code.
Partial stabilization of `once_cell`
This PR aims to stabilize a portion of the `once_cell` feature:
- `core::cell::OnceCell`
- `std::cell::OnceCell` (re-export of the above)
- `std::sync::OnceLock`
This will leave `LazyCell` and `LazyLock` unstabilized, which have been moved to the `lazy_cell` feature flag.
Tracking issue: https://github.com/rust-lang/rust/issues/74465 (does not fully close, but it may make sense to move to a new issue)
Future steps for separate PRs:
- ~~Add `#[inline]` to many methods~~ #105651
- Update cranelift usage of the `once_cell` crate
- Update rust-analyzer usage of the `once_cell` crate
- Update error messages discussing once_cell
## To be stabilized API summary
```rust
// core::cell (in core/cell/once.rs)
pub struct OnceCell<T> { .. }
impl<T> OnceCell<T> {
pub const fn new() -> OnceCell<T>;
pub fn get(&self) -> Option<&T>;
pub fn get_mut(&mut self) -> Option<&mut T>;
pub fn set(&self, value: T) -> Result<(), T>;
pub fn get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> T;
pub fn into_inner(self) -> Option<T>;
pub fn take(&mut self) -> Option<T>;
}
impl<T: Clone> Clone for OnceCell<T>;
impl<T: Debug> Debug for OnceCell<T>
impl<T> Default for OnceCell<T>;
impl<T> From<T> for OnceCell<T>;
impl<T: PartialEq> PartialEq for OnceCell<T>;
impl<T: Eq> Eq for OnceCell<T>;
```
```rust
// std::sync (in std/sync/once_lock.rs)
impl<T> OnceLock<T> {
pub const fn new() -> OnceLock<T>;
pub fn get(&self) -> Option<&T>;
pub fn get_mut(&mut self) -> Option<&mut T>;
pub fn set(&self, value: T) -> Result<(), T>;
pub fn get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> T;
pub fn into_inner(self) -> Option<T>;
pub fn take(&mut self) -> Option<T>;
}
impl<T: Clone> Clone for OnceLock<T>;
impl<T: Debug> Debug for OnceLock<T>;
impl<T> Default for OnceLock<T>;
impl<#[may_dangle] T> Drop for OnceLock<T>;
impl<T> From<T> for OnceLock<T>;
impl<T: PartialEq> PartialEq for OnceLock<T>
impl<T: Eq> Eq for OnceLock<T>;
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T>;
unsafe impl<T: Send> Send for OnceLock<T>;
unsafe impl<T: Sync + Send> Sync for OnceLock<T>;
impl<T: UnwindSafe> UnwindSafe for OnceLock<T>;
```
No longer planned as part of this PR, and moved to the `rust_cell_try` feature gate:
```rust
impl<T> OnceCell<T> {
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<T, E>;
}
impl<T> OnceLock<T> {
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<T, E>;
}
```
I am new to this process so would appreciate mentorship wherever needed.
Stabilize `nonnull_slice_from_raw_parts`
FCP is done: https://github.com/rust-lang/rust/issues/71941#issuecomment-1100910416
Note that this doesn't const-stabilize `NonNull::slice_from_raw_parts` as `slice_from_raw_parts_mut` isn't const-stabilized yet. Given #67456 and #57349, it's not likely available soon, meanwhile, stabilizing only the feature makes some sense, I think.
Closes#71941
Currently pretty much all of the btree_map and btree_set ones fail, as
well as linked_list::DrainFilter.
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:38:5
|
38 | / require_send_sync(async {
39 | | let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>;
40 | | async {}.await;
41 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:56:5
|
56 | / require_send_sync(async {
57 | | let _v = None::<
58 | | alloc::collections::btree_map::DrainFilter<
59 | | '_,
... |
65 | | async {}.await;
66 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:68:5
|
68 | / require_send_sync(async {
69 | | let _v = None::<alloc::collections::btree_map::Entry<'_, &u32, &u32>>;
70 | | async {}.await;
71 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:88:5
|
88 | / require_send_sync(async {
89 | | let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>;
90 | | async {}.await;
91 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:93:5
|
93 | / require_send_sync(async {
94 | | let _v = None::<alloc::collections::btree_map::IterMut<'_, &u32, &u32>>;
95 | | async {}.await;
96 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:98:5
|
98 | / require_send_sync(async {
99 | | let _v = None::<alloc::collections::btree_map::Keys<'_, &u32, &u32>>;
100 | | async {}.await;
101 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:103:5
|
103 | / require_send_sync(async {
104 | | let _v = None::<alloc::collections::btree_map::OccupiedEntry<'_, &u32, &u32>>;
105 | | async {}.await;
106 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:108:5
|
108 | / require_send_sync(async {
109 | | let _v = None::<alloc::collections::btree_map::OccupiedError<'_, &u32, &u32>>;
110 | | async {}.await;
111 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:113:5
|
113 | / require_send_sync(async {
114 | | let _v = None::<alloc::collections::btree_map::Range<'_, &u32, &u32>>;
115 | | async {}.await;
116 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:118:5
|
118 | / require_send_sync(async {
119 | | let _v = None::<alloc::collections::btree_map::RangeMut<'_, &u32, &u32>>;
120 | | async {}.await;
121 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:123:5
|
123 | / require_send_sync(async {
124 | | let _v = None::<alloc::collections::btree_map::VacantEntry<'_, &u32, &u32>>;
125 | | async {}.await;
126 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:128:5
|
128 | / require_send_sync(async {
129 | | let _v = None::<alloc::collections::btree_map::Values<'_, &u32, &u32>>;
130 | | async {}.await;
131 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:133:5
|
133 | / require_send_sync(async {
134 | | let _v = None::<alloc::collections::btree_map::ValuesMut<'_, &u32, &u32>>;
135 | | async {}.await;
136 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:146:5
|
146 | / require_send_sync(async {
147 | | let _v = None::<alloc::collections::btree_set::Difference<'_, &u32>>;
148 | | async {}.await;
149 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: implementation of `Send` is not general enough
--> library/alloc/tests/autotraits.rs:151:5
|
151 | / require_send_sync(async {
152 | | let _v = None::<alloc::collections::btree_set::DrainFilter<'_, &u32, fn(&&u32) -> bool>>;
153 | | async {}.await;
154 | | });
| |______^ implementation of `Send` is not general enough
|
= note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
= note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:156:5
|
156 | / require_send_sync(async {
157 | | let _v = None::<alloc::collections::btree_set::Intersection<'_, &u32>>;
158 | | async {}.await;
159 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:166:5
|
166 | / require_send_sync(async {
167 | | let _v = None::<alloc::collections::btree_set::Iter<'_, &u32>>;
168 | | async {}.await;
169 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:171:5
|
171 | / require_send_sync(async {
172 | | let _v = None::<alloc::collections::btree_set::Range<'_, &u32>>;
173 | | async {}.await;
174 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:176:5
|
176 | / require_send_sync(async {
177 | | let _v = None::<alloc::collections::btree_set::SymmetricDifference<'_, &u32>>;
178 | | async {}.await;
179 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: higher-ranked lifetime error
--> library/alloc/tests/autotraits.rs:181:5
|
181 | / require_send_sync(async {
182 | | let _v = None::<alloc::collections::btree_set::Union<'_, &u32>>;
183 | | async {}.await;
184 | | });
| |______^
|
= note: could not prove `impl Future<Output = ()>: Send`
error: future cannot be sent between threads safely
--> library/alloc/tests/autotraits.rs:243:23
|
243 | require_send_sync(async {
| _______________________^
244 | | let _v =
245 | | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
246 | | async {}.await;
247 | | });
| |_____^ future created by async block is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NonNull<std::collections::linked_list::Node<&u32>>`
note: future is not `Send` as this value is used across an await
--> library/alloc/tests/autotraits.rs:246:17
|
244 | let _v =
| -- has type `Option<std::collections::linked_list::DrainFilter<'_, &u32, for<'a, 'b> fn(&'a mut &'b u32) -> bool>>` which is not `Send`
245 | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
246 | async {}.await;
| ^^^^^^ await occurs here, with `_v` maybe used later
247 | });
| - `_v` is later dropped here
note: required by a bound in `require_send_sync`
--> library/alloc/tests/autotraits.rs:3:25
|
3 | fn require_send_sync<T: Send + Sync>(_: T) {}
| ^^^^ required by this bound in `require_send_sync`
error: future cannot be shared between threads safely
--> library/alloc/tests/autotraits.rs:243:23
|
243 | require_send_sync(async {
| _______________________^
244 | | let _v =
245 | | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
246 | | async {}.await;
247 | | });
| |_____^ future created by async block is not `Sync`
|
= help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `NonNull<std::collections::linked_list::Node<&u32>>`
note: future is not `Sync` as this value is used across an await
--> library/alloc/tests/autotraits.rs:246:17
|
244 | let _v =
| -- has type `Option<std::collections::linked_list::DrainFilter<'_, &u32, for<'a, 'b> fn(&'a mut &'b u32) -> bool>>` which is not `Sync`
245 | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
246 | async {}.await;
| ^^^^^^ await occurs here, with `_v` maybe used later
247 | });
| - `_v` is later dropped here
note: required by a bound in `require_send_sync`
--> library/alloc/tests/autotraits.rs:3:32
|
3 | fn require_send_sync<T: Send + Sync>(_: T) {}
| ^^^^ required by this bound in `require_send_sync`
Stabilize bench_black_box
This PR stabilize `feature(bench_black_box)`.
```rust
pub fn black_box<T>(dummy: T) -> T;
```
The FCP was completed in https://github.com/rust-lang/rust/issues/64102.
`@rustbot` label +T-libs-api -T-libs
Since `len` and `is_empty` are not const stable yet, this also
creates a new feature for them since they previously used the same
`const_btree_new` feature.
Add `vec::Drain{,Filter}::keep_rest`
This PR adds `keep_rest` methods to `vec::Drain` and `vec::DrainFilter` under `drain_keep_rest` feature gate:
```rust
// mod alloc::vec
impl<T, A: Allocator> Drain<'_, T, A> {
pub fn keep_rest(self);
}
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
pub fn keep_rest(self);
}
```
Both these methods cancel draining of elements that were not yet yielded from the iterators. While this needs more testing & documentation, I want at least start the discussion. This may be a potential way out of the "should `DrainFilter` exhaust itself on drop?" argument.
Optimized vec::IntoIter::next_chunk impl
```
x86_64v1, default
test vec::bench_next_chunk ... bench: 696 ns/iter (+/- 22)
x86_64v1, pr
test vec::bench_next_chunk ... bench: 309 ns/iter (+/- 4)
znver2, default
test vec::bench_next_chunk ... bench: 17,272 ns/iter (+/- 117)
znver2, pr
test vec::bench_next_chunk ... bench: 211 ns/iter (+/- 3)
```
On znver2 the default impl seems to be slow due to different inlining decisions. It goes through `core::array::iter_next_chunk`
which has a deep call tree.
Stabilize the `core_c_str` and `alloc_c_string` feature gates.
Change `std::ffi` to re-export these types rather than creating type
aliases, since they now have matching stability.
This only stabilizes the base types, not the non-zero variants, since
those have their own separate tracking issue and have not gone through
FCP to stabilize.
Classify BinaryHeap & LinkedList unit tests as such
All but one of these so-called integration test case are unit tests, just like btree's were (#75531). In addition, reunite the unit tests of linked_list that were split off during #23104 because they needed to remain unit tests (they were later moved to the separate file they are in during #63207). The two sets could remain separate files, but I opted to merge them back together, more or less in the order they used to be, apart from one duplicate name `test_split_off` and one duplicate tiny function `list_from`.
Relevant commit messages from squashed history in order:
Add initial version of ThinBox
update test to actually capture failure
swap to middle ptr impl based on matthieu-m's design
Fix stack overflow in debug impl
The previous version would take a `&ThinBox<T>` and deref it once, which
resulted in a no-op and the same type, which it would then print causing
an endless recursion. I've switched to calling `deref` by name to let
method resolution handle deref the correct number of times.
I've also updated the Drop impl for good measure since it seemed like it
could be falling prey to the same bug, and I'll be adding some tests to
verify that the drop is happening correctly.
add test to verify drop is behaving
add doc examples and remove unnecessary Pointee bounds
ThinBox: use NonNull
ThinBox: tests for size
Apply suggestions from code review
Co-authored-by: Alphyr <47725341+a1phyr@users.noreply.github.com>
use handle_alloc_error and fix drop signature
update niche and size tests
add cfg for allocating APIs
check null before calculating offset
add test for zst and trial usage
prevent optimizer induced ub in drop and cleanup metadata gathering
account for arbitrary size and alignment metadata
Thank you nika and thomcc!
Update library/alloc/src/boxed/thin.rs
Co-authored-by: Josh Triplett <josh@joshtriplett.org>
Update library/alloc/src/boxed/thin.rs
Co-authored-by: Josh Triplett <josh@joshtriplett.org>