diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fe37abe5..b05b80ac 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,8 +21,8 @@ env: # `LazyLock` detection means one binary, all ISAs. Jobs that # specifically need a higher target-cpu can opt in via per-job env. RUSTFLAGS: "-D warnings" - MSRV: 1.97.1 - BLAS_MSRV: 1.97.1 + MSRV: 1.98.1 + BLAS_MSRV: 1.98.1 jobs: pass-msrv: @@ -41,18 +41,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - # Pinned to 1.97.1 to match `rust-toolchain.toml`. The workspace - # bumped from 1.94.1 → 1.97.1 in commit - # https://github.com/AdaWorldAPI/ndarray (this PR) to align with - # bevy (edition 2024 → 1.95 MSRV) and lance-graph. 1.95 added the - # `clippy::manual_checked_ops` lint which fires on - # `impl_owned_array.rs::into_scalar` — fixed in this same PR. + # Must equal `rust-toolchain.toml`'s channel. The version is NOT + # restated in this comment on purpose: CI here does NOT read the + # toolchain file (it uses `dtolnay/rust-toolchain@`), so the + # number lives in three places — the `MSRV`/`BLAS_MSRV` env above, the + # matrix entry below, and each `dtolnay/rust-toolchain@` step. All of + # them move together with the toolchain file, and its bump log is the + # one place that records WHY each move happened. rust: - - "1.97.1" + - "1.98.1" name: clippy/${{ matrix.rust }} steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.97.1 + - uses: dtolnay/rust-toolchain@1.98.1 with: components: clippy - uses: Swatinem/rust-cache@v2 @@ -74,10 +75,10 @@ jobs: # That state no longer exists; the band-aid is removed in this PR. steps: - uses: actions/checkout@v4 - # Stable rustfmt 1.97.1 — pinned in `rust-toolchain.toml`. No - # nightly dependency since rustfmt.toml is stable-clean post-PR - # #133. - - uses: dtolnay/rust-toolchain@1.97.1 + # Stable rustfmt on the pinned channel (see `rust-toolchain.toml`; + # version deliberately not restated here). No nightly dependency since + # rustfmt.toml is stable-clean post-PR #133. + - uses: dtolnay/rust-toolchain@1.98.1 with: components: rustfmt - run: cargo fmt --all --check @@ -99,7 +100,7 @@ jobs: with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - # rust-toolchain.toml pins 1.97.1 — install the cross-compile target + # rust-toolchain.toml pins the channel — install the cross-compile target # for that toolchain too, since dtolnay/rust-toolchain only installs # for the matrix value which may differ from the pinned version. - run: rustup target add ${{ matrix.target }} @@ -126,7 +127,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: wasm32-unknown-unknown - # rust-toolchain.toml pins 1.97.1 — install the wasm target for the pinned + # rust-toolchain.toml pins the channel — install the wasm target for the pinned # toolchain too (dtolnay installs for `stable`, which may differ). - run: rustup target add wasm32-unknown-unknown - uses: actions/setup-node@v4 @@ -155,7 +156,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: aarch64-unknown-linux-gnu - # rust-toolchain.toml pins 1.97.1 — install the aarch64 target for the + # rust-toolchain.toml pins the channel — install the aarch64 target for the # pinned toolchain too (dtolnay installs for `stable`, which may differ). - run: rustup target add aarch64-unknown-linux-gnu - name: install aarch64 cross toolchain + qemu-user @@ -210,7 +211,7 @@ jobs: name: hpc-stream-parallel/rayon steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.97.1 + - uses: dtolnay/rust-toolchain@1.98.1 - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@nextest - name: cargo check (no rayon — scalar path unchanged) diff --git a/Cargo.toml b/Cargo.toml index 4fc7aa6c..ef7f9d9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" # of the contract crate happens to still succeed today — a coincidence, not a # guarantee, and exactly what an untested MSRV declaration buys. Declare what is # actually verified. -rust-version = "1.97" +rust-version = "1.98" authors = [ "Ulrik Sverdrup \"bluss\"", "Jim Turner" diff --git a/crates/numeric-tests/tests/accuracy.rs b/crates/numeric-tests/tests/accuracy.rs index e5172580..c132f36e 100644 --- a/crates/numeric-tests/tests/accuracy.rs +++ b/crates/numeric-tests/tests/accuracy.rs @@ -269,18 +269,17 @@ fn accurate_mul_with_column_f64() { let a = gen::(Ix2(m, k), rng); let b_owner = gen::(Ix2(k, k), rng); let b_row_col; - let b_sq; // pick dense square or broadcasted to square matrix - match i { - 0..=3 => b_sq = b_owner.view(), + let b_sq = match i { + 0..=3 => b_owner.view(), 4..=7 => { b_row_col = b_owner.column(0); - b_sq = b_row_col.broadcast((k, k)).unwrap(); + b_row_col.broadcast((k, k)).unwrap() } _otherwise => { b_row_col = b_owner.row(0); - b_sq = b_row_col.broadcast((k, k)).unwrap(); + b_row_col.broadcast((k, k)).unwrap() } }; diff --git a/examples/morton_cascade_probe.rs b/examples/morton_cascade_probe.rs index 1afcb298..9e6c8254 100644 --- a/examples/morton_cascade_probe.rs +++ b/examples/morton_cascade_probe.rs @@ -101,7 +101,7 @@ impl Pyramid { for l in 1..=k as usize { let prev = &levels[l - 1]; let mut cur = Vec::with_capacity(prev.len() / 4); - for node in prev.chunks_exact(4) { + for node in prev.as_chunks::<4>().0 { let mn = node.iter().map(|p| p.0).fold(f32::INFINITY, f32::min); let mx = node.iter().map(|p| p.1).fold(f32::NEG_INFINITY, f32::max); cur.push((mn, mx)); diff --git a/examples/onebrc_cascade_probe.rs b/examples/onebrc_cascade_probe.rs index 1ee9c79b..fbf1c5b1 100644 --- a/examples/onebrc_cascade_probe.rs +++ b/examples/onebrc_cascade_probe.rs @@ -201,7 +201,7 @@ impl Pyramid { for l in 1..=k as usize { let prev = &levels[l - 1]; let mut cur = Vec::with_capacity(prev.len() / 4); - for q in prev.chunks_exact(4) { + for q in prev.as_chunks::<4>().0 { cur.push(Node { min: q.iter().map(|n| n.min).fold(f32::INFINITY, f32::min), max: q.iter().map(|n| n.max).fold(f32::NEG_INFINITY, f32::max), diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e912b989..06fb5ae5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,19 +1,28 @@ [toolchain] -channel = "1.97.1" -# Pinned to 1.97.1 (2026-08-05). Aligns ndarray with the rest of the -# AdaWorldAPI stack — lance-graph, OGAR, ruff, MedCare-rs, woa-rs, a2ui-rs and -# stockfish-rs are all on 1.97.1; ndarray was the last sibling still declaring -# 1.95, so a consumer path-dep'ing both it and lance-graph-contract saw two -# different MSRVs. +channel = "1.98.1" +# The pinned version is the `channel` line ABOVE — deliberately not restated +# here. This comment used to open "Pinned to 1.97.1", and this file's own +# warning explains why that is a trap: "A stale comment on a version pin is how +# the next reader learns the wrong number." A bump edits `channel` and leaves +# prose behind, so the prose keeps only the rationale. +# +# Rationale: ndarray moves in lockstep with the rest of the AdaWorldAPI stack — +# lance-graph, OGAR, ruff, MedCare-rs, woa-rs, a2ui-rs, stockfish-rs — because a +# consumer path-dep'ing both ndarray and lance-graph-contract otherwise sees two +# different MSRVs. ndarray was once the last sibling still declaring 1.95. # # The channel here and `Cargo.toml`'s `rust-version` must move TOGETHER. They # were out of step between the 1.95 → 1.97.1 channel bump and 2026-08-05: this -# file said 1.97.1 while the manifest still declared 1.95, and the comment below -# still described the 1.95 rationale. A stale comment on a version pin is how the -# next reader learns the wrong number. +# file named one version while the manifest declared another. +# +# Bump log (append one line per bump): +# 1.95 → 1.97.1 stack alignment (2026-08-05); the 1.95 bump had introduced +# `clippy::manual_checked_ops`, fixed in `impl_owned_array.rs` +# 1.97.1 → 1.98.1 current stable (1.98.0 2026-08-20, 1.98.1 2026-09-01); +# workspace-wide sweep. The 1.98 delta measured across the +# stack is ONE lint, `clippy::chunks_exact_to_as_chunks` +# (new, default-on STYLE group) — zero sites in this repo. # -# (Historical: the 1.95 bump introduced `clippy::manual_checked_ops`, which fired -# on `impl_owned_array.rs::into_scalar` and was fixed in that same commit.) # Never auto-track `stable` — bump explicitly when a future version is # reviewed and the workspace clippy passes clean. components = ["clippy", "rustfmt"] diff --git a/src/backend/kernels_avx512.rs b/src/backend/kernels_avx512.rs index 8b1bec34..ce80a7d8 100644 --- a/src/backend/kernels_avx512.rs +++ b/src/backend/kernels_avx512.rs @@ -173,12 +173,13 @@ pub fn scal_f64(alpha: f64, x: &mut [f64]) { #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx512f")] pub fn asum_f32(x: &[f32]) -> f32 { + let (chunks, remainder) = x.as_chunks::<16>(); let mut acc = F32x16::splat(0.0); - for chunk in x.chunks_exact(16) { + for chunk in chunks { acc += F32x16::from_slice(chunk).abs(); } let mut sum = acc.reduce_sum(); - for &v in x.chunks_exact(16).remainder() { + for &v in remainder { sum += v.abs(); } sum @@ -190,12 +191,13 @@ pub fn asum_f32(x: &[f32]) -> f32 { #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx512f")] pub fn asum_f64(x: &[f64]) -> f64 { + let (chunks, remainder) = x.as_chunks::<8>(); let mut acc = F64x8::splat(0.0); - for chunk in x.chunks_exact(8) { + for chunk in chunks { acc += F64x8::from_slice(chunk).abs(); } let mut sum = acc.reduce_sum(); - for &v in x.chunks_exact(8).remainder() { + for &v in remainder { sum += v.abs(); } sum diff --git a/src/lib.rs b/src/lib.rs index 0b510eb5..8f8147eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ clippy::deref_addrof, clippy::manual_map, // is not an error clippy::while_let_on_iterator, // is not an error - clippy::from_iter_instead_of_collect, // using from_iter is good style clippy::incompatible_msrv, // false positive PointerExt::offset )] #![doc(test(attr(deny(warnings))))] diff --git a/src/simd_ops.rs b/src/simd_ops.rs index 2c0e213b..fde4a5af 100644 --- a/src/simd_ops.rs +++ b/src/simd_ops.rs @@ -609,7 +609,12 @@ pub fn bf16_tile_gemm_16x16(a_bf16: &[u16], b_bf16: &[u16], c: &mut [f32], k: us *slot = b_f32[kk * 16 + j]; } let mut acc = F32x16::splat(0.0); - for (ra, rb) in a_row.chunks_exact(16).zip(col.chunks_exact(16)) { + for (ra, rb) in a_row + .as_chunks::<16>() + .0 + .iter() + .zip(col.as_chunks::<16>().0) + { acc = F32x16::from_slice(ra).mul_add(F32x16::from_slice(rb), acc); } c[i * 16 + j] += acc.reduce_sum();