rust-lang / portable-simd

The testing ground for the future of portable SIMD in Rust
Apache License 2.0
897 stars 81 forks source link

`simd_swizzle` plays not well with type inference #292

Open usamoi opened 2 years ago

usamoi commented 2 years ago

I tried this code:

#![feature(portable_simd)]

use std::simd::simd_swizzle;
use std::simd::LaneCount;
use std::simd::Simd;
use std::simd::SupportedLaneCount;

struct Outer<const LANES: usize>;

impl<const LANES: usize> Outer<LANES>
where
    LaneCount<LANES>: SupportedLaneCount, // comment this line, and it compiles
{
    fn test(x: Simd<usize, 4>) {
        simd_swizzle!(x, [1, 3, 0, 2]);
    }
}

I expected to see this happen: it compiles

Instead, this happened: it doesn't compile

error[E0308]: mismatched types
  --> src/main.rs:15:23
   |
15 |         simd_swizzle!(x, [1, 3, 0, 2]);
   |         --------------^---------------
   |         |             |
   |         |             expected `LANES`, found `4_usize`
   |         arguments to this function are incorrect
   |
   = note: expected struct `Simd<_, LANES>`
              found struct `Simd<usize, 4_usize>`
note: associated function defined here
  --> /home/usamoi/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/../../portable-simd/crates/core_simd/src/swizzle.rs:90:8
   |
90 |     fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
   |        ^^^^^^^

For more information about this error, try `rustc --explain E0308`.

Meta

rustc --version --verbose:

rustc 1.64.0-nightly (1c7b36d4d 2022-07-12)
binary: rustc
commit-hash: 1c7b36d4db582cb47513a6c7176baaec1c3346ab
commit-date: 2022-07-12
host: x86_64-unknown-linux-gnu
release: 1.64.0-nightly
LLVM version: 14.0.6
calebzulawski commented 2 years ago

The more I look at this, the more I'm realizing this is probably an edge case of the compiler inference rules. LANES has nothing to do with the swizzle, yet the compiler is still selecting it as the expected vector width.

Here's a pared-down example that exhibits the same error, but without any swizzles at all:

#![feature(portable_simd)]

use std::simd::{Simd, SimdElement, LaneCount, SupportedLaneCount};

struct Outer<const UNRELATED_LANES: usize>;

impl<const UNRELATED_LANES: usize> Outer<UNRELATED_LANES>
where
    LaneCount<UNRELATED_LANES>: SupportedLaneCount, // comment this line, and it compiles
{
    fn test(x: Simd<usize, 4>) {
        fn foo<T, const LANES: usize>(x: Simd<T, LANES>)
        where
            T: std::simd::SimdElement,
            LaneCount<LANES>: SupportedLaneCount,
        {
            unimplemented!()
        }
        foo(x);
    }
}