genericsrustconst-generics

Const generic unconstrained generic constant


I have an interesting case i don't quite understand.

I am trying to constantly switch on some code down in an iteration. The conditional is the same during the whole iteration so instead of doing a regular if else, i tried to do it with const generic bools.

A minimal example is this:

#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

use const_assert::{Assert, IsTrue};

enum XorY {
    X,
    Y
}

fn foo(count: usize, do_special: Option<XorY>) {
    match do_special {
        Some(XorY::X) => foo_inner::<true, false>(count),
        Some(XorY::Y) => foo_inner::<false, true>(count),
        _ => foo_inner::<false, false>(count),
    }
}

const fn constraint(x: bool, y: bool) -> bool {
    !(x && y)
}

fn foo_inner<const X: bool, const Y: bool>(count: usize)
    where Assert<{constraint(X, Y)}> : IsTrue
{
    for i in 0..(count - 1)
    {
        foo_iter::<false, Y>(i);
    }

    foo_iter::<X, Y>(i);
}

fn foo_iter<const X: bool, const Y: bool>(index: usize)
    : where Assert<{constraint(X, Y)}> : IsTrue
{        
    if X {
        // do x stuff with index
    }
    else if Y {
        // do y stuff with index
    }
    else {
        // do default stuff with index
    }
}

But i get an "unconstrained generic constant" error.

error: unconstrained generic constant
   |
   |         foo_iter::<false, Y>(
   |                    ^^^^^
   |
note: required by a bound in `foo_iter`
   |
   | fn foo_iter<const X: bool, const Y: bool>(
   |    -------- required by a bound in this function
...
   |     where Assert<{ constraint(X, Y) }> : IsTrue
   |                  ^^^^^^^^^^^^^^^^^^^ required by this bound in `foo_iter`
help: try adding a `where` bound
   |
   |     where Assert<{ constraint(X, Y) }> : IsTrue, [(); { constraint(X, Y) } as usize]:
   |                 

And i don't understand why false would be unconstrained. Also, the suggestion does not work.


Solution

  • The compiler doesn't do any kind of analysis on const generics (such analysis will also be generally impossible). Therefore it requires every constraint to appear every time, unless all values are known. You have to repeat the constraint:

    fn foo_inner<const X: bool, const Y: bool>(count: usize)
    where
        Assert<{ constraint(X, Y) }>: IsTrue,
        Assert<{ constraint(false, Y) }>: IsTrue,
    { ... }