remove drain-on-drop behavior from vec::DrainFilter and add #[must_use]
This commit is contained in:
parent
fa8762b7b6
commit
c0df1c8c43
6 changed files with 32 additions and 131 deletions
|
@ -753,20 +753,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.drain_filter(|error| {
|
errors.retain(|error| {
|
||||||
let Error::Invalid(
|
let Error::Invalid(
|
||||||
provided_idx,
|
provided_idx,
|
||||||
expected_idx,
|
expected_idx,
|
||||||
Compatibility::Incompatible(Some(e)),
|
Compatibility::Incompatible(Some(e)),
|
||||||
) = error else { return false };
|
) = error else { return true };
|
||||||
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
|
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
|
||||||
let trace =
|
let trace =
|
||||||
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
||||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
||||||
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
// We're done if we found errors, but we already emitted them.
|
// We're done if we found errors, but we already emitted them.
|
||||||
|
|
|
@ -1170,11 +1170,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut deduped: SsoHashSet<_> = Default::default();
|
let mut deduped: SsoHashSet<_> = Default::default();
|
||||||
result.obligations.drain_filter(|projected_obligation| {
|
result.obligations.retain(|projected_obligation| {
|
||||||
if !deduped.insert(projected_obligation.clone()) {
|
if !deduped.insert(projected_obligation.clone()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
if use_cache {
|
if use_cache {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::alloc::{Allocator, Global};
|
use crate::alloc::{Allocator, Global};
|
||||||
use core::mem::{ManuallyDrop, SizedTypeProperties};
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
|
|
||||||
|
@ -20,6 +19,7 @@ use super::Vec;
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
pub struct DrainFilter<
|
pub struct DrainFilter<
|
||||||
'a,
|
'a,
|
||||||
T,
|
T,
|
||||||
|
@ -55,59 +55,6 @@ where
|
||||||
pub fn allocator(&self) -> &A {
|
pub fn allocator(&self) -> &A {
|
||||||
self.vec.allocator()
|
self.vec.allocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keep unyielded elements in the source `Vec`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(drain_filter)]
|
|
||||||
/// #![feature(drain_keep_rest)]
|
|
||||||
///
|
|
||||||
/// let mut vec = vec!['a', 'b', 'c'];
|
|
||||||
/// let mut drain = vec.drain_filter(|_| true);
|
|
||||||
///
|
|
||||||
/// assert_eq!(drain.next().unwrap(), 'a');
|
|
||||||
///
|
|
||||||
/// // This call keeps 'b' and 'c' in the vec.
|
|
||||||
/// drain.keep_rest();
|
|
||||||
///
|
|
||||||
/// // If we wouldn't call `keep_rest()`,
|
|
||||||
/// // `vec` would be empty.
|
|
||||||
/// assert_eq!(vec, ['b', 'c']);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "drain_keep_rest", issue = "101122")]
|
|
||||||
pub fn keep_rest(self) {
|
|
||||||
// At this moment layout looks like this:
|
|
||||||
//
|
|
||||||
// _____________________/-- old_len
|
|
||||||
// / \
|
|
||||||
// [kept] [yielded] [tail]
|
|
||||||
// \_______/ ^-- idx
|
|
||||||
// \-- del
|
|
||||||
//
|
|
||||||
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
|
|
||||||
//
|
|
||||||
// 1. Move [tail] after [kept]
|
|
||||||
// 2. Update length of the original vec to `old_len - del`
|
|
||||||
// a. In case of ZST, this is the only thing we want to do
|
|
||||||
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
|
||||||
let mut this = ManuallyDrop::new(self);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// ZSTs have no identity, so we don't need to move them around.
|
|
||||||
if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
|
|
||||||
let ptr = this.vec.as_mut_ptr();
|
|
||||||
let src = ptr.add(this.idx);
|
|
||||||
let dst = src.sub(this.del);
|
|
||||||
let tail_len = this.old_len - this.idx;
|
|
||||||
src.copy_to(dst, tail_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_len = this.old_len - this.del;
|
|
||||||
this.vec.set_len(new_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||||
|
@ -153,45 +100,22 @@ impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
|
||||||
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
drain: &'b mut DrainFilter<'a, T, F, A>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
|
if self.idx < self.old_len && self.del > 0 {
|
||||||
// This is a pretty messed up state, and there isn't really an
|
// This is a pretty messed up state, and there isn't really an
|
||||||
// obviously right thing to do. We don't want to keep trying
|
// obviously right thing to do. We don't want to keep trying
|
||||||
// to execute `pred`, so we just backshift all the unprocessed
|
// to execute `pred`, so we just backshift all the unprocessed
|
||||||
// elements and tell the vec that they still exist. The backshift
|
// elements and tell the vec that they still exist. The backshift
|
||||||
// is required to prevent a double-drop of the last successfully
|
// is required to prevent a double-drop of the last successfully
|
||||||
// drained item prior to a panic in the predicate.
|
// drained item prior to a panic in the predicate.
|
||||||
let ptr = self.drain.vec.as_mut_ptr();
|
let ptr = self.vec.as_mut_ptr();
|
||||||
let src = ptr.add(self.drain.idx);
|
let src = ptr.add(self.idx);
|
||||||
let dst = src.sub(self.drain.del);
|
let dst = src.sub(self.del);
|
||||||
let tail_len = self.drain.old_len - self.drain.idx;
|
let tail_len = self.old_len - self.idx;
|
||||||
src.copy_to(dst, tail_len);
|
src.copy_to(dst, tail_len);
|
||||||
}
|
}
|
||||||
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
|
self.vec.set_len(self.old_len - self.del);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let backshift = BackshiftOnDrop { drain: self };
|
|
||||||
|
|
||||||
// Attempt to consume any remaining elements if the filter predicate
|
|
||||||
// has not yet panicked. We'll backshift any remaining elements
|
|
||||||
// whether we've already panicked or if the consumption here panics.
|
|
||||||
if !backshift.drain.panic_flag {
|
|
||||||
backshift.drain.for_each(drop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2892,6 +2892,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
||||||
/// by the iterator.
|
/// by the iterator.
|
||||||
///
|
///
|
||||||
|
/// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
|
||||||
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
|
///
|
||||||
|
/// [`retain`]: Vec::retain
|
||||||
|
///
|
||||||
/// Using this method is equivalent to the following code:
|
/// Using this method is equivalent to the following code:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -1608,36 +1608,7 @@ fn drain_filter_unconsumed() {
|
||||||
let mut vec = vec![1, 2, 3, 4];
|
let mut vec = vec![1, 2, 3, 4];
|
||||||
let drain = vec.drain_filter(|&mut x| x % 2 != 0);
|
let drain = vec.drain_filter(|&mut x| x % 2 != 0);
|
||||||
drop(drain);
|
drop(drain);
|
||||||
assert_eq!(vec, [2, 4]);
|
assert_eq!(vec, [1, 2, 3, 4]);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
let mut drain = v.drain_filter(|&mut x| x % 2 == 0);
|
|
||||||
assert_eq!(drain.next(), Some(0));
|
|
||||||
assert_eq!(drain.next(), Some(2));
|
|
||||||
|
|
||||||
drain.keep_rest();
|
|
||||||
assert_eq!(v, &[1, 3, 4, 5, 6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest_all() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
v.drain_filter(|_| true).keep_rest();
|
|
||||||
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest_none() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
let mut drain = v.drain_filter(|_| true);
|
|
||||||
|
|
||||||
drain.by_ref().for_each(drop);
|
|
||||||
|
|
||||||
drain.keep_rest();
|
|
||||||
assert_eq!(v, &[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -158,13 +158,13 @@ pub(crate) fn try_inline_glob(
|
||||||
.filter_map(|child| child.res.opt_def_id())
|
.filter_map(|child| child.res.opt_def_id())
|
||||||
.collect();
|
.collect();
|
||||||
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
|
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
|
||||||
items.drain_filter(|item| {
|
items.retain(|item| {
|
||||||
if let Some(name) = item.name {
|
if let Some(name) = item.name {
|
||||||
// If an item with the same type and name already exists,
|
// If an item with the same type and name already exists,
|
||||||
// it takes priority over the inlined stuff.
|
// it takes priority over the inlined stuff.
|
||||||
!inlined_names.insert((item.type_(), name))
|
inlined_names.insert((item.type_(), name))
|
||||||
} else {
|
} else {
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Some(items)
|
Some(items)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue