Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3e2c614
Fix invalid tag closing when leaving expansion "original code"
GuillaumeGomez Oct 28, 2025
8442380
Add regression test for #148184
GuillaumeGomez Oct 28, 2025
2fbb751
Un-shadow object bound candidate in `NormalizesTo` goal
adwinwhite Oct 30, 2025
e2ac9d9
Apply suggestions
adwinwhite Oct 31, 2025
e23c155
implement VecDeque extend_front and prepend, add tests
antonilol Sep 30, 2025
5b96677
add specialization for extend_front and prepend with copied slice ite…
antonilol Nov 3, 2025
d2cfc47
add test for alias self_ty
adwinwhite Nov 5, 2025
fd6466a
run-make tests: use edition 2024
hkBst Nov 5, 2025
55b0125
Add regression test for ice
chenyukang Nov 6, 2025
a9795db
Fix ICE from async closure variance
chenyukang Nov 6, 2025
c8b2a9a
rustdoc-search: remove broken index special case
notriddle Nov 6, 2025
f7f128f
Rollup merge of #146861 - antonilol:vec_deque_extend_front, r=joboet
matthiaskrgr Nov 6, 2025
7b766e0
Rollup merge of #148213 - GuillaumeGomez:fix-exit-of-expansion, r=yot…
matthiaskrgr Nov 6, 2025
fc31898
Rollup merge of #148292 - adwinwhite:assemble_object_candidate, r=lcnr
matthiaskrgr Nov 6, 2025
320af6b
Rollup merge of #148528 - hkBst:run-make-tests-1, r=jieyouxu
matthiaskrgr Nov 6, 2025
a3409fd
Rollup merge of #148554 - chenyukang:test-issue-148542, r=jieyouxu
matthiaskrgr Nov 6, 2025
76dae76
Rollup merge of #148561 - chenyukang:yukang-fix-148488, r=lqd
matthiaskrgr Nov 6, 2025
1a6770c
Rollup merge of #148563 - notriddle:index-typedata-bug, r=GuillaumeGomez
matthiaskrgr Nov 6, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
}

Closure(..)
| CoroutineClosure(..)
| FnDef(..)
| Infer(..)
| Coroutine(..)
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,16 @@ where
self.assemble_object_bound_candidates(goal, &mut candidates);
}
}
AssembleCandidatesFrom::EnvAndBounds => {}
AssembleCandidatesFrom::EnvAndBounds => {
// This is somewhat inconsistent and may make #57893 slightly easier to exploit.
// However, it matches the behavior of the old solver. See
// `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`.
if matches!(normalized_self_ty.kind(), ty::Dynamic(..))
&& !candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
{
self.assemble_object_bound_candidates(goal, &mut candidates);
}
}
}

(candidates, failed_candidate_info)
Expand Down
113 changes: 112 additions & 1 deletion library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub use self::iter::Iter;

mod iter;

use self::spec_extend::SpecExtend;
use self::spec_extend::{SpecExtend, SpecExtendFront};

mod spec_extend;

Expand Down Expand Up @@ -179,6 +179,21 @@ impl<T, A: Allocator> VecDeque<T, A> {
self.len += 1;
}

/// Prepends an element to the buffer.
///
/// # Safety
///
/// May only be called if `deque.len() < deque.capacity()`
#[inline]
unsafe fn push_front_unchecked(&mut self, element: T) {
self.head = self.wrap_sub(self.head, 1);
// SAFETY: Because of the precondition, it's guaranteed that there is space
// in the logical array before the first element (where self.head is now).
unsafe { self.buffer_write(self.head, element) };
// This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`.
self.len += 1;
}

/// Moves an element out of the buffer
#[inline]
unsafe fn buffer_read(&mut self, off: usize) -> T {
Expand Down Expand Up @@ -505,6 +520,35 @@ impl<T, A: Allocator> VecDeque<T, A> {
}
}

/// Copies all values from `src` to `dst` in reversed order, wrapping around if needed.
/// Assumes capacity is sufficient.
/// Equivalent to calling [`VecDeque::copy_slice`] with a [reversed](https://doc.rust-lang.org/std/primitive.slice.html#method.reverse) slice.
#[inline]
unsafe fn copy_slice_reversed(&mut self, dst: usize, src: &[T]) {
/// # Safety
///
/// See [`ptr::copy_nonoverlapping`].
unsafe fn copy_nonoverlapping_reversed<T>(src: *const T, dst: *mut T, count: usize) {
for i in 0..count {
unsafe { ptr::copy_nonoverlapping(src.add(count - 1 - i), dst.add(i), 1) };
}
}

debug_assert!(src.len() <= self.capacity());
let head_room = self.capacity() - dst;
if src.len() <= head_room {
unsafe {
copy_nonoverlapping_reversed(src.as_ptr(), self.ptr().add(dst), src.len());
}
} else {
let (left, right) = src.split_at(src.len() - head_room);
unsafe {
copy_nonoverlapping_reversed(right.as_ptr(), self.ptr().add(dst), right.len());
copy_nonoverlapping_reversed(left.as_ptr(), self.ptr(), left.len());
}
}
}

