Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unrelated const generic selected during type inference #103741

Closed
calebzulawski opened this issue Oct 29, 2022 · 6 comments
Closed

Unrelated const generic selected during type inference #103741

calebzulawski opened this issue Oct 29, 2022 · 6 comments
Labels
A-const-generics Area: const generics (parameters and arguments) A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@calebzulawski
Copy link
Member

I tried this code:

playground link

#![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);
    }
}

I expected to see this happen: it compiles

Instead, this happened: it errors

   |
19 |         foo(x);
   |         --- ^ expected `UNRELATED_LANES`, found `4`
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected struct `Simd<_, UNRELATED_LANES>`
              found struct `Simd<usize, 4>`

I'm not sure why UNRELATED_LANES is selected for the second parameter of Simd, when it's not used at all. This was discovered in rust-lang/portable-simd#292.

Meta

rustc --version --verbose:

rustc 1.66.0-nightly (758f19645 2022-10-24)
binary: rustc
commit-hash: 758f19645b8ebce61ea52d1f6672fd057bc8dbee
commit-date: 2022-10-24
host: x86_64-apple-darwin
release: 1.66.0-nightly
LLVM version: 15.0.2
@calebzulawski calebzulawski added the C-bug Category: This is a bug. label Oct 29, 2022
@compiler-errors
Copy link
Member

This is probably related to https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/Why.20does.20an.20explicit.20.60Into.60.20bound.20prevent.20the.20no-op.20impl.3F/near/306742934

Where-clauses are always preferred over non-where clauses -- in this case, you should be able to fix this by using a turbofish.

@calebzulawski
Copy link
Member Author

calebzulawski commented Oct 29, 2022

I'm still a little confused why it would be considered a candidate at all. I'd understand if there were two possible ambiguous impls, but x is the concrete type Simd<usize, 4>... why would foo(x) ever try anything other than Simd<_, 4>? UNRELATED_LANES doesn't show up in any of the types in that function.

As to using a turbofish, I don't believe this is possible in the original issue reported to portable SIMD, which is inside the simd_swizzle macro and doesn't have access to the input type's lane count.

@compiler-errors
Copy link
Member

compiler-errors commented Oct 29, 2022

why would foo(x) ever try anything other than Simd<_, 4>

This is my theory, but it seems very likely given the circumstances --

When you call foo::<_T, _C>(x) (where _T is a type inference variable, and _C is a const inference variable, which are inserted during lowering), it registers the obligation LaneCount<_C>: SupportedLaneCount as something that needs to be solved for the program's correctness during type checking (among others).

While checking argument compatibility for foo, we call resolve_vars_with_obligations, which attempts to solve any pending obligations.

Therefore we try to check if LaneCount<_C>: SupportedLaneCount holds without having yet equated _C with 4 (this happens after the resolve call) -- but that obligation holds even with that unsatisfied const variable _C because the where-clause always has precedence over impls, so we infer _C to be UNRELATED_LANES.

That might seem silly in this example, but the ordering of these operations are required for function argument inference and coercion to work properly, so it's probably going to be hard to fix without breaking other types of function calls.

Hope that makes sense.

@calebzulawski
Copy link
Member Author

In that case, I'm surprised that adding LaneCount<4>: SupportedLaneCount to the where-clause has no affect, unless that requirement is immediately removed because it can be verified without generics.

@compiler-errors
Copy link
Member

unless that requirement is immediately removed because it can be verified without generics.

It's not filtered out immediately, though it's likely dropped due to special selection logic that filters out non-global param-env candidates.

is_global(cand) && other.evaluation.must_apply_modulo_regions()

@fmease fmease added A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-const-generics Area: const generics (parameters and arguments) and removed needs-triage-legacy labels Jan 26, 2024
@fmease
Copy link
Member

fmease commented Jan 26, 2024

Closing as a duplicate of #24066. If you feel it's worth keeping this open anyway, I can of course reopen it.

@fmease fmease closed this as not planned Won't fix, can't repro, duplicate, stale Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-generics Area: const generics (parameters and arguments) A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants