Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 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
702bf00
Fix suggestion for returning async closures
chenyukang Nov 6, 2025
c8b2a9a
rustdoc-search: remove broken index special case
notriddle Nov 6, 2025
cc733a5
Rollup merge of #146861 - antonilol:vec_deque_extend_front, r=joboet
matthiaskrgr Nov 6, 2025
01b0650
Rollup merge of #148213 - GuillaumeGomez:fix-exit-of-expansion, r=yot…
matthiaskrgr Nov 6, 2025
09a6aee
Rollup merge of #148292 - adwinwhite:assemble_object_candidate, r=lcnr
matthiaskrgr Nov 6, 2025
c778c4a
Rollup merge of #148528 - hkBst:run-make-tests-1, r=jieyouxu
matthiaskrgr Nov 6, 2025
e46403c
Rollup merge of #148554 - chenyukang:test-issue-148542, r=jieyouxu
matthiaskrgr Nov 6, 2025
41908fd
Rollup merge of #148556 - chenyukang:yukang-fix-148493-async-closure,…
matthiaskrgr Nov 6, 2025
426cef0
Rollup merge of #148561 - chenyukang:yukang-fix-148488, r=lqd
matthiaskrgr Nov 6, 2025
3fe4e4d
Rollup merge of #148563 - notriddle:index-typedata-bug, r=GuillaumeGomez
matthiaskrgr Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,21 @@ pub fn suggest_impl_trait<'tcx>(
infcx.tcx.lang_items().future_output(),
format_as_assoc,
),
(
infcx.tcx.lang_items().async_fn_trait(),
infcx.tcx.lang_items().async_fn_once_output(),
format_as_parenthesized,
),
(
infcx.tcx.lang_items().async_fn_mut_trait(),
infcx.tcx.lang_items().async_fn_once_output(),
format_as_parenthesized,
),
(
infcx.tcx.lang_items().async_fn_once_trait(),
infcx.tcx.lang_items().async_fn_once_output(),
format_as_parenthesized,
),
(
infcx.tcx.lang_items().fn_trait(),
infcx.tcx.lang_items().fn_once_output(),
Expand Down
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
Loading
Loading