1
Fork 0

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

@ -18,6 +18,7 @@ use rustc_span::{
Span,
};
use rustc_target::abi::VariantIdx;
use std::iter;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
@ -970,13 +971,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
for (captured_place, place) in self
.infcx
.tcx
.typeck(def_id.expect_local())
.closure_min_captures_flattened(def_id)
.zip(places)
{
for (captured_place, place) in iter::zip(
self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id),
places,
) {
let upvar_hir_id = captured_place.get_root_variable();
//FIXME(project-rfc-2229#8): Use better span from captured_place
let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;

View file

@ -1,4 +1,5 @@
use std::fmt::{self, Display};
use std::iter;
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
@ -536,7 +537,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// just worry about trying to match up the rustc type
// with the HIR types:
(ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(*elem_hir_tys));
search_stack
.extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys));
}
(ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
@ -611,7 +613,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
args: &'hir hir::GenericArgs<'hir>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
) -> Option<&'hir hir::Lifetime> {
for (kind, hir_arg) in substs.iter().zip(args.args) {
for (kind, hir_arg) in iter::zip(substs, args.args) {
match (kind.unpack(), hir_arg) {
(GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
if r.to_region_vid() == needle_fr {

View file

@ -5,6 +5,7 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
use std::iter;
use crate::dataflow::indexes::BorrowIndex;
@ -69,7 +70,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
self.mutate_place(location, **place, Shallow(None), JustWrite);
}
StatementKind::LlvmInlineAsm(asm) => {
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.

View file

@ -25,6 +25,7 @@ use either::Either;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::iter;
use std::mem;
use std::rc::Rc;
@ -595,7 +596,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
}
StatementKind::LlvmInlineAsm(ref asm) => {
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.

View file

@ -5,6 +5,7 @@ use rustc_hir as hir;
use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, TyCtxt};
use std::cmp::max;
use std::iter;
/// When checking if a place conflicts with another place, this enum is used to influence decisions
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
@ -139,7 +140,7 @@ fn place_components_conflict<'tcx>(
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, &access_c)) in
borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
iter::zip(borrow_place.projection, access_place.projection).enumerate()
{
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
let borrow_proj_base = &borrow_place.projection[..i];

View file

@ -1770,7 +1770,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
let op_arg_ty = op_arg.ty(body, self.tcx());
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {

View file

@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
let subst_mapping =
identity_substs.regions().zip(fr_substs.regions().map(|r| r.to_region_vid()));
iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid()));
UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() }
}

View file

@ -40,6 +40,7 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use std::iter;
/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements
/// in the set.
@ -110,7 +111,7 @@ impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
assert_eq!(self.len(), other.len());
let mut changed = false;
for (a, b) in self.iter_mut().zip(other.iter()) {
for (a, b) in iter::zip(self, other) {
changed |= a.join(b);
}
changed
@ -122,7 +123,7 @@ impl<I: Idx, T: MeetSemiLattice> MeetSemiLattice for IndexVec<I, T> {
assert_eq!(self.len(), other.len());
let mut changed = false;
for (a, b) in self.iter_mut().zip(other.iter()) {
for (a, b) in iter::zip(self, other) {
changed |= a.meet(b);
}
changed

View file

@ -11,6 +11,7 @@ use crate::borrow_check::{
use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
use std::fmt;
use std::iter;
rustc_index::newtype_index! {
pub struct BorrowIndex {
@ -292,7 +293,7 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
mir::StatementKind::LlvmInlineAsm(ref asm) => {
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect && !kind.is_rw {
self.kill_borrows_on_place(trans, *output);
}

View file

@ -4,6 +4,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
use std::iter;
use std::mem;
use super::abs_domain::Lift;
@ -296,7 +297,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
self.create_move_path(**place);
}
StatementKind::LlvmInlineAsm(ref asm) => {
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect {
self.gather_init(output.as_ref(), InitKind::Deep);
}

View file

@ -18,6 +18,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(map_try_insert)]
#![feature(min_specialization)]

View file

@ -121,6 +121,7 @@ use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
use rustc_middle::ty::TyCtxt;
use std::iter;
use std::lazy::SyncOnceCell;
pub const NESTED_INDENT: &str = " ";
@ -703,9 +704,7 @@ pub(super) fn dump_coverage_graphviz(
let edge_counters = from_terminator
.successors()
.map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
edge_labels
.iter()
.zip(edge_counters)
iter::zip(&edge_labels, edge_counters)
.map(|(label, some_counter)| {
if let Some(counter) = some_counter {
format!("{}\n{}", label, debug_counters.format_counter(counter))

View file

@ -1,7 +1,7 @@
//! This pass finds basic blocks that are completely equal,
//! and replaces all uses with just one of them.
use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher};
use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter};
use crate::transform::MirPass;
@ -115,11 +115,7 @@ impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> {
fn eq(&self, other: &Self) -> bool {
self.basic_block_data.statements.len() == other.basic_block_data.statements.len()
&& &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind
&& self
.basic_block_data
.statements
.iter()
.zip(&other.basic_block_data.statements)
&& iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements)
.all(|(x, y)| statement_eq(&x.kind, &y.kind))
}
}

View file

@ -1,6 +1,7 @@
use crate::transform::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use std::iter;
use super::simplify::simplify_cfg;
@ -83,7 +84,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
if first_stmts.len() != scnd_stmts.len() {
continue;
}
for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
for (f, s) in iter::zip(first_stmts, scnd_stmts) {
match (&f.kind, &s.kind) {
// If two statements are exactly the same, we can optimize.
(f_s, s_s) if f_s == s_s => {}
@ -113,7 +114,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
// and bb_idx has a different terminator from both of them.
let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| {
let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| {
match (&f.kind, &s.kind) {
(f_s, s_s) if f_s == s_s => (*f).clone(),