Skip to content

Commit

Permalink
Rollup merge of rust-lang#82917 - cuviper:iter-zip, r=m-ou-se
Browse files Browse the repository at this point in the history
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 rust-lang#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
  • Loading branch information
Dylan-DPC authored Mar 27, 2021
2 parents ebea9d9 + f0a6052 commit b2e2543
Show file tree
Hide file tree
Showing 111 changed files with 310 additions and 256 deletions.
5 changes: 3 additions & 2 deletions compiler/rustc_apfloat/src/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2273,6 +2273,7 @@ impl Loss {
mod sig {
use super::{limbs_for_bits, ExpInt, Limb, Loss, LIMB_BITS};
use core::cmp::Ordering;
use core::iter;
use core::mem;

pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool {
Expand Down Expand Up @@ -2483,7 +2484,7 @@ mod sig {
pub(super) fn add(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
assert!(c <= 1);

for (a, &b) in a.iter_mut().zip(b) {
for (a, &b) in iter::zip(a, b) {
let (r, overflow) = a.overflowing_add(b);
let (r, overflow2) = r.overflowing_add(c);
*a = r;
Expand All @@ -2497,7 +2498,7 @@ mod sig {
pub(super) fn sub(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
assert!(c <= 1);

for (a, &b) in a.iter_mut().zip(b) {
for (a, &b) in iter::zip(a, b) {
let (r, overflow) = a.overflowing_sub(b);
let (r, overflow2) = r.overflowing_sub(c);
*a = r;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_apfloat/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![no_std]
#![forbid(unsafe_code)]
#![feature(iter_zip)]
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#![feature(const_fn_transmute)]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(iter_zip)]
#![feature(label_break_value)]
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl TokenStream {
pub fn eq_unspanned(&self, other: &TokenStream) -> bool {
let mut t1 = self.trees();
let mut t2 = other.trees();
for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
for (t1, t2) in iter::zip(&mut t1, &mut t2) {
if !t1.eq_unspanned(&t2) {
return false;
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_target::spec::abi;
use smallvec::{smallvec, SmallVec};
use tracing::debug;

use std::iter;
use std::mem;

pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
Expand Down Expand Up @@ -206,7 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
UseTreeKind::Glob => {}
UseTreeKind::Simple(_, id1, id2) => {
for (_, &id) in
self.expect_full_res_from_use(base_id).skip(1).zip([id1, id2].iter())
iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
{
vec.push(id);
}
Expand Down Expand Up @@ -537,7 +538,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// won't be dealing with macros in the rest of the compiler.
// Essentially a single `use` which imports two names is desugared into
// two imports.
for (res, &new_node_id) in resolutions.zip([id1, id2].iter()) {
for (res, &new_node_id) in iter::zip(resolutions, &[id1, id2]) {
let ident = *ident;
let mut path = path.clone();
for seg in &mut path.segments {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#![feature(crate_visibility_modifier)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(box_patterns)]
#![feature(iter_zip)]
#![recursion_limit = "256"]

use rustc_ast::node_id::NodeMap;
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ impl<'a> MethodDef<'a> {
// make a series of nested matches, to destructure the
// structs. This is actually right-to-left, but it shouldn't
// matter.
for (arg_expr, pat) in self_args.iter().zip(patterns) {
for (arg_expr, pat) in iter::zip(self_args, patterns) {
body = cx.expr_match(
trait_.span,
arg_expr.clone(),
Expand Down Expand Up @@ -1351,7 +1351,7 @@ impl<'a> MethodDef<'a> {
let mut discriminant_test = cx.expr_bool(sp, true);

let mut first_ident = None;
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
let self_addr = cx.expr_addr_of(sp, self_arg.clone());
let variant_value =
deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
Expand Down Expand Up @@ -1571,9 +1571,7 @@ impl<'a> TraitDef<'a> {
let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries);
let pattern = match *struct_def {
VariantData::Struct(..) => {
let field_pats = subpats
.into_iter()
.zip(&ident_exprs)
let field_pats = iter::zip(subpats, &ident_exprs)
.map(|(pat, &(sp, ident, ..))| {
if ident.is_none() {
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(iter_zip)]
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(proc_macro_internals)]
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use tracing::{debug, info};
use std::ffi::{CStr, CString};
use std::fs::File;
use std::io;
use std::iter;
use std::path::Path;
use std::ptr;
use std::slice;
Expand Down Expand Up @@ -916,9 +917,7 @@ impl ThinLTOKeysMap {
modules: &[llvm::ThinLTOModule],
names: &[CString],
) -> Self {
let keys = modules
.iter()
.zip(names.iter())
let keys = iter::zip(modules, names)
.map(|(module, name)| {
let key = build_string(|rust_str| unsafe {
llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0);
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use rustc_target::abi::{self, Align, Size};
use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ffi::CStr;
use std::iter;
use std::ops::{Deref, Range};
use std::ptr;
use tracing::debug;
Expand Down Expand Up @@ -1352,18 +1353,14 @@ impl Builder<'a, 'll, 'tcx> {

let param_tys = self.cx.func_params_types(fn_ty);

let all_args_match = param_tys
.iter()
.zip(args.iter().map(|&v| self.val_ty(v)))
let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.val_ty(v)))
.all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);

if all_args_match {
return Cow::Borrowed(args);
}

let casted_args: Vec<_> = param_tys
.into_iter()
.zip(args.iter())
let casted_args: Vec<_> = iter::zip(param_tys, args)
.enumerate()
.map(|(i, (expected_ty, &actual_val))| {
let actual_ty = self.val_ty(actual_val);
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1962,9 +1962,7 @@ fn prepare_enum_metadata(

let discriminant_type_metadata = |discr: Primitive| {
let enumerators_metadata: Vec<_> = match enum_type.kind() {
ty::Adt(def, _) => def
.discriminants(tcx)
.zip(&def.variants)
ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants)
.map(|((_, discr), v)| {
let name = v.ident.as_str();
let is_unsigned = match discr.ty.kind() {
Expand Down Expand Up @@ -2336,9 +2334,7 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIAr
if substs.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did);
let names = get_parameter_names(cx, generics);
let template_params: Vec<_> = substs
.iter()
.zip(names)
let template_params: Vec<_> = iter::zip(substs, names)
.filter_map(|(kind, name)| {
if let GenericArgKind::Type(ty) = kind.unpack() {
let actual_type =
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use rustc_target::abi::{LayoutOf, Primitive, Size};
use libc::c_uint;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::iter;
use tracing::debug;

mod create_scope_map;
Expand Down Expand Up @@ -448,9 +449,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
let names = get_parameter_names(cx, generics);
substs
.iter()
.zip(names)
iter::zip(substs, names)
.filter_map(|(kind, name)| {
if let GenericArgKind::Type(ty) = kind.unpack() {
let actual_type =
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#![feature(extended_key_value_attributes)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(associated_type_bounds)]
#![feature(iter_zip)]
#![recursion_limit = "256"]
#![feature(box_syntax)]

Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,7 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>>,
IndexVec<mir::BasicBlock, Option<Bx::Funclet>>,
) {
block_bxs
.iter_enumerated()
.zip(cleanup_kinds)
iter::zip(block_bxs.iter_enumerated(), cleanup_kinds)
.map(|((bb, &llbb), cleanup_kind)| {
match *cleanup_kind {
CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {}
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2214,9 +2214,7 @@ pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
};
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
// All the chars that differ in capitalization are confusable (above):
let confusable = found
.chars()
.zip(suggested.chars())
let confusable = iter::zip(found.chars(), suggested.chars())
.filter(|(f, s)| f != s)
.all(|(f, s)| (ascii_confusables.contains(&f) || ascii_confusables.contains(&s)));
confusable && found.to_lowercase() == suggested.to_lowercase()
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#![feature(crate_visibility_modifier)]
#![feature(backtrace)]
#![feature(extended_key_value_attributes)]
#![feature(iter_zip)]
#![feature(nll)]

#[macro_use]
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_errors/src/styled_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Code for creating styled buffers

use crate::snippet::{Style, StyledString};
use std::iter;

#[derive(Debug)]
pub struct StyledBuffer {
Expand All @@ -20,11 +21,11 @@ impl StyledBuffer {
let mut output: Vec<Vec<StyledString>> = vec![];
let mut styled_vec: Vec<StyledString> = vec![];

for (row, row_style) in self.text.iter().zip(&self.styles) {
for (row, row_style) in iter::zip(&self.text, &self.styles) {
let mut current_style = Style::NoStyle;
let mut current_text = String::new();

for (&c, &s) in row.iter().zip(row_style) {
for (&c, &s) in iter::zip(row, row_style) {
if s != current_style {
if !current_text.is_empty() {
styled_vec.push(StyledString { text: current_text, style: current_style });
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
#![feature(iter_zip)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_expand/src/mbe/macro_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ use rustc_span::{symbol::MacroRulesNormalizedIdent, MultiSpan, Span};

use smallvec::SmallVec;

use std::iter;

/// Stack represented as linked list.
///
/// Those are used for environments because they grow incrementally and are not mutable.
Expand Down Expand Up @@ -204,7 +206,7 @@ pub(super) fn check_meta_variables(
sess.span_diagnostic.span_bug(span, "length mismatch between LHSes and RHSes")
}
let mut valid = true;
for (lhs, rhs) in lhses.iter().zip(rhses.iter()) {
for (lhs, rhs) in iter::zip(lhses, rhses) {
let mut binders = Binders::default();
check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut valid);
check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut valid);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_index/src/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ where
{
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) {
for (out_elem, in_elem) in iter::zip(out_vec, in_vec) {
let old_val = *out_elem;
let new_val = op(old_val, *in_elem);
*out_elem = new_val;
Expand Down Expand Up @@ -842,7 +842,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
let (write_start, write_end) = self.range(write);
let words = &mut self.words[..];
let mut changed = false;
for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
for (read_index, write_index) in iter::zip(read_start..read_end, write_start..write_end) {
let word = words[write_index];
let new_word = word | words[read_index];
words[write_index] = new_word;
Expand All @@ -858,7 +858,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
assert_eq!(with.domain_size(), self.num_columns);
let (write_start, write_end) = self.range(write);
let mut changed = false;
for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) {
for (read_index, write_index) in iter::zip(0..with.words().len(), write_start..write_end) {
let word = self.words[write_index];
let new_word = word | with.words()[read_index];
self.words[write_index] = new_word;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_index/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(unboxed_closures)]
#![feature(test)]
#![feature(fn_traits)]
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
use std::fmt::Debug;
use std::iter;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// This method is meant to be invoked as the final step of a canonical query
Expand Down Expand Up @@ -418,7 +419,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {

// In terms of our example above, we are iterating over pairs like:
// [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
for (original_value, result_value) in original_values.var_values.iter().zip(result_values) {
for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
{
match result_value.unpack() {
GenericArgKind::Type(result_value) => {
// e.g., here `result_value` might be `?0` in the example above...
Expand Down
Loading

0 comments on commit b2e2543

Please sign in to comment.