mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-27 07:03:45 +00:00
Auto merge of #109692 - Nilstrieb:rollup-hq65rps, r=Nilstrieb
Rollup of 8 pull requests Successful merges: - #91793 (socket ancillary data implementation for FreeBSD (from 13 and above).) - #92284 (Change advance(_back)_by to return the remainder instead of the number of processed elements) - #102472 (stop special-casing `'static` in evaluation) - #108480 (Use Rayon's TLV directly) - #109321 (Erase impl regions when checking for impossible to eagerly monomorphize items) - #109470 (Correctly substitute GAT's type used in `normalize_param_env` in `check_type_bounds`) - #109562 (Update ar_archive_writer to 0.1.3) - #109629 (remove obsolete `givens` from regionck) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
478cbb42b7
20
Cargo.lock
20
Cargo.lock
@ -106,11 +106,11 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
|
||||
checksum = "b0639441fd17a3197d1cbca8dc8768cc172a63b64b4bb6c372e8f41ed0acc9bb"
|
||||
dependencies = [
|
||||
"object 0.29.0",
|
||||
"object 0.30.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2689,9 +2689,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
@ -4160,21 +4160,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-rayon"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a79f0b0b2609e2eacf9758013f50e7176cb4b29fd6436a747b14a5362c8727a"
|
||||
checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rustc-rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-rayon-core"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02269144a0db9bb55cf5d4a41a5a0e95b334b0b78b08269018ca9b0250718c30"
|
||||
checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
|
@ -235,9 +235,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -25,7 +25,7 @@ target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
|
||||
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
||||
indexmap = "1.9.1"
|
||||
indexmap = "1.9.3"
|
||||
libloading = { version = "0.7.3", optional = true }
|
||||
once_cell = "1.10.0"
|
||||
smallvec = "1.8.1"
|
||||
|
@ -110,7 +110,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
|
||||
// FIXME use ArArchiveBuilder on most targets again once reading thin archives is
|
||||
// implemented
|
||||
if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
|
||||
if true {
|
||||
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
|
||||
} else {
|
||||
Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
|
||||
|
@ -10,12 +10,12 @@ arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "1.2.1"
|
||||
cfg-if = "1.0"
|
||||
ena = "0.14.2"
|
||||
indexmap = { version = "1.9.1" }
|
||||
indexmap = { version = "1.9.3" }
|
||||
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
||||
libc = "0.2"
|
||||
measureme = "10.0.0"
|
||||
rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
|
||||
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc-rayon = { version = "0.5.0", optional = true }
|
||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||
rustc-hash = "1.1.0"
|
||||
rustc_index = { path = "../rustc_index", package = "rustc_index" }
|
||||
@ -51,4 +51,4 @@ features = [
|
||||
memmap2 = "0.2.1"
|
||||
|
||||
[features]
|
||||
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rayon", "rayon-core"]
|
||||
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon", "rustc-rayon-core"]
|
||||
|
@ -330,7 +330,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
// lifetime parameters.
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
Some(infcx),
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
|
||||
);
|
||||
infcx.process_registered_region_obligations(
|
||||
@ -727,7 +726,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
// lifetime parameters.
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
Some(infcx),
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
|
||||
);
|
||||
infcx
|
||||
@ -1876,14 +1874,17 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
impl_ty: ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let param_env = tcx.param_env(impl_ty.def_id);
|
||||
let container_id = impl_ty.container_id(tcx);
|
||||
// Given
|
||||
//
|
||||
// impl<A, B> Foo<u32> for (A, B) {
|
||||
// type Bar<C> =...
|
||||
// type Bar<C> = Wrapper<A, B, C>
|
||||
// }
|
||||
//
|
||||
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
|
||||
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
|
||||
// - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
|
||||
// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
|
||||
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
|
||||
// the *trait* with the generic associated type parameters (as bound vars).
|
||||
//
|
||||
@ -1912,56 +1913,46 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
|
||||
// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
|
||||
// the trait (notably, that X: Eq and T: Family).
|
||||
let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
|
||||
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
|
||||
if let Some(def_id) = defs.parent {
|
||||
let parent_defs = tcx.generics_of(def_id);
|
||||
InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
|
||||
tcx.mk_param_from_def(param)
|
||||
});
|
||||
}
|
||||
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
|
||||
smallvec::SmallVec::with_capacity(defs.count());
|
||||
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
|
||||
let bound_var = ty::BoundVariableKind::Ty(kind);
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
|
||||
)
|
||||
.into()
|
||||
}
|
||||
GenericParamDefKind::Lifetime => {
|
||||
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
|
||||
let bound_var = ty::BoundVariableKind::Region(kind);
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_re_late_bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
|
||||
)
|
||||
.into()
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
let bound_var = ty::BoundVariableKind::Const;
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_const(
|
||||
ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
|
||||
tcx.type_of(param.def_id).subst_identity(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
});
|
||||
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
|
||||
let impl_ty_substs = tcx.mk_substs(&substs);
|
||||
let container_id = impl_ty.container_id(tcx);
|
||||
|
||||
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
|
||||
let impl_ty_value = tcx.type_of(impl_ty.def_id).subst_identity();
|
||||
|
||||
let param_env = tcx.param_env(impl_ty.def_id);
|
||||
|
||||
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
|
||||
// Extend the impl's identity substs with late-bound GAT vars
|
||||
let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id)
|
||||
.extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
|
||||
let bound_var = ty::BoundVariableKind::Ty(kind);
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
|
||||
)
|
||||
.into()
|
||||
}
|
||||
GenericParamDefKind::Lifetime => {
|
||||
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
|
||||
let bound_var = ty::BoundVariableKind::Region(kind);
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_re_late_bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
|
||||
)
|
||||
.into()
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
let bound_var = ty::BoundVariableKind::Const;
|
||||
bound_vars.push(bound_var);
|
||||
tcx.mk_const(
|
||||
ty::ConstKind::Bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||
),
|
||||
tcx.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
});
|
||||
// When checking something like
|
||||
//
|
||||
// trait X { type Y: PartialEq<<Self as X>::Y> }
|
||||
@ -1971,9 +1962,13 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
// we want <T as X>::Y to normalize to S. This is valid because we are
|
||||
// checking the default value specifically here. Add this equality to the
|
||||
// ParamEnv for normalization specifically.
|
||||
let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs);
|
||||
let rebased_substs =
|
||||
normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
|
||||
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
|
||||
let normalize_param_env = {
|
||||
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
|
||||
match impl_ty_value.kind() {
|
||||
match normalize_impl_ty.kind() {
|
||||
ty::Alias(ty::Projection, proj)
|
||||
if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
|
||||
{
|
||||
@ -1987,7 +1982,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
ty::Binder::bind_with_vars(
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
|
||||
term: impl_ty_value.into(),
|
||||
term: normalize_impl_ty.into(),
|
||||
},
|
||||
bound_vars,
|
||||
)
|
||||
@ -2068,8 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
|
||||
let outlives_environment =
|
||||
OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
impl_ty.def_id.expect_local(),
|
||||
|
@ -114,8 +114,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
|
||||
return;
|
||||
}
|
||||
|
||||
let outlives_environment =
|
||||
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
let _ = infcx
|
||||
.err_ctxt()
|
||||
@ -675,7 +674,6 @@ fn resolve_regions_with_wf_tys<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
Some(&infcx),
|
||||
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
|
||||
);
|
||||
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
||||
|
@ -179,7 +179,7 @@ fn get_impl_substs(
|
||||
}
|
||||
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let _ =
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||
|
@ -238,15 +238,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Note that there are two tests to check that this remains true
|
||||
// (`regions-reassign-{match,let}-bound-pointer.rs`).
|
||||
//
|
||||
// 2. Things go horribly wrong if we use subtype. The reason for
|
||||
// THIS is a fairly subtle case involving bound regions. See the
|
||||
// `givens` field in `region_constraints`, as well as the test
|
||||
// 2. An outdated issue related to the old HIR borrowck. See the test
|
||||
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
|
||||
// for details. Short version is that we must sometimes detect
|
||||
// relationships between specific region variables and regions
|
||||
// bound in a closure signature, and that detection gets thrown
|
||||
// off when we substitute fresh region variables here to enable
|
||||
// subtyping.
|
||||
}
|
||||
|
||||
/// Compute the new expected type and default binding mode from the old ones
|
||||
|
@ -640,11 +640,9 @@ pub fn make_query_region_constraints<'tcx>(
|
||||
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
) -> QueryRegionConstraints<'tcx> {
|
||||
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
|
||||
region_constraints;
|
||||
let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
|
||||
|
||||
assert!(verifys.is_empty());
|
||||
assert!(givens.is_empty());
|
||||
|
||||
debug!(?constraints);
|
||||
|
||||
|
@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
|
||||
const_freshen_count: u32,
|
||||
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
|
||||
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
|
||||
keep_static: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
|
||||
TypeFreshener {
|
||||
infcx,
|
||||
ty_freshen_count: 0,
|
||||
const_freshen_count: 0,
|
||||
ty_freshen_map: Default::default(),
|
||||
const_freshen_map: Default::default(),
|
||||
keep_static,
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
||||
| ty::ReFree(_)
|
||||
| ty::ReVar(_)
|
||||
| ty::RePlaceholder(..)
|
||||
| ty::ReStatic
|
||||
| ty::ReError(_)
|
||||
| ty::ReErased => {
|
||||
// replace all free regions with 'erased
|
||||
self.interner().lifetimes.re_erased
|
||||
}
|
||||
ty::ReStatic => {
|
||||
if self.keep_static {
|
||||
r
|
||||
} else {
|
||||
self.interner().lifetimes.re_erased
|
||||
}
|
||||
}
|
||||
| ty::ReErased => self.interner().lifetimes.re_erased,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
|
||||
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
|
||||
};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::PlaceholderRegion;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
let graph = self.construct_graph();
|
||||
self.expand_givens(&graph);
|
||||
self.expansion(&mut var_data);
|
||||
self.collect_errors(&mut var_data, errors);
|
||||
self.collect_var_errors(&var_data, &graph, errors);
|
||||
@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
|
||||
// Givens are a kind of horrible hack to account for
|
||||
// constraints like 'c <= '0 that are known to hold due to
|
||||
// closure signatures (see the comment above on the `givens`
|
||||
// field). They should go away. But until they do, the role
|
||||
// of this fn is to account for the transitive nature:
|
||||
//
|
||||
// Given 'c <= '0
|
||||
// and '0 <= '1
|
||||
// then 'c <= '1
|
||||
|
||||
let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
|
||||
for (r, vid) in seeds {
|
||||
// While all things transitively reachable in the graph
|
||||
// from the variable (`'0` in the example above).
|
||||
let seed_index = NodeIndex(vid.index() as usize);
|
||||
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
|
||||
let succ_index = succ_index.0;
|
||||
|
||||
// The first N nodes correspond to the region
|
||||
// variables. Other nodes correspond to constant
|
||||
// regions.
|
||||
if succ_index < self.num_vars() {
|
||||
let succ_vid = RegionVid::new(succ_index);
|
||||
|
||||
// Add `'c <= '1`.
|
||||
self.data.givens.insert((r, succ_vid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the LUb of a given region and the empty region
|
||||
fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
|
||||
match *a_region {
|
||||
@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
) -> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
|
||||
|
||||
match *a_region {
|
||||
// Check if this relationship is implied by a given.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
if self.data.givens.contains(&(a_region, b_vid)) {
|
||||
debug!("given");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match *b_data {
|
||||
VarValue::Empty(empty_ui) => {
|
||||
let lub = match self.lub_empty(a_region) {
|
||||
|
@ -713,12 +713,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
|
||||
freshen::TypeFreshener::new(self, false)
|
||||
}
|
||||
|
||||
/// Like `freshener`, but does not replace `'static` regions.
|
||||
pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
|
||||
freshen::TypeFreshener::new(self, true)
|
||||
freshen::TypeFreshener::new(self)
|
||||
}
|
||||
|
||||
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
|
||||
@ -874,10 +869,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
|
||||
}
|
||||
|
||||
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
|
||||
}
|
||||
|
||||
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
|
||||
where
|
||||
T: at::ToTrace<'tcx>,
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::infer::free_regions::FreeRegionMap;
|
||||
use crate::infer::{GenericKind, InferCtxt};
|
||||
use crate::infer::GenericKind;
|
||||
use crate::traits::query::OutlivesBound;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
|
||||
use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
|
||||
use rustc_middle::ty::{self, Region};
|
||||
|
||||
use super::explicit_outlives_bounds;
|
||||
|
||||
@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||
region_bound_pairs: Default::default(),
|
||||
};
|
||||
|
||||
builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
|
||||
builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
|
||||
|
||||
builder
|
||||
}
|
||||
@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
|
||||
pub fn with_bounds(
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
infcx: Option<&InferCtxt<'tcx>>,
|
||||
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
) -> Self {
|
||||
let mut builder = Self::builder(param_env);
|
||||
builder.add_outlives_bounds(infcx, extra_bounds);
|
||||
builder.add_outlives_bounds(extra_bounds);
|
||||
builder.build()
|
||||
}
|
||||
|
||||
@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
|
||||
}
|
||||
|
||||
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||
///
|
||||
/// The `infcx` parameter is optional; if the implied bounds may
|
||||
/// contain inference variables, it must be supplied, in which
|
||||
/// case we will register "givens" on the inference context. (See
|
||||
/// `RegionConstraintData`.)
|
||||
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
|
||||
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
|
||||
where
|
||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
{
|
||||
@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
|
||||
self.region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
|
||||
infcx
|
||||
.expect("no infcx provided but region vars found")
|
||||
.add_given(r_a, vid_b);
|
||||
} else {
|
||||
// In principle, we could record (and take
|
||||
// advantage of) every relationship here, but
|
||||
// we are also free not to -- it simply means
|
||||
// strictly less that we can successfully type
|
||||
// check. Right now we only look for things
|
||||
// relationships between free regions. (It may
|
||||
// also be that we should revise our inference
|
||||
// system to be more general and to make use
|
||||
// of *every* relationship that arises here,
|
||||
// but presently we do not.)
|
||||
if r_a.is_free_or_static() && r_b.is_free() {
|
||||
self.region_relation.add(r_a, r_b)
|
||||
}
|
||||
}
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
|
||||
(
|
||||
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
|
||||
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
|
||||
) => self.region_relation.add(r_a, r_b),
|
||||
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
|
||||
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
|
||||
// Panic here once the linked issue is resolved!
|
||||
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
|
||||
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
|
||||
&AddConstraint(Constraint::RegSubReg(a, b)) => {
|
||||
each_edge(a, b);
|
||||
}
|
||||
&AddGiven(a, b) => {
|
||||
each_edge(a, tcx.mk_re_var(b));
|
||||
}
|
||||
&AddVerify(i) => span_bug!(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
|
@ -7,7 +7,7 @@ use super::{
|
||||
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
|
||||
/// An example is a `A <= B` where neither `A` nor `B` are
|
||||
/// inference variables.
|
||||
pub verifys: Vec<Verify<'tcx>>,
|
||||
|
||||
/// A "given" is a relationship that is known to hold. In
|
||||
/// particular, we often know from closure fn signatures that a
|
||||
/// particular free region must be a subregion of a region
|
||||
/// variable:
|
||||
///
|
||||
/// foo.iter().filter(<'a> |x: &'a &'b T| ...)
|
||||
///
|
||||
/// In situations like this, `'b` is in fact a region variable
|
||||
/// introduced by the call to `iter()`, and `'a` is a bound region
|
||||
/// on the closure (as indicated by the `<'a>` prefix). If we are
|
||||
/// naive, we wind up inferring that `'b` must be `'static`,
|
||||
/// because we require that it be greater than `'a` and we do not
|
||||
/// know what `'a` is precisely.
|
||||
///
|
||||
/// This hashmap is used to avoid that naive scenario. Basically
|
||||
/// we record the fact that `'a <= 'b` is implied by the fn
|
||||
/// signature, and then ignore the constraint when solving
|
||||
/// equations. This is a bit of a hack but seems to work.
|
||||
pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
|
||||
}
|
||||
|
||||
/// Represents a constraint that influences the inference process.
|
||||
@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
|
||||
/// We added the given `verify`.
|
||||
AddVerify(usize),
|
||||
|
||||
/// We added the given `given`.
|
||||
AddGiven(Region<'tcx>, ty::RegionVid),
|
||||
|
||||
/// We added a GLB/LUB "combination variable".
|
||||
AddCombination(CombineMapType, TwoRegions<'tcx>),
|
||||
}
|
||||
@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
|
||||
self.data.verifys.pop();
|
||||
assert_eq!(self.data.verifys.len(), index);
|
||||
}
|
||||
AddGiven(sub, sup) => {
|
||||
self.data.givens.remove(&(sub, sup));
|
||||
}
|
||||
AddCombination(Glb, ref regions) => {
|
||||
self.glbs.remove(regions);
|
||||
}
|
||||
@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
self.undo_log.push(AddVerify(index));
|
||||
}
|
||||
|
||||
pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
|
||||
// cannot add givens once regions are resolved
|
||||
if self.data.givens.insert((sub, sup)) {
|
||||
debug!("add_given({:?} <= {:?})", sub, sup);
|
||||
|
||||
self.undo_log.push(AddGiven(sub, sup));
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn make_eqregion(
|
||||
&mut self,
|
||||
origin: SubregionOrigin<'tcx>,
|
||||
@ -804,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
||||
/// Returns `true` if this region constraint data contains no constraints, and `false`
|
||||
/// otherwise.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
|
||||
constraints.is_empty()
|
||||
&& member_constraints.is_empty()
|
||||
&& verifys.is_empty()
|
||||
&& givens.is_empty()
|
||||
let RegionConstraintData { constraints, member_constraints, verifys } = self;
|
||||
constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
libloading = "0.7.1"
|
||||
tracing = "0.1"
|
||||
rustc-rayon-core = { version = "0.4.0", optional = true }
|
||||
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc-rayon = { version = "0.5.0", optional = true }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
@ -52,4 +52,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
|
||||
|
||||
[features]
|
||||
llvm = ['rustc_codegen_llvm']
|
||||
rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
|
||||
rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
|
||||
|
@ -183,7 +183,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
.try_collect_active_jobs()
|
||||
.expect("active jobs shouldn't be locked in deadlock handler")
|
||||
});
|
||||
let registry = rustc_rayon_core::Registry::current();
|
||||
let registry = rayon_core::Registry::current();
|
||||
thread::spawn(move || deadlock(query_map, ®istry));
|
||||
});
|
||||
if let Some(size) = get_stack_size() {
|
||||
|
@ -26,8 +26,8 @@ rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc-rayon-core = { version = "0.4.0", optional = true }
|
||||
rustc-rayon = { version = "0.4.0", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc-rayon = { version = "0.5.0", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -4,6 +4,8 @@ use crate::dep_graph::TaskDepsRef;
|
||||
use crate::ty::query;
|
||||
use rustc_data_structures::sync::{self, Lock};
|
||||
use rustc_errors::Diagnostic;
|
||||
#[cfg(not(parallel_compiler))]
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use thin_vec::ThinVec;
|
||||
@ -47,52 +49,15 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
|
||||
#[cfg(parallel_compiler)]
|
||||
mod tlv {
|
||||
use rustc_rayon_core as rayon_core;
|
||||
use std::ptr;
|
||||
|
||||
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
|
||||
/// This is used to get the pointer to the current `ImplicitCtxt`.
|
||||
#[inline]
|
||||
pub(super) fn get_tlv() -> *const () {
|
||||
ptr::from_exposed_addr(rayon_core::tlv::get())
|
||||
}
|
||||
|
||||
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
|
||||
/// to `value` during the call to `f`. It is restored to its previous value after.
|
||||
/// This is used to set the pointer to the new `ImplicitCtxt`.
|
||||
#[inline]
|
||||
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
|
||||
rayon_core::tlv::with(value.expose_addr(), f)
|
||||
}
|
||||
}
|
||||
use rayon_core::tlv::TLV;
|
||||
|
||||
// Otherwise define our own
|
||||
#[cfg(not(parallel_compiler))]
|
||||
mod tlv {
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
thread_local! {
|
||||
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
|
||||
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
|
||||
}
|
||||
|
||||
/// Gets the pointer to the current `ImplicitCtxt`.
|
||||
#[inline]
|
||||
pub(super) fn get_tlv() -> *const () {
|
||||
TLV.with(|tlv| tlv.get())
|
||||
}
|
||||
|
||||
/// Sets TLV to `value` during the call to `f`.
|
||||
/// It is restored to its previous value after.
|
||||
/// This is used to set the pointer to the new `ImplicitCtxt`.
|
||||
#[inline]
|
||||
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
|
||||
let old = TLV.replace(value);
|
||||
let _reset = rustc_data_structures::OnDrop(move || TLV.set(old));
|
||||
f()
|
||||
}
|
||||
thread_local! {
|
||||
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
|
||||
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -111,7 +76,11 @@ pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) ->
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
tlv::with_tlv(erase(context), f)
|
||||
TLV.with(|tlv| {
|
||||
let old = tlv.replace(erase(context));
|
||||
let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
|
||||
f()
|
||||
})
|
||||
}
|
||||
|
||||
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
|
||||
@ -120,7 +89,7 @@ pub fn with_context_opt<F, R>(f: F) -> R
|
||||
where
|
||||
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
|
||||
{
|
||||
let context = tlv::get_tlv();
|
||||
let context = TLV.get();
|
||||
if context.is_null() {
|
||||
f(None)
|
||||
} else {
|
||||
|
@ -1327,27 +1327,40 @@ fn create_mono_items_for_default_impls<'tcx>(
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Lifetimes never affect trait selection, so we are allowed to eagerly
|
||||
// instantiate an instance of an impl method if the impl (and method,
|
||||
// which we check below) is only parameterized over lifetime. In that case,
|
||||
// we use the ReErased, which has no lifetime information associated with
|
||||
// it, to validate whether or not the impl is legal to instantiate at all.
|
||||
let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
|
||||
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
unreachable!(
|
||||
"`own_requires_monomorphization` check means that \
|
||||
we should have no type/const params"
|
||||
)
|
||||
}
|
||||
};
|
||||
let impl_substs = InternalSubsts::for_item(tcx, item.owner_id.to_def_id(), only_region_params);
|
||||
let trait_ref = trait_ref.subst(tcx, impl_substs);
|
||||
|
||||
// Unlike 'lazy' monomorphization that begins by collecting items transitively
|
||||
// called by `main` or other global items, when eagerly monomorphizing impl
|
||||
// items, we never actually check that the predicates of this impl are satisfied
|
||||
// in a empty reveal-all param env (i.e. with no assumptions).
|
||||
//
|
||||
// Even though this impl has no substitutions, because we don't consider higher-
|
||||
// ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
|
||||
// we must now check that the impl has no impossible-to-satisfy predicates.
|
||||
if tcx.subst_and_check_impossible_predicates((
|
||||
item.owner_id.to_def_id(),
|
||||
&InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
|
||||
)) {
|
||||
// Even though this impl has no type or const substitutions, because we don't
|
||||
// consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to
|
||||
// be trivially false. We must now check that the impl has no impossible-to-satisfy
|
||||
// predicates.
|
||||
if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_substs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
|
||||
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
|
||||
@ -1360,12 +1373,9 @@ fn create_mono_items_for_default_impls<'tcx>(
|
||||
continue;
|
||||
}
|
||||
|
||||
let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
|
||||
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
trait_ref.substs[param.index as usize]
|
||||
}
|
||||
});
|
||||
// As mentioned above, the method is legal to eagerly instantiate if it
|
||||
// only has lifetime substitutions. This is validated by
|
||||
let substs = trait_ref.substs.extend_to(tcx, method.def_id, only_region_params);
|
||||
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
|
||||
|
||||
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
|
||||
|
@ -16,7 +16,7 @@ rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc-rayon-core = { version = "0.4.0", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -15,7 +15,7 @@ rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc-rayon-core = { version = "0.4.0", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -18,11 +18,11 @@ use std::num::NonZeroU64;
|
||||
#[cfg(parallel_compiler)]
|
||||
use {
|
||||
parking_lot::{Condvar, Mutex},
|
||||
rayon_core,
|
||||
rustc_data_structures::fx::FxHashSet,
|
||||
rustc_data_structures::sync::Lock,
|
||||
rustc_data_structures::sync::Lrc,
|
||||
rustc_data_structures::{jobserver, OnDrop},
|
||||
rustc_rayon_core as rayon_core,
|
||||
rustc_span::DUMMY_SP,
|
||||
std::iter,
|
||||
std::process,
|
||||
|
@ -4,7 +4,7 @@ version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
indexmap = "1.9.1"
|
||||
indexmap = "1.9.3"
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.12"
|
||||
|
||||
|
@ -18,4 +18,4 @@ tracing = "0.1"
|
||||
sha1 = "0.10.0"
|
||||
sha2 = "0.10.1"
|
||||
md5 = { package = "md-5", version = "0.10.0" }
|
||||
indexmap = { version = "1.9.1" }
|
||||
indexmap = { version = "1.9.3" }
|
||||
|
@ -402,7 +402,6 @@ fn resolve_negative_obligation<'tcx>(
|
||||
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
Some(&infcx),
|
||||
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
|
||||
);
|
||||
|
||||
|
@ -111,7 +111,6 @@ pub fn type_allowed_to_implement_copy<'tcx>(
|
||||
// Check regions assuming the self type of the impl is WF
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
Some(&infcx),
|
||||
infcx.implied_bounds_tys(
|
||||
param_env,
|
||||
parent_cause.body_id,
|
||||
|
@ -3,7 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty};
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
||||
pub use rustc_middle::traits::query::OutlivesBound;
|
||||
@ -52,6 +53,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
body_id: LocalDefId,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
|
||||
assert!(!ty.needs_infer());
|
||||
|
||||
let span = self.tcx.def_span(body_id);
|
||||
let result = param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
@ -106,10 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
tys: FxIndexSet<Ty<'tcx>>,
|
||||
) -> Bounds<'a, 'tcx> {
|
||||
tys.into_iter()
|
||||
.map(move |ty| {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
self.implied_outlives_bounds(param_env, body_id, ty)
|
||||
})
|
||||
.map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx,
|
||||
freshener: infcx.freshener_keep_static(),
|
||||
freshener: infcx.freshener(),
|
||||
intercrate_ambiguity_causes: None,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
@ -770,14 +770,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
|
||||
// A global type with no late-bound regions can only
|
||||
// contain the "'static" lifetime (any other lifetime
|
||||
// would either be late-bound or local), so it is guaranteed
|
||||
// to outlive any other lifetime
|
||||
if pred.0.is_global() && !pred.0.has_late_bound_vars() {
|
||||
Ok(EvaluatedToOk)
|
||||
} else {
|
||||
// A global type with no free lifetimes or generic parameters
|
||||
// outlives anything.
|
||||
if pred.0.has_free_regions()
|
||||
|| pred.0.has_late_bound_regions()
|
||||
|| pred.0.has_non_region_infer()
|
||||
|| pred.0.has_non_region_infer()
|
||||
{
|
||||
Ok(EvaluatedToOkModuloRegions)
|
||||
} else {
|
||||
Ok(EvaluatedToOk)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1825,6 +1827,12 @@ enum DropVictim {
|
||||
No,
|
||||
}
|
||||
|
||||
impl DropVictim {
|
||||
fn drop_if(should_drop: bool) -> DropVictim {
|
||||
if should_drop { DropVictim::Yes } else { DropVictim::No }
|
||||
}
|
||||
}
|
||||
|
||||
/// ## Winnowing
|
||||
///
|
||||
/// Winnowing is the process of attempting to resolve ambiguity by
|
||||
@ -1890,11 +1898,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
// or the current one if tied (they should both evaluate to the same answer). This is
|
||||
// probably best characterized as a "hack", since we might prefer to just do our
|
||||
// best to *not* create essentially duplicate candidates in the first place.
|
||||
if other.bound_vars().len() <= victim.bound_vars().len() {
|
||||
DropVictim::Yes
|
||||
} else {
|
||||
DropVictim::No
|
||||
}
|
||||
DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
|
||||
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
|
||||
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
|
||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
||||
@ -1924,17 +1928,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
| ObjectCandidate(_)
|
||||
| ProjectionCandidate(..),
|
||||
) => {
|
||||
if is_global(other_cand) {
|
||||
DropVictim::No
|
||||
} else {
|
||||
// We have a where clause so don't go around looking
|
||||
// for impls. Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
//
|
||||
// Global bounds from the where clause should be ignored
|
||||
// here (see issue #50825).
|
||||
DropVictim::Yes
|
||||
}
|
||||
// We have a where clause so don't go around looking
|
||||
// for impls. Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
//
|
||||
// Global bounds from the where clause should be ignored
|
||||
// here (see issue #50825).
|
||||
DropVictim::drop_if(!is_global(other_cand))
|
||||
}
|
||||
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
@ -1956,18 +1956,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
|
||||
DropVictim::Yes
|
||||
} else {
|
||||
DropVictim::No
|
||||
}
|
||||
DropVictim::drop_if(
|
||||
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
|
||||
)
|
||||
}
|
||||
|
||||
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
|
||||
| (ObjectCandidate(i), ObjectCandidate(j)) => {
|
||||
// Arbitrarily pick the lower numbered candidate for backwards
|
||||
// compatibility reasons. Don't let this affect inference.
|
||||
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
|
||||
DropVictim::drop_if(i < j && !needs_infer)
|
||||
}
|
||||
(ObjectCandidate(_), ProjectionCandidate(..))
|
||||
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
|
||||
@ -2018,55 +2016,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if other.evaluation.must_apply_considering_regions() {
|
||||
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constraining inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrain)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
if needs_infer { DropVictim::No } else { DropVictim::Yes }
|
||||
}
|
||||
Some(_) => DropVictim::Yes,
|
||||
None => DropVictim::No,
|
||||
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
// For #33140 the impl headers must be exactly equal, the trait must not have
|
||||
// any associated items and there are no where-clauses.
|
||||
//
|
||||
// We can just arbitrarily drop one of the impls.
|
||||
Some(ty::ImplOverlapKind::Issue33140) => {
|
||||
assert_eq!(other.evaluation, victim.evaluation);
|
||||
DropVictim::Yes
|
||||
}
|
||||
} else {
|
||||
DropVictim::No
|
||||
// For candidates which already reference errors it doesn't really
|
||||
// matter what we do 🤷
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
|
||||
DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
|
||||
}
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constraining inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrain)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
DropVictim::drop_if(
|
||||
!needs_infer && other.evaluation.must_apply_considering_regions(),
|
||||
)
|
||||
}
|
||||
None => DropVictim::No,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::{FusedIterator, TrustedLen};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::{array, fmt, mem::MaybeUninit, ops::Try, ptr};
|
||||
|
||||
use crate::alloc::{Allocator, Global};
|
||||
@ -54,15 +55,16 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
if self.inner.len < n {
|
||||
let len = self.inner.len;
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let len = self.inner.len;
|
||||
let rem = if len < n {
|
||||
self.inner.clear();
|
||||
Err(len)
|
||||
n - len
|
||||
} else {
|
||||
self.inner.drain(..n);
|
||||
Ok(())
|
||||
}
|
||||
0
|
||||
};
|
||||
NonZeroUsize::new(rem).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -182,15 +184,16 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let len = self.inner.len;
|
||||
if len >= n {
|
||||
self.inner.truncate(len - n);
|
||||
Ok(())
|
||||
} else {
|
||||
let rem = if len < n {
|
||||
self.inner.clear();
|
||||
Err(len)
|
||||
}
|
||||
n - len
|
||||
} else {
|
||||
self.inner.truncate(len - n);
|
||||
0
|
||||
};
|
||||
NonZeroUsize::new(rem).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ops::Try;
|
||||
use core::{fmt, mem, slice};
|
||||
|
||||
@ -55,13 +56,15 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let m = match self.i1.advance_by(n) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(m) => m,
|
||||
};
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i1.advance_by(n - m).map_err(|o| o + m)
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let remaining = self.i1.advance_by(n);
|
||||
match remaining {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(n) => {
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i1.advance_by(n.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -125,14 +128,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let m = match self.i2.advance_back_by(n) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(m) => m,
|
||||
};
|
||||
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i2.advance_back_by(n - m).map_err(|o| m + o)
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
match self.i2.advance_back_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(n) => {
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i2.advance_back_by(n.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ops::Try;
|
||||
use core::{fmt, mem, slice};
|
||||
|
||||
@ -47,13 +48,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let m = match self.i1.advance_by(n) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(m) => m,
|
||||
};
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i1.advance_by(n - m).map_err(|o| o + m)
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
match self.i1.advance_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(remaining) => {
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i1.advance_by(remaining.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -117,14 +119,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let m = match self.i2.advance_back_by(n) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(m) => m,
|
||||
};
|
||||
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i2.advance_back_by(n - m).map_err(|o| m + o)
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
match self.i2.advance_back_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(remaining) => {
|
||||
mem::swap(&mut self.i1, &mut self.i2);
|
||||
self.i2.advance_back_by(remaining.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc
|
||||
|
@ -11,6 +11,7 @@ use core::iter::{
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||
use core::num::NonZeroUsize;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::ops::Deref;
|
||||
use core::ptr::{self, NonNull};
|
||||
@ -213,7 +214,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let step_size = self.len().min(n);
|
||||
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
|
||||
if T::IS_ZST {
|
||||
@ -227,10 +228,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
unsafe {
|
||||
ptr::drop_in_place(to_drop);
|
||||
}
|
||||
if step_size < n {
|
||||
return Err(step_size);
|
||||
}
|
||||
Ok(())
|
||||
NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -313,7 +311,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let step_size = self.len().min(n);
|
||||
if T::IS_ZST {
|
||||
// SAFETY: same as for advance_by()
|
||||
@ -327,10 +325,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
unsafe {
|
||||
ptr::drop_in_place(to_drop);
|
||||
}
|
||||
if step_size < n {
|
||||
return Err(step_size);
|
||||
}
|
||||
Ok(())
|
||||
NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
use core::alloc::{Allocator, Layout};
|
||||
use core::assert_eq;
|
||||
use core::iter::IntoIterator;
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ptr::NonNull;
|
||||
use std::alloc::System;
|
||||
use std::assert_matches::assert_matches;
|
||||
@ -1062,21 +1064,21 @@ fn test_into_iter_leak() {
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_advance_by() {
|
||||
let mut i = [1, 2, 3, 4, 5].into_iter();
|
||||
i.advance_by(0).unwrap();
|
||||
i.advance_back_by(0).unwrap();
|
||||
let mut i = vec![1, 2, 3, 4, 5].into_iter();
|
||||
assert_eq!(i.advance_by(0), Ok(()));
|
||||
assert_eq!(i.advance_back_by(0), Ok(()));
|
||||
assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
|
||||
|
||||
i.advance_by(1).unwrap();
|
||||
i.advance_back_by(1).unwrap();
|
||||
assert_eq!(i.advance_by(1), Ok(()));
|
||||
assert_eq!(i.advance_back_by(1), Ok(()));
|
||||
assert_eq!(i.as_slice(), [2, 3, 4]);
|
||||
|
||||
assert_eq!(i.advance_back_by(usize::MAX), Err(3));
|
||||
assert_eq!(i.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 3).unwrap()));
|
||||
|
||||
assert_eq!(i.advance_by(usize::MAX), Err(0));
|
||||
assert_eq!(i.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
|
||||
|
||||
i.advance_by(0).unwrap();
|
||||
i.advance_back_by(0).unwrap();
|
||||
assert_eq!(i.advance_by(0), Ok(()));
|
||||
assert_eq!(i.advance_back_by(0), Ok(()));
|
||||
|
||||
assert_eq!(i.len(), 0);
|
||||
}
|
||||
@ -1124,7 +1126,7 @@ fn test_into_iter_zst() {
|
||||
for _ in vec![C; 5].into_iter().rev() {}
|
||||
|
||||
let mut it = vec![C, C].into_iter();
|
||||
it.advance_by(1).unwrap();
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
drop(it);
|
||||
|
||||
let mut it = vec![C, C].into_iter();
|
||||
|
@ -1,3 +1,4 @@
|
||||
use core::num::NonZeroUsize;
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::collections::TryReserveErrorKind::*;
|
||||
use std::collections::{vec_deque::Drain, VecDeque};
|
||||
@ -426,6 +427,28 @@ fn test_into_iter() {
|
||||
assert_eq!(it.next(), Some(7));
|
||||
assert_eq!(it.size_hint(), (5, Some(5)));
|
||||
}
|
||||
|
||||
// advance_by
|
||||
{
|
||||
let mut d = VecDeque::new();
|
||||
for i in 0..=4 {
|
||||
d.push_back(i);
|
||||
}
|
||||
for i in 6..=8 {
|
||||
d.push_front(i);
|
||||
}
|
||||
|
||||
let mut it = d.into_iter();
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.next(), Some(7));
|
||||
assert_eq!(it.advance_back_by(1), Ok(()));
|
||||
assert_eq!(it.next_back(), Some(3));
|
||||
|
||||
let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
|
||||
assert_eq!(it.advance_by(10), Err(NonZeroUsize::new(5).unwrap()));
|
||||
let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
|
||||
assert_eq!(it.advance_back_by(10), Err(NonZeroUsize::new(5).unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Defines the `IntoIter` owned iterator for arrays.
|
||||
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::{
|
||||
fmt,
|
||||
iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
|
||||
@ -284,12 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
||||
self.next_back()
|
||||
}
|
||||
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let original_len = self.len();
|
||||
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// This also moves the start, which marks them as conceptually "dropped",
|
||||
// so if anything goes bad then our drop impl won't double-free them.
|
||||
let range_to_drop = self.alive.take_prefix(n);
|
||||
let remaining = n - range_to_drop.len();
|
||||
|
||||
// SAFETY: These elements are currently initialized, so it's fine to drop them.
|
||||
unsafe {
|
||||
@ -297,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
||||
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
|
||||
}
|
||||
|
||||
if n > original_len { Err(original_len) } else { Ok(()) }
|
||||
NonZeroUsize::new(remaining).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,12 +334,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
|
||||
})
|
||||
}
|
||||
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let original_len = self.len();
|
||||
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// This also moves the end, which marks them as conceptually "dropped",
|
||||
// so if anything goes bad then our drop impl won't double-free them.
|
||||
let range_to_drop = self.alive.take_suffix(n);
|
||||
let remaining = n - range_to_drop.len();
|
||||
|
||||
// SAFETY: These elements are currently initialized, so it's fine to drop them.
|
||||
unsafe {
|
||||
@ -347,7 +346,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
|
||||
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
|
||||
}
|
||||
|
||||
if n > original_len { Err(original_len) } else { Ok(()) }
|
||||
NonZeroUsize::new(remaining).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{NeverShortCircuit, Try};
|
||||
|
||||
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
|
||||
@ -26,7 +27,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
I::advance_by(self.0, n)
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
I::advance_back_by(self.0, n)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::Try;
|
||||
|
||||
/// An iterator that links two iterators together, in a chain.
|
||||
@ -95,38 +96,33 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let mut rem = n;
|
||||
|
||||
fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
|
||||
if let Some(ref mut a) = self.a {
|
||||
match a.advance_by(rem) {
|
||||
n = match a.advance_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(k) => rem -= k,
|
||||
}
|
||||
Err(k) => k.get(),
|
||||
};
|
||||
self.a = None;
|
||||
}
|
||||
|
||||
if let Some(ref mut b) = self.b {
|
||||
match b.advance_by(rem) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(k) => rem -= k,
|
||||
}
|
||||
return b.advance_by(n);
|
||||
// we don't fuse the second iterator
|
||||
}
|
||||
|
||||
if rem == 0 { Ok(()) } else { Err(n - rem) }
|
||||
NonZeroUsize::new(n).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||
if let Some(ref mut a) = self.a {
|
||||
match a.advance_by(n) {
|
||||
n = match a.advance_by(n) {
|
||||
Ok(()) => match a.next() {
|
||||
None => n = 0,
|
||||
None => 0,
|
||||
x => return x,
|
||||
},
|
||||
Err(k) => n -= k,
|
||||
}
|
||||
Err(k) => k.get(),
|
||||
};
|
||||
|
||||
self.a = None;
|
||||
}
|
||||
@ -186,38 +182,33 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let mut rem = n;
|
||||
|
||||
fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
|
||||
if let Some(ref mut b) = self.b {
|
||||
match b.advance_back_by(rem) {
|
||||
n = match b.advance_back_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(k) => rem -= k,
|
||||
}
|
||||
Err(k) => k.get(),
|
||||
};
|
||||
self.b = None;
|
||||
}
|
||||
|
||||
if let Some(ref mut a) = self.a {
|
||||
match a.advance_back_by(rem) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(k) => rem -= k,
|
||||
}
|
||||
return a.advance_back_by(n);
|
||||
// we don't fuse the second iterator
|
||||
}
|
||||
|
||||
if rem == 0 { Ok(()) } else { Err(n - rem) }
|
||||
NonZeroUsize::new(n).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||
if let Some(ref mut b) = self.b {
|
||||
match b.advance_back_by(n) {
|
||||
n = match b.advance_back_by(n) {
|
||||
Ok(()) => match b.next_back() {
|
||||
None => n = 0,
|
||||
None => 0,
|
||||
x => return x,
|
||||
},
|
||||
Err(k) => n -= k,
|
||||
}
|
||||
Err(k) => k.get(),
|
||||
};
|
||||
|
||||
self.b = None;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use crate::iter::adapters::{
|
||||
use crate::iter::{FusedIterator, TrustedLen};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::mem::SizedTypeProperties;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::Try;
|
||||
use crate::{array, ptr};
|
||||
|
||||
@ -89,7 +90,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.it.advance_by(n)
|
||||
}
|
||||
|
||||
@ -130,7 +131,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.it.advance_back_by(n)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::{iter::FusedIterator, ops::Try};
|
||||
|
||||
/// An iterator that repeats endlessly.
|
||||
@ -81,23 +82,22 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let mut rem = n;
|
||||
match self.iter.advance_by(rem) {
|
||||
ret @ Ok(_) => return ret,
|
||||
Err(advanced) => rem -= advanced,
|
||||
}
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let mut n = match self.iter.advance_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(rem) => rem.get(),
|
||||
};
|
||||
|
||||
while rem > 0 {
|
||||
while n > 0 {
|
||||
self.iter = self.orig.clone();
|
||||
match self.iter.advance_by(rem) {
|
||||
ret @ Ok(_) => return ret,
|
||||
Err(0) => return Err(n - rem),
|
||||
Err(advanced) => rem -= advanced,
|
||||
}
|
||||
n = match self.iter.advance_by(n) {
|
||||
Ok(()) => return Ok(()),
|
||||
e @ Err(rem) if rem.get() == n => return e,
|
||||
Err(rem) => rem.get(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
NonZeroUsize::new(n).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
// No `fold` override, because `fold` doesn't make much sense for `Cycle`,
|
||||
|
@ -2,6 +2,7 @@ use crate::iter::adapters::{
|
||||
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
|
||||
};
|
||||
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::Try;
|
||||
|
||||
/// An iterator that yields the current count and the element during iteration.
|
||||
@ -114,17 +115,14 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
match self.iter.advance_by(n) {
|
||||
ret @ Ok(_) => {
|
||||
self.count += n;
|
||||
ret
|
||||
}
|
||||
ret @ Err(advanced) => {
|
||||
self.count += advanced;
|
||||
ret
|
||||
}
|
||||
}
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let remaining = self.iter.advance_by(n);
|
||||
let advanced = match remaining {
|
||||
Ok(()) => n,
|
||||
Err(rem) => n - rem.get(),
|
||||
};
|
||||
self.count += advanced;
|
||||
remaining
|
||||
}
|
||||
|
||||
#[rustc_inherit_overflow_checks]
|
||||
@ -208,7 +206,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// we do not need to update the count since that only tallies the number of items
|
||||
// consumed from the front. consuming items from the back can never reduce that.
|
||||
self.iter.advance_back_by(n)
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::fmt;
|
||||
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator that maps each element to an iterator, and yields the elements
|
||||
@ -75,7 +76,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.inner.advance_by(n)
|
||||
}
|
||||
|
||||
@ -120,7 +121,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.inner.advance_back_by(n)
|
||||
}
|
||||
}
|
||||
@ -236,7 +237,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.inner.advance_by(n)
|
||||
}
|
||||
|
||||
@ -281,7 +282,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.inner.advance_back_by(n)
|
||||
}
|
||||
}
|
||||
@ -552,18 +553,18 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
|
||||
match iter.advance_by(n) {
|
||||
Ok(()) => ControlFlow::Break(()),
|
||||
Err(advanced) => ControlFlow::Continue(n - advanced),
|
||||
Err(remaining) => ControlFlow::Continue(remaining.get()),
|
||||
}
|
||||
}
|
||||
|
||||
match self.iter_try_fold(n, advance) {
|
||||
ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
|
||||
ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
@ -642,18 +643,18 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
|
||||
match iter.advance_back_by(n) {
|
||||
Ok(()) => ControlFlow::Break(()),
|
||||
Err(advanced) => ControlFlow::Continue(n - advanced),
|
||||
Err(remaining) => ControlFlow::Continue(remaining.get()),
|
||||
}
|
||||
}
|
||||
|
||||
match self.iter_try_rfold(n, advance) {
|
||||
ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
|
||||
ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::iter::{FusedIterator, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::Try;
|
||||
|
||||
/// A double-ended iterator with the direction inverted.
|
||||
@ -38,7 +39,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.iter.advance_back_by(n)
|
||||
}
|
||||
|
||||
@ -83,7 +84,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.iter.advance_by(n)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::intrinsics::unlikely;
|
||||
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator that skips over `n` elements of `iter`.
|
||||
@ -128,34 +129,27 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let mut rem = n;
|
||||
let step_one = self.n.saturating_add(rem);
|
||||
fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
|
||||
let skip_inner = self.n;
|
||||
let skip_and_advance = skip_inner.saturating_add(n);
|
||||
|
||||
match self.iter.advance_by(step_one) {
|
||||
Ok(_) => {
|
||||
rem -= step_one - self.n;
|
||||
self.n = 0;
|
||||
}
|
||||
Err(advanced) => {
|
||||
let advanced_without_skip = advanced.saturating_sub(self.n);
|
||||
self.n = self.n.saturating_sub(advanced);
|
||||
return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
|
||||
let remainder = match self.iter.advance_by(skip_and_advance) {
|
||||
Ok(()) => 0,
|
||||
Err(n) => n.get(),
|
||||
};
|
||||
let advanced_inner = skip_and_advance - remainder;
|
||||
n -= advanced_inner.saturating_sub(skip_inner);
|
||||
self.n = self.n.saturating_sub(advanced_inner);
|
||||
|
||||
// skip_and_advance may have saturated
|
||||
if unlikely(remainder == 0 && n > 0) {
|
||||
n = match self.iter.advance_by(n) {
|
||||
Ok(()) => 0,
|
||||
Err(n) => n.get(),
|
||||
}
|
||||
}
|
||||
|
||||
// step_one calculation may have saturated
|
||||
if unlikely(rem > 0) {
|
||||
return match self.iter.advance_by(rem) {
|
||||
ret @ Ok(_) => ret,
|
||||
Err(advanced) => {
|
||||
rem -= advanced;
|
||||
Err(n - rem)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
NonZeroUsize::new(n).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,13 +203,11 @@ where
|
||||
impl_fold_via_try_fold! { rfold -> try_rfold }
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let min = crate::cmp::min(self.len(), n);
|
||||
return match self.iter.advance_back_by(min) {
|
||||
ret @ Ok(_) if n <= min => ret,
|
||||
Ok(_) => Err(min),
|
||||
_ => panic!("ExactSizeIterator contract violation"),
|
||||
};
|
||||
let rem = self.iter.advance_back_by(min);
|
||||
assert!(rem.is_ok(), "ExactSizeIterator contract violation");
|
||||
NonZeroUsize::new(n - min).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::cmp;
|
||||
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator that only iterates over the first `n` iterations of `iter`.
|
||||
@ -121,18 +122,15 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let min = self.n.min(n);
|
||||
match self.iter.advance_by(min) {
|
||||
Ok(_) => {
|
||||
self.n -= min;
|
||||
if min < n { Err(min) } else { Ok(()) }
|
||||
}
|
||||
ret @ Err(advanced) => {
|
||||
self.n -= advanced;
|
||||
ret
|
||||
}
|
||||
}
|
||||
let rem = match self.iter.advance_by(min) {
|
||||
Ok(()) => 0,
|
||||
Err(rem) => rem.get(),
|
||||
};
|
||||
let advanced = min - rem;
|
||||
self.n -= advanced;
|
||||
NonZeroUsize::new(n - advanced).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,7 +221,7 @@ where
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// The amount by which the inner iterator needs to be shortened for it to be
|
||||
// at most as long as the take() amount.
|
||||
let trim_inner = self.iter.len().saturating_sub(self.n);
|
||||
@ -232,12 +230,14 @@ where
|
||||
// about having to advance more than usize::MAX here.
|
||||
let advance_by = trim_inner.saturating_add(n);
|
||||
|
||||
let advanced = match self.iter.advance_back_by(advance_by) {
|
||||
Ok(_) => advance_by - trim_inner,
|
||||
Err(advanced) => advanced - trim_inner,
|
||||
let remainder = match self.iter.advance_back_by(advance_by) {
|
||||
Ok(()) => 0,
|
||||
Err(rem) => rem.get(),
|
||||
};
|
||||
self.n -= advanced;
|
||||
return if advanced < n { Err(advanced) } else { Ok(()) };
|
||||
let advanced_by_inner = advance_by - remainder;
|
||||
let advanced_by = advanced_by_inner - trim_inner;
|
||||
self.n -= advanced_by;
|
||||
NonZeroUsize::new(n - advanced_by).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::convert::TryFrom;
|
||||
use crate::marker::Destruct;
|
||||
use crate::mem;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{self, Try};
|
||||
|
||||
use super::{
|
||||
@ -530,12 +531,12 @@ trait RangeIteratorImpl {
|
||||
// Iterator
|
||||
fn spec_next(&mut self) -> Option<Self::Item>;
|
||||
fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
|
||||
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>;
|
||||
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
|
||||
|
||||
// DoubleEndedIterator
|
||||
fn spec_next_back(&mut self) -> Option<Self::Item>;
|
||||
fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
|
||||
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
|
||||
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
|
||||
}
|
||||
|
||||
impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
|
||||
@ -567,7 +568,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let available = if self.start <= self.end {
|
||||
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
|
||||
} else {
|
||||
@ -579,7 +580,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
|
||||
self.start =
|
||||
Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
|
||||
|
||||
if taken < n { Err(taken) } else { Ok(()) }
|
||||
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -608,7 +609,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let available = if self.start <= self.end {
|
||||
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
|
||||
} else {
|
||||
@ -620,7 +621,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
|
||||
self.end =
|
||||
Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
|
||||
|
||||
if taken < n { Err(taken) } else { Ok(()) }
|
||||
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -651,7 +652,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let available = if self.start <= self.end {
|
||||
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
|
||||
} else {
|
||||
@ -666,7 +667,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
|
||||
// Otherwise 0 is returned which always safe to use.
|
||||
self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) };
|
||||
|
||||
if taken < n { Err(taken) } else { Ok(()) }
|
||||
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -695,7 +696,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let available = if self.start <= self.end {
|
||||
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
|
||||
} else {
|
||||
@ -707,7 +708,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
|
||||
// SAFETY: same as the spec_advance_by() implementation
|
||||
self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) };
|
||||
|
||||
if taken < n { Err(taken) } else { Ok(()) }
|
||||
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +758,7 @@ impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.spec_advance_by(n)
|
||||
}
|
||||
|
||||
@ -836,7 +837,7 @@ impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.spec_advance_back_by(n)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::iter::{FusedIterator, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
|
||||
/// Creates a new iterator that endlessly repeats a single element.
|
||||
///
|
||||
@ -80,7 +81,7 @@ impl<A: Clone> Iterator for Repeat<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// Advancing an infinite iterator of a single element is a no-op.
|
||||
let _ = n;
|
||||
Ok(())
|
||||
@ -109,7 +110,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
// Advancing an infinite iterator of a single element is a no-op.
|
||||
let _ = n;
|
||||
Ok(())
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::iter::{FusedIterator, TrustedLen};
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::num::NonZeroUsize;
|
||||
|
||||
/// Creates a new iterator that repeats a single element a given number of times.
|
||||
///
|
||||
@ -137,7 +138,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> {
|
||||
let len = self.count;
|
||||
|
||||
if skip >= len {
|
||||
@ -145,7 +146,8 @@ impl<A: Clone> Iterator for RepeatN<A> {
|
||||
}
|
||||
|
||||
if skip > len {
|
||||
Err(len)
|
||||
// SAFETY: we just checked that the difference is positive
|
||||
Err(unsafe { NonZeroUsize::new_unchecked(skip - len) })
|
||||
} else {
|
||||
self.count = len - skip;
|
||||
Ok(())
|
||||
@ -178,7 +180,7 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
self.advance_by(n)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::marker::Destruct;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator able to yield elements from both ends.
|
||||
@ -100,10 +101,11 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// eagerly skip `n` elements starting from the back by calling [`next_back`] up
|
||||
/// to `n` times until [`None`] is encountered.
|
||||
///
|
||||
/// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by
|
||||
/// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of
|
||||
/// elements the iterator is advanced by before running out of elements (i.e. the length
|
||||
/// of the iterator). Note that `k` is always less than `n`.
|
||||
/// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by
|
||||
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k`
|
||||
/// is remaining number of steps that could not be advanced because the iterator ran out.
|
||||
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
|
||||
/// Otherwise, `k` is always less than `n`.
|
||||
///
|
||||
/// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
|
||||
/// outer iterator until it finds an inner iterator that is not empty, which then often
|
||||
@ -120,25 +122,29 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// ```
|
||||
/// #![feature(iter_advance_by)]
|
||||
///
|
||||
/// use std::num::NonZeroUsize;
|
||||
/// let a = [3, 4, 5, 6];
|
||||
/// let mut iter = a.iter();
|
||||
///
|
||||
/// assert_eq!(iter.advance_back_by(2), Ok(()));
|
||||
/// assert_eq!(iter.next_back(), Some(&4));
|
||||
/// assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
/// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped
|
||||
/// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped
|
||||
/// ```
|
||||
///
|
||||
/// [`Ok(())`]: Ok
|
||||
/// [`Err(k)`]: Err
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize>
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
|
||||
where
|
||||
Self::Item: ~const Destruct,
|
||||
{
|
||||
for i in 0..n {
|
||||
self.next_back().ok_or(i)?;
|
||||
if self.next_back().is_none() {
|
||||
// SAFETY: `i` is always less than `n`.
|
||||
return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -188,7 +194,9 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
#[stable(feature = "iter_nth_back", since = "1.37.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
self.advance_back_by(n).ok()?;
|
||||
if self.advance_back_by(n).is_err() {
|
||||
return None;
|
||||
}
|
||||
self.next_back()
|
||||
}
|
||||
|
||||
@ -374,7 +382,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
|
||||
fn next_back(&mut self) -> Option<I::Item> {
|
||||
(**self).next_back()
|
||||
}
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
(**self).advance_back_by(n)
|
||||
}
|
||||
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::array;
|
||||
use crate::cmp::{self, Ordering};
|
||||
use crate::marker::Destruct;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
|
||||
|
||||
use super::super::try_process;
|
||||
@ -308,10 +309,11 @@ pub trait Iterator {
|
||||
/// This method will eagerly skip `n` elements by calling [`next`] up to `n`
|
||||
/// times until [`None`] is encountered.
|
||||
///
|
||||
/// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by
|
||||
/// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number
|
||||
/// of elements the iterator is advanced by before running out of elements (i.e. the
|
||||
/// length of the iterator). Note that `k` is always less than `n`.
|
||||
/// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
|
||||
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered,
|
||||
/// where `k` is remaining number of steps that could not be advanced because the iterator ran out.
|
||||
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
|
||||
/// Otherwise, `k` is always less than `n`.
|
||||
///
|
||||
/// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
|
||||
/// can advance its outer iterator until it finds an inner iterator that is not empty, which
|
||||
@ -327,22 +329,26 @@ pub trait Iterator {
|
||||
/// ```
|
||||
/// #![feature(iter_advance_by)]
|
||||
///
|
||||
/// use std::num::NonZeroUsize;
|
||||
/// let a = [1, 2, 3, 4];
|
||||
/// let mut iter = a.iter();
|
||||
///
|
||||
/// assert_eq!(iter.advance_by(2), Ok(()));
|
||||
/// assert_eq!(iter.next(), Some(&3));
|
||||
/// assert_eq!(iter.advance_by(0), Ok(()));
|
||||
/// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped
|
||||
/// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize>
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
|
||||
where
|
||||
Self::Item: ~const Destruct,
|
||||
{
|
||||
for i in 0..n {
|
||||
self.next().ok_or(i)?;
|
||||
if self.next().is_none() {
|
||||
// SAFETY: `i` is always less than `n`.
|
||||
return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -4013,7 +4019,7 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(**self).size_hint()
|
||||
}
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
(**self).advance_by(n)
|
||||
}
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
|
||||
use crate::iter::{FusedIterator, TrustedLen};
|
||||
use crate::num::NonZeroUsize;
|
||||
|
||||
/// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
|
||||
///
|
||||
@ -132,10 +133,9 @@ impl Iterator for IndexRange {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let original_len = self.len();
|
||||
self.take_prefix(n);
|
||||
if n > original_len { Err(original_len) } else { Ok(()) }
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let taken = self.take_prefix(n);
|
||||
NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,10 +151,9 @@ impl DoubleEndedIterator for IndexRange {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
let original_len = self.len();
|
||||
self.take_suffix(n);
|
||||
if n > original_len { Err(original_len) } else { Ok(()) }
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let taken = self.take_suffix(n);
|
||||
NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,11 +176,11 @@ macro_rules! iterator {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let advance = cmp::min(len!(self), n);
|
||||
// SAFETY: By construction, `advance` does not exceed `self.len()`.
|
||||
unsafe { self.post_inc_start(advance) };
|
||||
if advance == n { Ok(()) } else { Err(advance) }
|
||||
NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -371,11 +371,11 @@ macro_rules! iterator {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
|
||||
let advance = cmp::min(len!(self), n);
|
||||
// SAFETY: By construction, `advance` does not exceed `self.len()`.
|
||||
unsafe { self.pre_dec_end(advance) };
|
||||
if advance == n { Ok(()) } else { Err(advance) }
|
||||
NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::array;
|
||||
use core::{array, assert_eq};
|
||||
use core::convert::TryFrom;
|
||||
use core::num::NonZeroUsize;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
#[test]
|
||||
@ -557,7 +558,7 @@ fn array_intoiter_advance_by() {
|
||||
assert_eq!(counter.get(), 13);
|
||||
|
||||
let r = it.advance_by(123456);
|
||||
assert_eq!(r, Err(87));
|
||||
assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(counter.get(), 100);
|
||||
|
||||
@ -567,7 +568,7 @@ fn array_intoiter_advance_by() {
|
||||
assert_eq!(counter.get(), 100);
|
||||
|
||||
let r = it.advance_by(10);
|
||||
assert_eq!(r, Err(0));
|
||||
assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(counter.get(), 100);
|
||||
}
|
||||
@ -610,7 +611,7 @@ fn array_intoiter_advance_back_by() {
|
||||
assert_eq!(counter.get(), 13);
|
||||
|
||||
let r = it.advance_back_by(123456);
|
||||
assert_eq!(r, Err(87));
|
||||
assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(counter.get(), 100);
|
||||
|
||||
@ -620,7 +621,7 @@ fn array_intoiter_advance_back_by() {
|
||||
assert_eq!(counter.get(), 100);
|
||||
|
||||
let r = it.advance_back_by(10);
|
||||
assert_eq!(r, Err(0));
|
||||
assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(counter.get(), 100);
|
||||
}
|
||||
@ -679,8 +680,8 @@ fn array_into_iter_fold() {
|
||||
|
||||
let a = [1, 2, 3, 4, 5, 6];
|
||||
let mut it = a.into_iter();
|
||||
it.advance_by(1).unwrap();
|
||||
it.advance_back_by(2).unwrap();
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.advance_back_by(2), Ok(()));
|
||||
let s = it.fold(10, |a, b| 10 * a + b);
|
||||
assert_eq!(s, 10234);
|
||||
}
|
||||
@ -695,8 +696,8 @@ fn array_into_iter_rfold() {
|
||||
|
||||
let a = [1, 2, 3, 4, 5, 6];
|
||||
let mut it = a.into_iter();
|
||||
it.advance_by(1).unwrap();
|
||||
it.advance_back_by(2).unwrap();
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.advance_back_by(2), Ok(()));
|
||||
let s = it.rfold(10, |a, b| 10 * a + b);
|
||||
assert_eq!(s, 10432);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use core::iter::*;
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
#[test]
|
||||
fn test_iterator_chain() {
|
||||
@ -31,28 +32,28 @@ fn test_iterator_chain_advance_by() {
|
||||
|
||||
for i in 0..xs.len() {
|
||||
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
||||
iter.advance_by(i).unwrap();
|
||||
assert_eq!(iter.advance_by(i), Ok(()));
|
||||
assert_eq!(iter.next(), Some(&xs[i]));
|
||||
assert_eq!(iter.advance_by(100), Err(len - i - 1));
|
||||
iter.advance_by(0).unwrap();
|
||||
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
|
||||
assert_eq!(iter.advance_by(0), Ok(()));
|
||||
}
|
||||
|
||||
for i in 0..ys.len() {
|
||||
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
||||
iter.advance_by(xs.len() + i).unwrap();
|
||||
assert_eq!(iter.advance_by(xs.len() + i), Ok(()));
|
||||
assert_eq!(iter.next(), Some(&ys[i]));
|
||||
assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
|
||||
iter.advance_by(0).unwrap();
|
||||
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (ys.len() - i - 1)).unwrap()));
|
||||
assert_eq!(iter.advance_by(0), Ok(()));
|
||||
}
|
||||
|
||||
let mut iter = xs.iter().chain(ys);
|
||||
iter.advance_by(len).unwrap();
|
||||
assert_eq!(iter.advance_by(len), Ok(()));
|
||||
assert_eq!(iter.next(), None);
|
||||
iter.advance_by(0).unwrap();
|
||||
assert_eq!(iter.advance_by(0), Ok(()));
|
||||
|
||||
let mut iter = xs.iter().chain(ys);
|
||||
assert_eq!(iter.advance_by(len + 1), Err(len));
|
||||
iter.advance_by(0).unwrap();
|
||||
assert_eq!(iter.advance_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(iter.advance_by(0), Ok(()));
|
||||
}
|
||||
|
||||
test_chain(&[], &[]);
|
||||
@ -68,28 +69,28 @@ fn test_iterator_chain_advance_back_by() {
|
||||
|
||||
for i in 0..ys.len() {
|
||||
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
||||
iter.advance_back_by(i).unwrap();
|
||||
assert_eq!(iter.advance_back_by(i), Ok(()));
|
||||
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
|
||||
assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
|
||||
iter.advance_back_by(0).unwrap();
|
||||
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
|
||||
assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
}
|
||||
|
||||
for i in 0..xs.len() {
|
||||
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
||||
iter.advance_back_by(ys.len() + i).unwrap();
|
||||
assert_eq!(iter.advance_back_by(ys.len() + i), Ok(()));
|
||||
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
|
||||
assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
|
||||
iter.advance_back_by(0).unwrap();
|
||||
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (xs.len() - i - 1)).unwrap()));
|
||||
assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
}
|
||||
|
||||
let mut iter = xs.iter().chain(ys);
|
||||
iter.advance_back_by(len).unwrap();
|
||||
assert_eq!(iter.advance_back_by(len), Ok(()));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
iter.advance_back_by(0).unwrap();
|
||||
assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
|
||||
let mut iter = xs.iter().chain(ys);
|
||||
assert_eq!(iter.advance_back_by(len + 1), Err(len));
|
||||
iter.advance_back_by(0).unwrap();
|
||||
assert_eq!(iter.advance_back_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
}
|
||||
|
||||
test_chain(&[], &[]);
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::*;
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate() {
|
||||
@ -55,6 +56,20 @@ fn test_iterator_enumerate_count() {
|
||||
assert_eq!(xs.iter().enumerate().count(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate_advance_by() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().enumerate();
|
||||
assert_eq!(it.advance_by(0), Ok(()));
|
||||
assert_eq!(it.next(), Some((0, &0)));
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.next(), Some((2, &2)));
|
||||
assert_eq!(it.advance_by(2), Ok(()));
|
||||
assert_eq!(it.next(), Some((5, &5)));
|
||||
assert_eq!(it.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_enumerate_fold() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
|
@ -1,5 +1,7 @@
|
||||
use core::assert_eq;
|
||||
use super::*;
|
||||
use core::iter::*;
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
#[test]
|
||||
fn test_iterator_flatten() {
|
||||
@ -61,19 +63,19 @@ fn test_flatten_try_folds() {
|
||||
fn test_flatten_advance_by() {
|
||||
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
|
||||
|
||||
it.advance_by(5).unwrap();
|
||||
assert_eq!(it.advance_by(5), Ok(()));
|
||||
assert_eq!(it.next(), Some(5));
|
||||
it.advance_by(9).unwrap();
|
||||
assert_eq!(it.advance_by(9), Ok(()));
|
||||
assert_eq!(it.next(), Some(15));
|
||||
it.advance_back_by(4).unwrap();
|
||||
assert_eq!(it.advance_back_by(4), Ok(()));
|
||||
assert_eq!(it.next_back(), Some(35));
|
||||
it.advance_back_by(9).unwrap();
|
||||
assert_eq!(it.advance_back_by(9), Ok(()));
|
||||
assert_eq!(it.next_back(), Some(25));
|
||||
|
||||
assert_eq!(it.advance_by(usize::MAX), Err(9));
|
||||
assert_eq!(it.advance_back_by(usize::MAX), Err(0));
|
||||
it.advance_by(0).unwrap();
|
||||
it.advance_back_by(0).unwrap();
|
||||
assert_eq!(it.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 9).unwrap()));
|
||||
assert_eq!(it.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
|
||||
assert_eq!(it.advance_by(0), Ok(()));
|
||||
assert_eq!(it.advance_back_by(0), Ok(()));
|
||||
assert_eq!(it.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
@ -174,19 +176,19 @@ fn test_flatten_count() {
|
||||
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
|
||||
|
||||
assert_eq!(it.clone().count(), 40);
|
||||
it.advance_by(5).unwrap();
|
||||
assert_eq!(it.advance_by(5), Ok(()));
|
||||
assert_eq!(it.clone().count(), 35);
|
||||
it.advance_back_by(5).unwrap();
|
||||
assert_eq!(it.advance_back_by(5), Ok(()));
|
||||
assert_eq!(it.clone().count(), 30);
|
||||
it.advance_by(10).unwrap();
|
||||
assert_eq!(it.advance_by(10), Ok(()));
|
||||
assert_eq!(it.clone().count(), 20);
|
||||
it.advance_back_by(8).unwrap();
|
||||
assert_eq!(it.advance_back_by(8), Ok(()));
|
||||
assert_eq!(it.clone().count(), 12);
|
||||
it.advance_by(4).unwrap();
|
||||
assert_eq!(it.advance_by(4), Ok(()));
|
||||
assert_eq!(it.clone().count(), 8);
|
||||
it.advance_back_by(5).unwrap();
|
||||
assert_eq!(it.advance_back_by(5), Ok(()));
|
||||
assert_eq!(it.clone().count(), 3);
|
||||
it.advance_by(3).unwrap();
|
||||
assert_eq!(it.advance_by(3), Ok(()));
|
||||
assert_eq!(it.clone().count(), 0);
|
||||
}
|
||||
|
||||
@ -195,18 +197,18 @@ fn test_flatten_last() {
|
||||
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
|
||||
|
||||
assert_eq!(it.clone().last(), Some(39));
|
||||
it.advance_by(5).unwrap(); // 5..40
|
||||
assert_eq!(it.advance_by(5), Ok(())); // 5..40
|
||||
assert_eq!(it.clone().last(), Some(39));
|
||||
it.advance_back_by(5).unwrap(); // 5..35
|
||||
assert_eq!(it.advance_back_by(5), Ok(())); // 5..35
|
||||
assert_eq!(it.clone().last(), Some(34));
|
||||
it.advance_by(10).unwrap(); // 15..35
|
||||
assert_eq!(it.advance_by(10), Ok(())); // 15..35
|
||||
assert_eq!(it.clone().last(), Some(34));
|
||||
it.advance_back_by(8).unwrap(); // 15..27
|
||||
assert_eq!(it.advance_back_by(8), Ok(())); // 15..27
|
||||
assert_eq!(it.clone().last(), Some(26));
|
||||
it.advance_by(4).unwrap(); // 19..27
|
||||
assert_eq!(it.advance_by(4), Ok(())); // 19..27
|
||||
assert_eq!(it.clone().last(), Some(26));
|
||||
it.advance_back_by(5).unwrap(); // 19..22
|
||||
assert_eq!(it.advance_back_by(5), Ok(())); // 19..22
|
||||
assert_eq!(it.clone().last(), Some(21));
|
||||
it.advance_by(3).unwrap(); // 22..22
|
||||
assert_eq!(it.advance_by(3), Ok(())); // 22..22
|
||||
assert_eq!(it.clone().last(), None);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::*;
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
use super::Unfuse;
|
||||
|
||||
@ -74,11 +75,14 @@ fn test_iterator_skip_nth() {
|
||||
#[test]
|
||||
fn test_skip_advance_by() {
|
||||
assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
|
||||
assert_eq!((0..0).skip(10).advance_by(1), Err(0));
|
||||
assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
|
||||
assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
|
||||
assert_eq!((0..0).skip(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(
|
||||
(0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5),
|
||||
Err(NonZeroUsize::new(usize::MAX - 16).unwrap())
|
||||
);
|
||||
assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(()));
|
||||
|
||||
assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
|
||||
assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
|
||||
assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::iter::*;
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
#[test]
|
||||
fn test_iterator_take() {
|
||||
@ -78,21 +79,21 @@ fn test_take_advance_by() {
|
||||
let mut take = (0..10).take(3);
|
||||
assert_eq!(take.advance_by(2), Ok(()));
|
||||
assert_eq!(take.next(), Some(2));
|
||||
assert_eq!(take.advance_by(1), Err(0));
|
||||
assert_eq!(take.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
|
||||
assert_eq!((0..0).take(10).advance_by(0), Ok(()));
|
||||
assert_eq!((0..0).take(10).advance_by(1), Err(0));
|
||||
assert_eq!((0..10).take(4).advance_by(5), Err(4));
|
||||
assert_eq!((0..0).take(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!((0..10).take(4).advance_by(5), Err(NonZeroUsize::new(1).unwrap()));
|
||||
|
||||
let mut take = (0..10).take(3);
|
||||
assert_eq!(take.advance_back_by(2), Ok(()));
|
||||
assert_eq!(take.next(), Some(0));
|
||||
assert_eq!(take.advance_back_by(1), Err(0));
|
||||
assert_eq!(take.advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
|
||||
assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
|
||||
assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
|
||||
assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
|
||||
assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
|
||||
assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
|
||||
assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 100).unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,3 +1,4 @@
|
||||
use core::num::NonZeroUsize;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@ -287,25 +288,25 @@ fn test_range_step() {
|
||||
#[test]
|
||||
fn test_range_advance_by() {
|
||||
let mut r = 0..usize::MAX;
|
||||
r.advance_by(0).unwrap();
|
||||
r.advance_back_by(0).unwrap();
|
||||
assert_eq!(Ok(()), r.advance_by(0));
|
||||
assert_eq!(Ok(()), r.advance_back_by(0));
|
||||
|
||||
assert_eq!(r.len(), usize::MAX);
|
||||
|
||||
r.advance_by(1).unwrap();
|
||||
r.advance_back_by(1).unwrap();
|
||||
assert_eq!(Ok(()), r.advance_by(1));
|
||||
assert_eq!(Ok(()), r.advance_back_by(1));
|
||||
|
||||
assert_eq!((r.start, r.end), (1, usize::MAX - 1));
|
||||
|
||||
assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
|
||||
assert_eq!(Err(NonZeroUsize::new(2).unwrap()), r.advance_by(usize::MAX));
|
||||
|
||||
r.advance_by(0).unwrap();
|
||||
r.advance_back_by(0).unwrap();
|
||||
assert_eq!(Ok(()), r.advance_by(0));
|
||||
assert_eq!(Ok(()), r.advance_back_by(0));
|
||||
|
||||
let mut r = 0u128..u128::MAX;
|
||||
|
||||
r.advance_by(usize::MAX).unwrap();
|
||||
r.advance_back_by(usize::MAX).unwrap();
|
||||
assert_eq!(Ok(()), r.advance_by(usize::MAX));
|
||||
assert_eq!(Ok(()), r.advance_back_by(usize::MAX));
|
||||
|
||||
assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
|
||||
/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
|
||||
/// return the correct element if some of them are equal.
|
||||
@ -150,11 +152,11 @@ fn test_iterator_advance_by() {
|
||||
let mut iter = v.iter();
|
||||
assert_eq!(iter.advance_by(i), Ok(()));
|
||||
assert_eq!(iter.next().unwrap(), &v[i]);
|
||||
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
|
||||
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
|
||||
}
|
||||
|
||||
assert_eq!(v.iter().advance_by(v.len()), Ok(()));
|
||||
assert_eq!(v.iter().advance_by(100), Err(v.len()));
|
||||
assert_eq!(v.iter().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -165,11 +167,11 @@ fn test_iterator_advance_back_by() {
|
||||
let mut iter = v.iter();
|
||||
assert_eq!(iter.advance_back_by(i), Ok(()));
|
||||
assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
|
||||
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
|
||||
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
|
||||
}
|
||||
|
||||
assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
|
||||
assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
|
||||
assert_eq!(v.iter().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -180,11 +182,11 @@ fn test_iterator_rev_advance_back_by() {
|
||||
let mut iter = v.iter().rev();
|
||||
assert_eq!(iter.advance_back_by(i), Ok(()));
|
||||
assert_eq!(iter.next_back().unwrap(), &v[i]);
|
||||
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
|
||||
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
|
||||
}
|
||||
|
||||
assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
|
||||
assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
|
||||
assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -424,11 +426,11 @@ fn test_iterator_rev_advance_by() {
|
||||
let mut iter = v.iter().rev();
|
||||
assert_eq!(iter.advance_by(i), Ok(()));
|
||||
assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
|
||||
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
|
||||
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
|
||||
}
|
||||
|
||||
assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
|
||||
assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
|
||||
assert_eq!(v.iter().rev().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,6 +1,7 @@
|
||||
use core::cell::Cell;
|
||||
use core::cmp::Ordering;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::num::NonZeroUsize;
|
||||
use core::result::Result::{Err, Ok};
|
||||
use core::slice;
|
||||
|
||||
@ -142,20 +143,20 @@ fn test_iterator_advance_by() {
|
||||
|
||||
for i in 0..=v.len() {
|
||||
let mut iter = v.iter();
|
||||
iter.advance_by(i).unwrap();
|
||||
assert_eq!(iter.advance_by(i), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &v[i..]);
|
||||
}
|
||||
|
||||
let mut iter = v.iter();
|
||||
assert_eq!(iter.advance_by(v.len() + 1), Err(v.len()));
|
||||
assert_eq!(iter.advance_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(iter.as_slice(), &[]);
|
||||
|
||||
let mut iter = v.iter();
|
||||
iter.advance_by(3).unwrap();
|
||||
assert_eq!(iter.advance_by(3), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &v[3..]);
|
||||
iter.advance_by(2).unwrap();
|
||||
assert_eq!(iter.advance_by(2), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &[]);
|
||||
iter.advance_by(0).unwrap();
|
||||
assert_eq!(iter.advance_by(0), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -164,20 +165,20 @@ fn test_iterator_advance_back_by() {
|
||||
|
||||
for i in 0..=v.len() {
|
||||
let mut iter = v.iter();
|
||||
iter.advance_back_by(i).unwrap();
|
||||
assert_eq!(iter.advance_back_by(i), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &v[..v.len() - i]);
|
||||
}
|
||||
|
||||
let mut iter = v.iter();
|
||||
assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len()));
|
||||
assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
|
||||
assert_eq!(iter.as_slice(), &[]);
|
||||
|
||||
let mut iter = v.iter();
|
||||
iter.advance_back_by(3).unwrap();
|
||||
assert_eq!(iter.advance_back_by(3), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
|
||||
iter.advance_back_by(2).unwrap();
|
||||
assert_eq!(iter.advance_back_by(2), Ok(()));
|
||||
assert_eq!(iter.as_slice(), &[]);
|
||||
iter.advance_back_by(0).unwrap();
|
||||
assert_eq!(iter.advance_back_by(0), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -6,6 +6,9 @@ fn main() {
|
||||
if target.contains("freebsd") {
|
||||
if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() {
|
||||
println!("cargo:rustc-cfg=freebsd12");
|
||||
} else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() {
|
||||
println!("cargo:rustc-cfg=freebsd12");
|
||||
println!("cargo:rustc-cfg=freebsd13");
|
||||
}
|
||||
} else if target.contains("linux")
|
||||
|| target.contains("netbsd")
|
||||
|
@ -86,7 +86,12 @@ fn add_to_ancillary_data<T>(
|
||||
cmsg_level: libc::c_int,
|
||||
cmsg_type: libc::c_int,
|
||||
) -> bool {
|
||||
let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
let cmsg_size = source.len().checked_mul(size_of::<T>());
|
||||
#[cfg(target_os = "freebsd")]
|
||||
let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
|
||||
|
||||
let source_len = if let Some(source_len) = cmsg_size {
|
||||
if let Ok(source_len) = u32::try_from(source_len) {
|
||||
source_len
|
||||
} else {
|
||||
@ -178,7 +183,13 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
|
||||
#[cfg(all(
|
||||
doc,
|
||||
not(target_os = "android"),
|
||||
not(target_os = "linux"),
|
||||
not(target_os = "netbsd"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
#[derive(Clone)]
|
||||
pub struct SocketCred(());
|
||||
@ -194,6 +205,11 @@ pub struct SocketCred(libc::ucred);
|
||||
#[derive(Clone)]
|
||||
pub struct SocketCred(libc::sockcred);
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
#[derive(Clone)]
|
||||
pub struct SocketCred(libc::sockcred2);
|
||||
|
||||
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
impl SocketCred {
|
||||
@ -246,6 +262,66 @@ impl SocketCred {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl SocketCred {
|
||||
/// Create a Unix credential struct.
|
||||
///
|
||||
/// PID, UID and GID is set to 0.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
#[must_use]
|
||||
pub fn new() -> SocketCred {
|
||||
SocketCred(libc::sockcred2 {
|
||||
sc_version: 0,
|
||||
sc_pid: 0,
|
||||
sc_uid: 0,
|
||||
sc_euid: 0,
|
||||
sc_gid: 0,
|
||||
sc_egid: 0,
|
||||
sc_ngroups: 0,
|
||||
sc_groups: [0; 1],
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the PID.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn set_pid(&mut self, pid: libc::pid_t) {
|
||||
self.0.sc_pid = pid;
|
||||
}
|
||||
|
||||
/// Get the current PID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_pid(&self) -> libc::pid_t {
|
||||
self.0.sc_pid
|
||||
}
|
||||
|
||||
/// Set the UID.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn set_uid(&mut self, uid: libc::uid_t) {
|
||||
self.0.sc_euid = uid;
|
||||
}
|
||||
|
||||
/// Get the current UID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_uid(&self) -> libc::uid_t {
|
||||
self.0.sc_euid
|
||||
}
|
||||
|
||||
/// Set the GID.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn set_gid(&mut self, gid: libc::gid_t) {
|
||||
self.0.sc_egid = gid;
|
||||
}
|
||||
|
||||
/// Get the current GID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_gid(&self) -> libc::gid_t {
|
||||
self.0.sc_egid
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
impl SocketCred {
|
||||
/// Create a Unix credential struct.
|
||||
@ -271,6 +347,7 @@ impl SocketCred {
|
||||
}
|
||||
|
||||
/// Get the current PID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_pid(&self) -> libc::pid_t {
|
||||
self.0.sc_pid
|
||||
@ -283,6 +360,7 @@ impl SocketCred {
|
||||
}
|
||||
|
||||
/// Get the current UID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_uid(&self) -> libc::uid_t {
|
||||
self.0.sc_uid
|
||||
@ -295,6 +373,7 @@ impl SocketCred {
|
||||
}
|
||||
|
||||
/// Get the current GID.
|
||||
#[must_use]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn get_gid(&self) -> libc::gid_t {
|
||||
self.0.sc_gid
|
||||
@ -316,7 +395,13 @@ impl<'a> Iterator for ScmRights<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
|
||||
#[cfg(all(
|
||||
doc,
|
||||
not(target_os = "android"),
|
||||
not(target_os = "linux"),
|
||||
not(target_os = "netbsd"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
|
||||
|
||||
@ -327,11 +412,21 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
|
||||
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
impl<'a> Iterator for ScmCredentials<'a> {
|
||||
type Item = SocketCred;
|
||||
@ -353,7 +448,13 @@ pub enum AncillaryError {
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub enum AncillaryData<'a> {
|
||||
ScmRights(ScmRights<'a>),
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
ScmCredentials(ScmCredentials<'a>),
|
||||
}
|
||||
|
||||
@ -376,7 +477,13 @@ impl<'a> AncillaryData<'a> {
|
||||
///
|
||||
/// `data` must contain a valid control message and the control message must be type of
|
||||
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
unsafe fn as_credentials(data: &'a [u8]) -> Self {
|
||||
let ancillary_data_iter = AncillaryDataIter::new(data);
|
||||
let scm_credentials = ScmCredentials(ancillary_data_iter);
|
||||
@ -395,6 +502,8 @@ impl<'a> AncillaryData<'a> {
|
||||
libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
|
||||
#[cfg(any(target_os = "android", target_os = "linux",))]
|
||||
libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
|
||||
#[cfg(target_os = "freebsd")]
|
||||
libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
|
||||
#[cfg(target_os = "netbsd")]
|
||||
libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
|
||||
cmsg_type => {
|
||||
@ -603,12 +712,18 @@ impl<'a> SocketAncillary<'a> {
|
||||
|
||||
/// Add credentials to the ancillary data.
|
||||
///
|
||||
/// The function returns `true` if there was enough space in the buffer.
|
||||
/// If there was not enough space then no credentials was appended.
|
||||
/// The function returns `true` if there is enough space in the buffer.
|
||||
/// If there is not enough space then no credentials will be appended.
|
||||
/// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
|
||||
/// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
|
||||
/// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
|
||||
///
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
|
||||
self.truncated = false;
|
||||
@ -617,8 +732,10 @@ impl<'a> SocketAncillary<'a> {
|
||||
&mut self.length,
|
||||
creds,
|
||||
libc::SOL_SOCKET,
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
|
||||
libc::SCM_CREDENTIALS,
|
||||
#[cfg(target_os = "freebsd")]
|
||||
libc::SCM_CREDS2,
|
||||
#[cfg(target_os = "netbsd")]
|
||||
libc::SCM_CREDS,
|
||||
)
|
||||
|
@ -808,8 +808,24 @@ impl UnixDatagram {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
#[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
|
||||
#[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
|
||||
#[cfg_attr(
|
||||
any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
),
|
||||
doc = "```no_run"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
)),
|
||||
doc = "```ignore"
|
||||
)]
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::UnixDatagram;
|
||||
///
|
||||
@ -819,7 +835,13 @@ impl UnixDatagram {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
|
||||
self.0.set_passcred(passcred)
|
||||
@ -831,7 +853,13 @@ impl UnixDatagram {
|
||||
/// Get the socket option `SO_PASSCRED`.
|
||||
///
|
||||
/// [`set_passcred`]: UnixDatagram::set_passcred
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn passcred(&self) -> io::Result<bool> {
|
||||
self.0.passcred()
|
||||
|
@ -397,8 +397,24 @@ impl UnixStream {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
#[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
|
||||
#[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
|
||||
#[cfg_attr(
|
||||
any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
),
|
||||
doc = "```no_run"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
)),
|
||||
doc = "```ignore"
|
||||
)]
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::UnixStream;
|
||||
///
|
||||
@ -408,7 +424,13 @@ impl UnixStream {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
|
||||
self.0.set_passcred(passcred)
|
||||
@ -420,7 +442,13 @@ impl UnixStream {
|
||||
/// Get the socket option `SO_PASSCRED`.
|
||||
///
|
||||
/// [`set_passcred`]: UnixStream::set_passcred
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
|
||||
#[cfg(any(
|
||||
doc,
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
|
||||
pub fn passcred(&self) -> io::Result<bool> {
|
||||
self.0.passcred()
|
||||
|
@ -646,7 +646,7 @@ fn test_send_vectored_fds_unix_stream() {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux",))]
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
|
||||
#[test]
|
||||
fn test_send_vectored_with_ancillary_to_unix_datagram() {
|
||||
fn getpid() -> libc::pid_t {
|
||||
|
@ -443,6 +443,17 @@ impl Socket {
|
||||
Ok(passcred != 0)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
|
||||
setsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT, passcred as libc::c_int)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub fn passcred(&self) -> io::Result<bool> {
|
||||
let passcred: libc::c_int = getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?;
|
||||
Ok(passcred != 0)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
let mut nonblocking = nonblocking as libc::c_int;
|
||||
|
@ -125,6 +125,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
|
||||
(Some(Mode::Std), "no_rc", None),
|
||||
(Some(Mode::Std), "no_sync", None),
|
||||
(Some(Mode::Std), "freebsd12", None),
|
||||
(Some(Mode::Std), "freebsd13", None),
|
||||
(Some(Mode::Std), "backtrace_in_libstd", None),
|
||||
/* Extra values not defined in the built-in targets yet, but used in std */
|
||||
(Some(Mode::Std), "target_env", Some(&["libnx"])),
|
||||
|
19
tests/ui/codegen/mono-impossible-2.rs
Normal file
19
tests/ui/codegen/mono-impossible-2.rs
Normal file
@ -0,0 +1,19 @@
|
||||
//compile-flags: --crate-type=lib -Clink-dead-code=on
|
||||
// build-pass
|
||||
|
||||
// Make sure that we don't monomorphize the impossible method `<() as Visit>::visit`,
|
||||
// which does not hold under a reveal-all param env.
|
||||
|
||||
pub trait Visit {
|
||||
fn visit() {}
|
||||
}
|
||||
|
||||
pub trait Array {
|
||||
type Element;
|
||||
}
|
||||
|
||||
impl<'a> Visit for () where (): Array<Element = &'a ()> {}
|
||||
|
||||
impl Array for () {
|
||||
type Element = ();
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// check-pass
|
||||
|
||||
trait Foo {
|
||||
type Assoc<T>: PartialEq<Self::Assoc<i32>>;
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
type Assoc<T> = Wrapper<T>;
|
||||
}
|
||||
|
||||
struct Wrapper<T>(T);
|
||||
|
||||
impl<T> PartialEq<Wrapper<i32>> for Wrapper<T> {
|
||||
fn eq(&self, _other: &Wrapper<i32>) -> bool { true }
|
||||
}
|
||||
|
||||
fn main() {}
|
24
tests/ui/implied-bounds/ice-unbound-region-vars.rs
Normal file
24
tests/ui/implied-bounds/ice-unbound-region-vars.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Because of #109628, we can have unbounded region vars in implied bounds.
|
||||
// Make sure we don't ICE in this case!
|
||||
//
|
||||
// check-pass
|
||||
|
||||
pub trait MapAccess {
|
||||
type Error;
|
||||
fn next_key_seed(&mut self) -> Option<Self::Error>;
|
||||
}
|
||||
|
||||
struct Access<'a> {
|
||||
_marker: std::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
// implied_bounds(Option<Self::Error>) = ['?1: 'a, ]
|
||||
// where '?1 is a fresh region var.
|
||||
impl<'a, 'b: 'a> MapAccess for Access<'a> {
|
||||
type Error = ();
|
||||
fn next_key_seed(&mut self) -> Option<Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
58
tests/ui/implied-bounds/normalization.rs
Normal file
58
tests/ui/implied-bounds/normalization.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// Test that we get implied bounds from complex projections after normalization.
|
||||
|
||||
// check-pass
|
||||
|
||||
// implementations wil ensure that
|
||||
// WF(<T as Combine<'a>>::Ty) implies T: 'a
|
||||
trait Combine<'a> {
|
||||
type Ty;
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Combine<'a> for Box<T> {
|
||||
type Ty = &'a T;
|
||||
}
|
||||
|
||||
// ======= Wrappers ======
|
||||
|
||||
// normalizes to a projection
|
||||
struct WrapA<T>(T);
|
||||
impl<'a, T> Combine<'a> for WrapA<T>
|
||||
where
|
||||
T: Combine<'a>,
|
||||
{
|
||||
type Ty = T::Ty;
|
||||
}
|
||||
|
||||
// <WrapB<T> as Combine<'a>>::Ty normalizes to a type variable ?X
|
||||
// with constraint `<T as Combine<'a>>::Ty == ?X`
|
||||
struct WrapB<T>(T);
|
||||
impl<'a, X, T> Combine<'a> for WrapB<T>
|
||||
where
|
||||
T: Combine<'a, Ty = X>,
|
||||
{
|
||||
type Ty = X;
|
||||
}
|
||||
|
||||
// <WrapC<T> as Combine<'a>>::Ty normalizes to `&'a &'?x ()`
|
||||
// with constraint `<T as Combine<'a>>::Ty == &'a &'?x ()`
|
||||
struct WrapC<T>(T);
|
||||
impl<'a, 'x: 'a, T> Combine<'a> for WrapC<T>
|
||||
where
|
||||
T: Combine<'a, Ty = &'a &'x ()>,
|
||||
{
|
||||
type Ty = &'a &'x ();
|
||||
}
|
||||
|
||||
//==== Test implied bounds ======
|
||||
|
||||
fn test_wrap<'a, 'b, 'c1, 'c2, A, B>(
|
||||
_: <WrapA<Box<A>> as Combine<'a>>::Ty, // normalized: &'a A
|
||||
_: <WrapB<Box<B>> as Combine<'b>>::Ty, // normalized: &'b B
|
||||
_: <WrapC<Box<&'c1 ()>> as Combine<'c2>>::Ty, // normalized: &'c2 &'c1 ()
|
||||
) {
|
||||
None::<&'a A>;
|
||||
None::<&'b B>;
|
||||
None::<&'c2 &'c1 ()>;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,4 +1,8 @@
|
||||
// check-pass
|
||||
// known-bug: #89515
|
||||
//
|
||||
// The trait solver cannot deal with ambiguous marker trait impls
|
||||
// if there are lifetimes involved. As we must not special-case any
|
||||
// regions this does not work, even with 'static
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
#[marker]
|
||||
|
@ -0,0 +1,31 @@
|
||||
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
|
||||
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:17
|
||||
|
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: multiple `impl`s satisfying `&'static (): Marker` found
|
||||
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
|
||||
|
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
|
||||
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:12:17
|
||||
|
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: multiple `impl`s satisfying `&'static (): Marker` found
|
||||
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
|
||||
|
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl Marker for &'static () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
@ -1,9 +1,17 @@
|
||||
// check-pass
|
||||
// known-bug: #109481
|
||||
//
|
||||
// While the `T: Copy` is always applicable when checking
|
||||
// that the impl `impl<T: Copy> F for T {}` is well formed,
|
||||
// the old trait solver can only approximate this by checking
|
||||
// that there are no inference variables in the obligation and
|
||||
// no region constraints in the evaluation result.
|
||||
//
|
||||
// Because of this we end up with ambiguity here.
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
#[marker]
|
||||
pub trait F {}
|
||||
impl<T> F for T where T: Copy {}
|
||||
impl<T> F for T where T: 'static {}
|
||||
impl<T: Copy> F for T {}
|
||||
impl<T: 'static> F for T {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -0,0 +1,14 @@
|
||||
error[E0310]: the parameter type `T` may not live long enough
|
||||
--> $DIR/overlapping-impl-1-modulo-regions.rs:14:21
|
||||
|
|
||||
LL | impl<T: Copy> F for T {}
|
||||
| ^ ...so that the type `T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | impl<T: Copy + 'static> F for T {}
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
Loading…
Reference in New Issue
Block a user