/// Writes all values from `iter` to `dst`.
///
/// # Safety
Expand Down Expand Up @@ -2122,6 +2166,73 @@ impl<T, A: Allocator> VecDeque<T, A> {
unsafe { self.buffer_write(self.to_physical_idx(len), value) }
}

/// Prepends all contents of the iterator to the front of the deque.
/// The order of the contents is preserved.
///
/// To get behavior like [`append`][VecDeque::append] where elements are moved
/// from the other collection to this one, use `self.prepend(other.drain(..))`.
///
/// # Examples
///
/// ```
/// #![feature(deque_extend_front)]
/// use std::collections::VecDeque;
///
/// let mut deque = VecDeque::from([4, 5, 6]);
/// deque.prepend([1, 2, 3]);
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
/// ```
///
/// Move values between collections like [`append`][VecDeque::append] does but prepend to the front:
///
/// ```
/// #![feature(deque_extend_front)]
/// use std::collections::VecDeque;
///
/// let mut deque1 = VecDeque::from([4, 5, 6]);
/// let mut deque2 = VecDeque::from([1, 2, 3]);
/// deque1.prepend(deque2.drain(..));
/// assert_eq!(deque1, [1, 2, 3, 4, 5, 6]);
/// assert!(deque2.is_empty());
/// ```
#[unstable(feature = "deque_extend_front", issue = "146975")]
#[track_caller]
pub fn prepend<I: IntoIterator<Item = T, IntoIter: DoubleEndedIterator>>(&mut self, other: I) {
self.extend_front(other.into_iter().rev())
}

/// Prepends all contents of the iterator to the front of the deque,
/// as if [`push_front`][VecDeque::push_front] was called repeatedly with
/// the values yielded by the iterator.
///
/// # Examples
///
/// ```
/// #![feature(deque_extend_front)]
/// use std::collections::VecDeque;
///
/// let mut deque = VecDeque::from([4, 5, 6]);
/// deque.extend_front([3, 2, 1]);
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
/// ```
///
/// This behaves like [`push_front`][VecDeque::push_front] was called repeatedly:
///
/// ```
/// use std::collections::VecDeque;
///
/// let mut deque = VecDeque::from([4, 5, 6]);
/// for v in [3, 2, 1] {
/// deque.push_front(v);
/// }
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(feature = "deque_extend_front", issue = "146975")]
#[track_caller]
pub fn extend_front<I: IntoIterator<Item = T>>(&mut self, iter: I) {
<Self as SpecExtendFront<T, I::IntoIter>>::spec_extend_front(self, iter.into_iter());
}

#[inline]
fn is_contiguous(&self) -> bool {
// Do the calculation like this to avoid overflowing if len + head > usize::MAX
Expand Down
112 changes: 111 additions & 1 deletion library/alloc/src/collections/vec_deque/spec_extend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::iter::TrustedLen;
use core::iter::{Copied, Rev, TrustedLen};
use core::slice;

use super::VecDeque;
Expand Down Expand Up @@ -114,3 +114,113 @@ where
}
}
}

// Specialization trait used for VecDeque::extend_front
pub(super) trait SpecExtendFront<T, I> {
#[track_caller]
fn spec_extend_front(&mut self, iter: I);
}

impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A>
where
I: Iterator<Item = T>,
{
#[track_caller]
default fn spec_extend_front(&mut self, mut iter: I) {
// This function should be the moral equivalent of:
//
// for item in iter {
// self.push_front(item);
// }

while let Some(element) = iter.next() {
let (lower, _) = iter.size_hint();
self.reserve(lower.saturating_add(1));

// SAFETY: We just reserved space for at least one element.
unsafe { self.push_front_unchecked(element) };

// Inner loop to avoid repeatedly calling `reserve`.
while self.len < self.capacity() {
let Some(element) = iter.next() else {
return;
};
// SAFETY: The loop condition guarantees that `self.len() < self.capacity()`.
unsafe { self.push_front_unchecked(element) };
}
}
}
}

#[cfg(not(test))]
impl<T, A: Allocator> SpecExtendFront<T, vec::IntoIter<T>> for VecDeque<T, A> {
#[track_caller]
fn spec_extend_front(&mut self, mut iterator: vec::IntoIter<T>) {
let slice = iterator.as_slice();
// SAFETY: elements in the slice are forgotten after this call
unsafe { prepend_reversed(self, slice) };
iterator.forget_remaining_elements();
}
}

#[cfg(not(test))]
impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T, A> {
#[track_caller]
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
let mut iterator = iterator.into_inner();
let slice = iterator.as_slice();
// SAFETY: elements in the slice are forgotten after this call
unsafe { prepend(self, slice) };
iterator.forget_remaining_elements();
}
}

impl<'a, T, A: Allocator> SpecExtendFront<T, Copied<slice::Iter<'a, T>>> for VecDeque<T, A>
where
Copied<slice::Iter<'a, T>>: Iterator<Item = T>,
{
#[track_caller]
fn spec_extend_front(&mut self, iter: Copied<slice::Iter<'a, T>>) {
let slice = iter.into_inner().as_slice();
// SAFETY: T is Copy because Copied<slice::Iter<'a, T>> is Iterator
unsafe { prepend_reversed(self, slice) };
}
}

impl<'a, T, A: Allocator> SpecExtendFront<T, Rev<Copied<slice::Iter<'a, T>>>> for VecDeque<T, A>
where
Rev<Copied<slice::Iter<'a, T>>>: Iterator<Item = T>,
{
#[track_caller]
fn spec_extend_front(&mut self, iter: Rev<Copied<slice::Iter<'a, T>>>) {
let slice = iter.into_inner().into_inner().as_slice();
// SAFETY: T is Copy because Rev<Copied<slice::Iter<'a, T>>> is Iterator
unsafe { prepend(self, slice) };
}
}

/// # Safety
///
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
deque.reserve(slice.len());

unsafe {
deque.head = deque.wrap_sub(deque.head, slice.len());
deque.copy_slice(deque.head, slice);
deque.len += slice.len();
}
}

/// # Safety
///
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
unsafe fn prepend_reversed<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
deque.reserve(slice.len());

unsafe {
deque.head = deque.wrap_sub(deque.head, slice.len());
deque.copy_slice_reversed(deque.head, slice);
deque.len += slice.len();
}
}
2 changes: 2 additions & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
#![feature(const_default)]
#![feature(const_eval_select)]
#![feature(const_heap)]
#![feature(copied_into_inner)]
#![feature(core_intrinsics)]
#![feature(deprecated_suggestion)]
#![feature(deref_pure_trait)]
Expand Down Expand Up @@ -134,6 +135,7 @@
#![feature(ptr_alignment_type)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(rev_into_inner)]
#![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
Expand Down
2 changes: 2 additions & 0 deletions library/alloctests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#![feature(assert_matches)]
#![feature(char_internals)]
#![feature(char_max_len)]
#![feature(copied_into_inner)]
#![feature(core_intrinsics)]
#![feature(exact_size_is_empty)]
#![feature(extend_one)]
Expand All @@ -32,6 +33,7 @@
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(ptr_alignment_type)]
#![feature(ptr_internals)]
#![feature(rev_into_inner)]
#![feature(sized_type_properties)]
#![feature(slice_iter_mut_as_mut_slice)]
#![feature(slice_ptr_get)]
Expand Down
74 changes: 74 additions & 0 deletions library/alloctests/tests/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2081,3 +2081,77 @@ fn test_extend_and_prepend_from_within() {
v.extend_from_within(..);
assert_eq!(v.iter().map(|s| &**s).collect::<String>(), "123123123123");
}

#[test]
fn test_extend_front() {
let mut v = VecDeque::new();
v.extend_front(0..3);
assert_eq!(v, [2, 1, 0]);
v.extend_front(3..6);
assert_eq!(v, [5, 4, 3, 2, 1, 0]);
v.prepend([1; 4]);
assert_eq!(v, [1, 1, 1, 1, 5, 4, 3, 2, 1, 0]);

let mut v = VecDeque::with_capacity(8);
let cap = v.capacity();
v.extend(0..4);
v.truncate_front(2);
v.extend_front(4..8);
assert_eq!(v.as_slices(), ([7, 6].as_slice(), [5, 4, 2, 3].as_slice()));
assert_eq!(v.capacity(), cap);

let mut v = VecDeque::new();
v.extend_front([]);
v.extend_front(None);
v.extend_front(vec![]);
v.prepend([]);
v.prepend(None);
v.prepend(vec![]);
assert_eq!(v.capacity(), 0);
v.extend_front(Some(123));
assert_eq!(v, [123]);
}

#[test]
fn test_extend_front_specialization_vec_into_iter() {
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
let mut v = VecDeque::with_capacity(4);
v.prepend(vec![1, 2, 3]);
assert_eq!(v, [1, 2, 3]);
v.pop_back();
// this should wrap around the physical buffer
v.prepend(vec![-1, 0]);
// check it really wrapped
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));

let mut v = VecDeque::with_capacity(4);
v.extend_front(vec![1, 2, 3]);
assert_eq!(v, [3, 2, 1]);
v.pop_back();
// this should wrap around the physical buffer
v.extend_front(vec![4, 5]);
// check it really wrapped
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
}

#[test]
fn test_extend_front_specialization_copy_slice() {
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
let mut v = VecDeque::with_capacity(4);
v.prepend([1, 2, 3].as_slice().iter().copied());
assert_eq!(v, [1, 2, 3]);
v.pop_back();
// this should wrap around the physical buffer
v.prepend([-1, 0].as_slice().iter().copied());
// check it really wrapped
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));

let mut v = VecDeque::with_capacity(4);
v.extend_front([1, 2, 3].as_slice().iter().copied());
assert_eq!(v, [3, 2, 1]);
v.pop_back();
// this should wrap around the physical buffer
v.extend_front([4, 5].as_slice().iter().copied());
// check it really wrapped
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
}
Loading
Loading