Search code examples
d

Pattern-matching inside a template constraint


This question is based on Andrei's answer to my question on signature constraints.

struct S(int x, int y) {
  void fun(T)(T t) if (is(T U == S!(a, b), int a, int b)) { }
}

template s(int a, int b) {
  enum result = S!(a,b)();
  alias result s;
}

void main() {

  auto s1 = S!(1, 1)();
  auto s2 = S!(2, 2)();
  auto s3 = s!(3, 3);
  auto s4 = s!(4, 4);

  s1.fun(s1);  // ok
  s1.fun(s2);  // ok
  s1.fun(s3);  // compile error
  s3.fun(s1);  // ok
  s3.fun(s3);  // compile error
  s3.fun(s4);  // compile error
}

I don't understand why the code is producing compile errors. Any ideas?


Solution

  • First, I wouldn't recommend using a naked template to generate an instance of an object/struct, because you're essentially requiring the object to be CTFE-able. If you need an instance your best option is to return it from a templated function:

    @property S!(a, b) s(int a, int b)()
    {
        return S!(a, b)();
    }
    

    However this still doesn't seem to work with the template constraint. I think this has to be a front-end bug. From what I can tell it seems that the type returned cannot be properly checked in the is() expression unless it was already instantiated somewhere else, e.g.:

    struct S(int x, int y) 
    {
        void fun(T)(T t) 
            if (is(T U == S!(a, b), int a, int b))
        {
    
        }
    }
    
    @property S!(a, b) s(int a, int b)()
    {
        return S!(a, b)();
    }
    
    void main() 
    {
        auto s1 = S!(1, 1)();
        auto s2 = S!(2, 2)();  // comment out and you get errors in fun() call
        auto s3 = s!(2, 2);
        s1.fun(s3);
    }
    

    I'll file this as a bug.

    Edit: Filed as Issue 8493.