jiebi/CodeConvo huggingface dataset:
<ins> // When WF checking the hidden type in the ParamEnv of the opaque type, // one complication arises when the hidden type is a closure/generator: // the "parent_substs" of the type may reference lifetime parameters // not present in the opaque type. // These region parameters are not really useful in this check. // So here we ignore them and replace them with fresh region variables. // check-pass #![feature(type_alias_impl_trait)] #![allow(dead_code)] // Basic test mod test1 { // Hidden type = Closure['_#0r] type Opaque = impl Sized; fn define<'a: 'a>() -> Opaque { || {} } } // the region vars cannot both be equal to `'static` or `'empty` mod test2 { trait Trait {} // Hidden type = Closure['a, '_#0r, '_#1r] // Constraints = [('_#0r: 'a), ('a: '_#1r)] type Opaque<'a> where &'a (): Trait, = impl Sized + 'a; fn define<'a, 'x, 'y>() -> Opaque<'a> where &'a (): Trait, 'x: 'a, 'a: 'y, { || {} } } // the region var cannot be equal to `'a` or `'b` mod test3 { trait Trait {} // Hidden type = Closure['a, 'b, '_#0r] // Constraints = [('_#0r: 'a), ('_#0r: 'b)] type Opaque<'a, 'b> where (&'a (), &'b ()): Trait, = impl Sized + 'a + 'b; fn define<'a, 'b, 'x>() -> Opaque<'a, 'b> where (&'a (), &'b ()): Trait, 'x: 'a, 'x: 'b, { || {} } } fn main() {} </ins>
<ins> // If the hidden type is a closure, we require the "outlives" bounds that appear on the // defining site to also appear on the opaque type. // // It's not clear if this is the desired behavior but at least // it's consistent and has no back-compat risk. // check-fail #![feature(type_alias_impl_trait)] #![allow(dead_code)] // requires `'a: 'b` bound mod test1 { type Opaque<'a, 'b> = impl Sized + 'a + 'b; //~^ ERROR lifetime bound not satisfied fn define<'a, 'b>() -> Opaque<'a, 'b> where 'a: 'b, { || {} } } // Same as the above but through indirection `'x` mod test2 { type Opaque<'a, 'b> = impl Sized + 'a + 'b; //~^ ERROR cannot infer an appropriate lifetime fn define<'a, 'b, 'x>() -> Opaque<'a, 'b> where 'a: 'x, 'x: 'b, { || {} } } // fixed version of the above mod test2_fixed { type Opaque<'a: 'b, 'b> = impl Sized + 'a + 'b; fn define<'a, 'b, 'x>() -> Opaque<'a, 'b> where 'a: 'x, 'x: 'b, { || {} } } // requires `T: 'static` mod test3 { type Opaque<T> = impl Sized; //~^ ERROR the parameter type `T` may not live long enough fn define<T>() -> Opaque<T> where T: 'static, { || {} } } fn main() {} </ins>
<ins> error[E0478]: lifetime bound not satisfied --> $DIR/closure_wf_outlives.rs:14:27 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                           ^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/closure_wf_outlives.rs:14:17 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                 ^^ note: but lifetime parameter must outlive the lifetime `'b` as defined here --> $DIR/closure_wf_outlives.rs:14:21 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                     ^^ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/closure_wf_outlives.rs:27:27 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                           ^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/closure_wf_outlives.rs:27:17 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                 ^^ note: ...so that the declared lifetime parameter bounds are satisfied --> $DIR/closure_wf_outlives.rs:27:27 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                           ^^^^^^^^^^^^^^^^^^^^ note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/closure_wf_outlives.rs:27:21 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                     ^^ note: ...so that the declared lifetime parameter bounds are satisfied --> $DIR/closure_wf_outlives.rs:27:27 | LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b; |                           ^^^^^^^^^^^^^^^^^^^^ error[E0310]: the parameter type `T` may not live long enough --> $DIR/closure_wf_outlives.rs:54:22 | LL |     type Opaque<T> = impl Sized; |                      ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | note: ...that is required by this bound --> $DIR/closure_wf_outlives.rs:59:12 | LL |         T: 'static, |            ^^^^^^^ help: consider adding an explicit lifetime bound... | LL |     type Opaque<T: 'static> = impl Sized; |                  +++++++++ error: aborting due to 3 previous errors Some errors have detailed explanations: E0310, E0478, E0495. For more information about an error, try `rustc --explain E0310`. </ins>
let ocx = ObligationCtxt::new(infcx); let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); <del> let impl_return_ty = ocx.normalize( </del> <ins> let impl_sig = ocx.normalize( </ins> norm_cause.clone(), param_env, <del> infcx .replace_bound_vars_with_fresh_vars( return_span, infer::HigherRankedType, tcx.fn_sig(impl_m.def_id), ) .output(), </del> <ins> infcx.replace_bound_vars_with_fresh_vars( return_span, infer::HigherRankedType, tcx.fn_sig(impl_m.def_id), ), </ins> ); <ins> let impl_return_ty = impl_sig.output(); </ins> let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); <del> let unnormalized_trait_return_ty = tcx </del> <ins> let unnormalized_trait_sig = tcx </ins> .liberate_late_bound_regions( impl_m.def_id, tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), ) <del> .output() </del> .fold_with(&mut collector); <del> let trait_return_ty = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty); </del> <ins> let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig); let trait_return_ty = trait_sig.output(); </ins> <del> let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]); </del> <ins> let wf_tys = FxHashSet::from_iter( unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()), ); </ins> match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) { Ok(infer::InferOk { value: (), obligations }) => {
} } <ins> // Unify the whole function signature. We need to do this to fully infer // the lifetimes of the return type, but do this after unifying just the // return types, since we want to avoid duplicating errors from // `compare_predicate_entailment`. match infcx .at(&cause, param_env) .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig))) { Ok(infer::InferOk { value: (), obligations }) => { ocx.register_obligations(obligations); } Err(terr) => { let guar = tcx.sess.delay_span_bug( return_span, format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"), ); return Err(guar); } } </ins> // Check that all obligations are satisfied by the implementation's // RPITs. let errors = ocx.select_all_or_error();
let id_substs = InternalSubsts::identity_for_item(tcx, def_id); debug!(?id_substs, ?substs); let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = <del> substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect(); </del> <ins> std::iter::zip(substs, id_substs).collect(); </ins> debug!(?map); <ins> // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound // region substs that are synthesized during AST lowering. These are substs // that are appended to the parent substs (trait and trait method). However, // we're trying to infer the unsubstituted type value of the RPITIT inside // the *impl*, so we can later use the impl's method substs to normalize // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`). // // Due to the design of RPITITs, during AST lowering, we have no idea that // an impl method corresponds to a trait method with RPITITs in it. Therefore, // we don't have a list of early-bound region substs for the RPITIT in the impl. // Since early region parameters are index-based, we can't just rebase these // (trait method) early-bound region substs onto the impl, and there's no // guarantee that the indices from the trait substs and impl substs line up. // So to fix this, we subtract the number of trait substs and add the number of // impl substs to *renumber* these early-bound regions to their corresponding // indices in the impl's substitutions list. // // Also, we only need to account for a difference in trait and impl substs, // since we previously enforce that the trait method and impl method have the // same generics. let num_trait_substs = trait_to_impl_substs.len(); let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len(); </ins> let ty = tcx.fold_regions(ty, |region, _| { <del> if let ty::ReFree(_) = region.kind() { map[&region.into()].expect_region() } else { region } </del> <ins> let ty::ReFree(_) = region.kind() else { return region; }; let ty::ReEarlyBound(e) = map[&region.into()].expect_region().kind() else { bug!("expected ReFree to map to ReEarlyBound"); }; tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: e.def_id, name: e.name, index: (e.index as usize - num_trait_substs + num_impl_substs) as u32, })) </ins> }); debug!(%ty); collected_tys.insert(def_id, ty);
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { #[cold] #[inline(never)] <del> fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! { </del> <ins> fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! { </ins> bug!( <del> "Region parameter out of range when substituting in region {} (index={})", </del> <ins> "Region parameter out of range when substituting in region {} (index={}, substs = {:?})", data.name, data.index, substs, ) } #[cold] #[inline(never)] fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! { bug!( "Unexpected parameter {:?} when substituting in region {} (index={})", other, </ins> data.name, data.index )
let rk = self.substs.get(data.index as usize).map(|k| k.unpack()); match rk { Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), <del> _ => region_param_out_of_range(data), </del> <ins> Some(other) => region_param_invalid(data, other), None => region_param_out_of_range(data, self.substs), </ins> } } _ => r,
} let impl_fn_def_id = leaf_def.item.def_id; <del> let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs); </del> <ins> // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque}, // since `data.substs` are the impl substs. let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs); </ins> let cause = ObligationCause::new( obligation.cause.span,
<ins> // check-pass #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Foo<T> { fn foo<F2: Foo<T>>(self) -> impl Foo<T>; } struct Bar; impl Foo<u8> for Bar { fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { self } } fn main() {} </ins>
lint_builtin_export_name_fn = declaration of a function with `export_name` lint_builtin_export_name_method = declaration of a method with `export_name` lint_builtin_export_name_static = declaration of a static with `export_name` <ins> lint_builtin_global_asm = usage of `core::arch::global_asm` lint_builtin_global_macro_unsafety = using this macro is unsafe even though it does not need an `unsafe` block </ins> lint_builtin_impl_unsafe_method = implementation of an `unsafe` method lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
<ins> //@ needs-asm-support #![deny(unsafe_code)] use std::arch::global_asm; #[allow(unsafe_code)] mod allowed_unsafe { std::arch::global_asm!(""); } macro_rules! unsafe_in_macro { () => { global_asm!(""); //~ ERROR: usage of `core::arch::global_asm` }; } global_asm!(""); //~ ERROR: usage of `core::arch::global_asm` unsafe_in_macro!(); fn main() {} </ins>
<ins> error: usage of `core::arch::global_asm` --> $DIR/lint-global-asm-as-unsafe.rs:17:1 | LL | global_asm!(""); | ^^^^^^^^^^^^^^^ | = note: using this macro is unsafe even though it does not need an `unsafe` block note: the lint level is defined here --> $DIR/lint-global-asm-as-unsafe.rs:2:9 | LL | #![deny(unsafe_code)] |         ^^^^^^^^^^^ error: usage of `core::arch::global_asm` --> $DIR/lint-global-asm-as-unsafe.rs:13:9 | LL |         global_asm!(""); |         ^^^^^^^^^^^^^^^ ... LL | unsafe_in_macro!(); | ------------------ in this macro invocation | = note: using this macro is unsafe even though it does not need an `unsafe` block = note: this error originates in the macro `unsafe_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors </ins>
/// Returns a new span representing the next character after the end-point of this span. /// Special cases: /// - if span is a dummy one, returns the same span <del> /// - if next_point reached the end of source, return span with lo = hi </del> <ins> /// - if next_point reached the end of source, return a span exceeding the end of source, ///   which means sm.span_to_snippet(next_point) will get `Err` </ins> /// - respect multi-byte characters pub fn next_point(&self, sp: Span) -> Span { if sp.is_dummy() {
let start_of_next_point = sp.hi().0; let width = self.find_width_of_character_at_span(sp, true); <del> if width == 0 { return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None); } </del> // If the width is 1, then the next span should only contain the next char besides current ending. // However, in the case of a multibyte character, where the width != 1, the next span should // span multiple bytes to include the whole character.
assert_eq!(span.lo().0, 4); assert_eq!(span.hi().0, 5); <del> // A non-empty span at the last byte should advance to create an empty // span pointing at the end of the file. </del> <ins> // Reaching to the end of file, return a span that will get error with `span_to_snippet` </ins> let span = Span::with_root_ctxt(BytePos(4), BytePos(5)); let span = sm.next_point(span); assert_eq!(span.lo().0, 5); <del> assert_eq!(span.hi().0, 5); </del> <ins> assert_eq!(span.hi().0, 6); assert!(sm.span_to_snippet(span).is_err()); </ins> <del> // Empty span pointing just past the last byte. </del> <ins> // Reaching to the end of file, return a span that will get error with `span_to_snippet` </ins> let span = Span::with_root_ctxt(BytePos(5), BytePos(5)); let span = sm.next_point(span); assert_eq!(span.lo().0, 5); <del> assert_eq!(span.hi().0, 5); </del> <ins> assert_eq!(span.hi().0, 6); assert!(sm.span_to_snippet(span).is_err()); </ins> }
<ins> error: this file contains an unclosed delimiter --> $DIR/issue-103451.rs:5:15 | LL | struct S { |          - unclosed delimiter LL |     x: [u8; R |        -      ^ |        | |        unclosed delimiter error: this file contains an unclosed delimiter --> $DIR/issue-103451.rs:5:15 | LL | struct S { |          - unclosed delimiter LL |     x: [u8; R |        -      ^ |        | |        unclosed delimiter error[E0423]: expected value, found struct `R` --> $DIR/issue-103451.rs:5:13 | LL | struct R { } | ------------ `R` defined here LL | struct S { LL |     x: [u8; R |             ^ help: use struct literal syntax instead: `R {}` error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0423`. </ins>
} /// Parses the parameter list of a function, including the `(` and `)` delimiters. <del> fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> { </del> <ins> pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> { </ins> let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... let (mut params, _) = self.parse_paren_comma_seq(|p| {
has_parens: bool, modifiers: BoundModifiers, ) -> PResult<'a, GenericBound> { <del> let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = if self.token.is_keyword(kw::Fn) </del> <ins> let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; let mut path = if self.token.is_keyword(kw::Fn) </ins> && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() {
} else { self.parse_path(PathStyle::Type)? }; <ins> if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) { self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?; } </ins> if has_parens { if self.token.is_like_plus() { // Someone has written something like `&dyn (Trait + Other)`. The correct code
} } <ins> /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already /// been eaten. fn recover_fn_trait_with_lifetime_params( &mut self, fn_path: &mut ast::Path, lifetime_defs: &mut Vec<GenericParam>, ) -> PResult<'a, ()> { let fn_path_segment = fn_path.segments.last_mut().unwrap(); let generic_args = if let Some(p_args) = &fn_path_segment.args { p_args.clone().into_inner() } else { // Normally it wouldn't come here because the upstream should have parsed // generic parameters (otherwise it's impossible to call this function). return Ok(()); }; let lifetimes = if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) = &generic_args { args.into_iter() .filter_map(|arg| { if let ast::AngleBracketedArg::Arg(generic_arg) = arg && let ast::GenericArg::Lifetime(lifetime) = generic_arg { Some(lifetime) } else { None } }) .collect() } else { Vec::new() }; // Only try to recover if the trait has lifetime params. if lifetimes.is_empty() { return Ok(()); } // Parse `(T, U) -> R`. let inputs_lo = self.token.span; let inputs: Vec<_> = self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; let args = ast::ParenthesizedArgs { span: fn_path_segment.span().to(self.prev_token.span), inputs, inputs_span, output, } .into(); *fn_path_segment = ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID }; // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`. let mut generic_params = lifetimes .iter() .map(|lt| GenericParam { id: lt.id, ident: lt.ident, attrs: ast::AttrVec::new(), bounds: Vec::new(), is_placeholder: false, kind: ast::GenericParamKind::Lifetime, colon_span: None, }) .collect::<Vec<GenericParam>>(); lifetime_defs.append(&mut generic_params); let generic_args_span = generic_args.span(); let mut err = self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters"); let snippet = format!( "for<{}> ", lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(), ); let before_fn_path = fn_path.span.shrink_to_lo(); err.multipart_suggestion( "consider using a higher-ranked trait bound instead", vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], Applicability::MaybeIncorrect, ) .emit(); Ok(()) } </ins> pub(super) fn check_lifetime(&mut self) -> bool { self.expected_tokens.push(TokenType::Lifetime); self.token.is_lifetime()
<ins> // Test that Fn-family traits with lifetime parameters shouldn't compile and // we suggest the usage of higher-rank trait bounds instead. fn fa(_: impl Fn<'a>(&'a str) -> bool) {} //~^ ERROR `Fn` traits cannot take lifetime parameters fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {} //~^ ERROR `Fn` traits cannot take lifetime parameters fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {} //~^ ERROR `Fn` traits cannot take lifetime parameters use std::ops::Fn as AliasedFn; fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {} //~^ ERROR `Fn` traits cannot take lifetime parameters fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {} //~^ ERROR `Fn` traits cannot take lifetime parameters fn main() {} </ins>
<ins> error: `Fn` traits cannot take lifetime parameters --> $DIR/hrtb-malformed-lifetime-generics.rs:4:17 | LL | fn fa(_: impl Fn<'a>(&'a str) -> bool) {} |                 ^^^^ | help: consider using a higher-ranked trait bound instead | LL - fn fa(_: impl Fn<'a>(&'a str) -> bool) {} LL + fn fa(_: impl for<'a> Fn(&'a str) -> bool) {} | error: `Fn` traits cannot take lifetime parameters --> $DIR/hrtb-malformed-lifetime-generics.rs:7:20 | LL | fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {} |                    ^^^^^^^^ | help: consider using a higher-ranked trait bound instead | LL - fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {} LL + fn fb(_: impl for<'a, 'b> FnMut(&'a str, &'b str) -> bool) {} | error: `Fn` traits cannot take lifetime parameters --> $DIR/hrtb-malformed-lifetime-generics.rs:10:41 | LL | fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {} |                                         ^^^^ | help: consider using a higher-ranked trait bound instead | LL - fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {} LL + fn fc(_: impl std::fmt::Display + for<'a> FnOnce(&'a str) -> bool + std::fmt::Debug) {} | error: `Fn` traits cannot take lifetime parameters --> $DIR/hrtb-malformed-lifetime-generics.rs:14:24 | LL | fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {} |                        ^^^^ | help: consider using a higher-ranked trait bound instead | LL - fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {} LL + fn fd(_: impl for<'a> AliasedFn(&'a str) -> bool) {} | error: `Fn` traits cannot take lifetime parameters --> $DIR/hrtb-malformed-lifetime-generics.rs:17:27 | LL | fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {} |                           ^^^^ | help: consider using a higher-ranked trait bound instead | LL - fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {} LL + fn fe<F>(_: F) where F: for<'a> Fn(&'a str) -> bool {} | error: aborting due to 5 previous errors </ins>
drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } <del> /// 'Zips up' two arrays into a single array of pairs. /// /// `zip()` returns a new array where every element is a tuple where the /// first element comes from the first array, and the second element comes /// from the second array. In other words, it zips two arrays together, /// into a single one. /// /// # Examples /// /// ``` /// #![feature(array_zip)] /// let x = [1, 2, 3]; /// let y = [4, 5, 6]; /// let z = x.zip(y); /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); /// ``` #[unstable(feature = "array_zip", issue = "80094")] pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] { drain_array_with(self, |lhs| { drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs))) }) } </del> /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")]
x.map(|x| 2 * x + 1) } <del> // CHECK-LABEL: @short_integer_zip_map #[no_mangle] pub fn short_integer_zip_map(x: [u32; 8], y: [u32; 8]) -> [u32; 8] { // CHECK: %[[A:.+]] = load <8 x i32> // CHECK: %[[B:.+]] = load <8 x i32> // CHECK: sub <8 x i32> %[[B]], %[[A]] // CHECK: store <8 x i32> x.zip(y).map(|(x, y)| x - y) } </del> // This test is checking that LLVM can SRoA away a bunch of the overhead, // like fully moving the iterators to registers.  Notably, previous implementations // of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a
c } <del> // CHECK-LABEL: @auto_vectorize_array_zip_map </del> <ins> // CHECK-LABEL: @auto_vectorize_array_from_fn </ins> #[no_mangle] <del> pub fn auto_vectorize_array_zip_map(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { </del> <ins> pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { </ins> // CHECK: load <4 x float> // CHECK: load <4 x float> // CHECK: fadd <4 x float> // CHECK: store <4 x float> <del> a.zip(b).map(|(a, b)| a + b) </del> <ins> std::array::from_fn(|i| a[i] + b[i]) </ins> }