Rollup merge of #82917 - cuviper:iter-zip, r=m-ou-se

Add function core::iter::zip

This makes it a little easier to `zip` iterators:

```rust
for (x, y) in zip(xs, ys) {}
// vs.
for (x, y) in xs.into_iter().zip(ys) {}
```

You can `zip(&mut xs, &ys)` for the conventional `iter_mut()` and
`iter()`, respectively. This can also support arbitrary nesting, where
it's easier to see the item layout than with arbitrary `zip` chains:

```rust
for ((x, y), z) in zip(zip(xs, ys), zs) {}
for (x, (y, z)) in zip(xs, zip(ys, zs)) {}
// vs.
for ((x, y), z) in xs.into_iter().zip(ys).zip(xz) {}
for (x, (y, z)) in xs.into_iter().zip((ys.into_iter().zip(xz)) {}
```

It may also format more nicely, especially when the first iterator is a
longer chain of methods -- for example:

```rust
    iter::zip(
        trait_ref.substs.types().skip(1),
        impl_trait_ref.substs.types().skip(1),
    )
    // vs.
    trait_ref
        .substs
        .types()
        .skip(1)
        .zip(impl_trait_ref.substs.types().skip(1))
```

This replaces the tuple-pair `IntoIterator` in #78204.
There is prior art for the utility of this in [`itertools::zip`].

[`itertools::zip`]: https://docs.rs/itertools/0.10.0/itertools/fn.zip.html
This commit is contained in:
Dylan DPC 2021-03-27 20:37:07 +01:00 committed by GitHub
commit b2e254318d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
111 changed files with 310 additions and 256 deletions

View file

@ -15,6 +15,7 @@
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![cfg_attr(bootstrap, feature(or_patterns))]

View file

@ -12,6 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry;
use std::collections::VecDeque;
use std::iter;
// FIXME(twk): this is obviously not nice to duplicate like that
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
@ -428,7 +429,9 @@ impl AutoTraitFinder<'tcx> {
return true;
}
for (new_region, old_region) in new_substs.regions().zip(old_substs.regions()) {
for (new_region, old_region) in
iter::zip(new_substs.regions(), old_substs.regions())
{
match (new_region, old_region) {
// If both predicates have an `ReLateBound` (a HRTB) in the
// same spot, we do nothing.

View file

@ -74,23 +74,22 @@ where
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
// Check if any of the input types definitely do not unify.
if impl1_ref
.iter()
.flat_map(|tref| tref.substs.types())
.zip(impl2_ref.iter().flat_map(|tref| tref.substs.types()))
.any(|(ty1, ty2)| {
let t1 = fast_reject::simplify_type(tcx, ty1, false);
let t2 = fast_reject::simplify_type(tcx, ty2, false);
if let (Some(t1), Some(t2)) = (t1, t2) {
// Simplified successfully
// Types cannot unify if they differ in their reference mutability or simplify to different types
t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
} else {
// Types might unify
false
}
})
{
if iter::zip(
impl1_ref.iter().flat_map(|tref| tref.substs.types()),
impl2_ref.iter().flat_map(|tref| tref.substs.types()),
)
.any(|(ty1, ty2)| {
let t1 = fast_reject::simplify_type(tcx, ty1, false);
let t2 = fast_reject::simplify_type(tcx, ty2, false);
if let (Some(t1), Some(t2)) = (t1, t2) {
// Simplified successfully
// Types cannot unify if they differ in their reference mutability or simplify to different types
t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
} else {
// Types might unify
false
}
}) {
// Some types involved are definitely different, so the impls couldn't possibly overlap.
debug!("overlapping_impls: fast_reject early-exit");
return no_overlap();

View file

@ -23,6 +23,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
use std::cmp;
use std::iter;
use std::ops::ControlFlow;
/// Check if a given constant can be evaluated.
@ -672,9 +673,7 @@ pub(super) fn try_unify<'tcx>(
if a_args.len() == b_args.len() =>
{
try_unify(tcx, a.subtree(a_f), b.subtree(b_f))
&& a_args
.iter()
.zip(b_args)
&& iter::zip(a_args, b_args)
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
}
_ => false,

View file

@ -28,6 +28,7 @@ use rustc_session::DiagnosticMessageId;
use rustc_span::symbol::{kw, sym};
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
use std::fmt;
use std::iter;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
@ -161,7 +162,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
for (error, suppressed) in errors.iter().zip(is_suppressed) {
for (error, suppressed) in iter::zip(errors, is_suppressed) {
if !suppressed {
self.report_fulfillment_error(error, body_id, fallback_has_occurred);
}

View file

@ -7,6 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, GenericParamDefKind};
use rustc_span::symbol::sym;
use std::iter;
use super::InferCtxtPrivExt;
@ -51,12 +52,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
self_match_impls.push(def_id);
if trait_ref
.substs
.types()
.skip(1)
.zip(impl_trait_ref.substs.types().skip(1))
.all(|(u, v)| self.fuzzy_match_tys(u, v))
if iter::zip(
trait_ref.substs.types().skip(1),
impl_trait_ref.substs.types().skip(1),
)
.all(|(u, v)| self.fuzzy_match_tys(u, v))
{
fuzzy_match_impls.push(def_id);
}

View file

@ -1887,7 +1887,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// substitution if we find that any of the input types, when
// simplified, do not match.
obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any(
iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs).any(
|(obligation_arg, impl_arg)| {
match (obligation_arg.unpack(), impl_arg.unpack()) {
(GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {

View file

@ -692,11 +692,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let predicates = predicates.instantiate(self.infcx.tcx, substs);
debug_assert_eq!(predicates.predicates.len(), origins.len());
predicates
.predicates
.into_iter()
.zip(predicates.spans.into_iter())
.zip(origins.into_iter().rev())
iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
.map(|((pred, span), origin_def_id)| {
let cause = self.cause(traits::BindingObligation(origin_def_id, span));
traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)