Generating switch at Compile Time

ag0aep6g via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Apr 17 15:49:39 PDT 2017


On 04/17/2017 09:29 PM, Jesse Phillips wrote:
> On Thursday, 13 April 2017 at 21:33:28 UTC, ag0aep6g wrote:
[...]
>> By the way, in my opinion, `case li[0]:` shouldn't compile with the
>> static immutable `list`. `list` and `li[0]` are dynamic values. The
>> compiler only attempts (and succeeds) to evaluate them at compile time
>> because they're typed as immutable. The way I see it, that only makes
>> things more confusing.
>
> This is very interesting. I wonder if the compiler is still unrolling
> the loop at compile time since it functions as expected; It certainly
> needs that deprecation though.

It's really weird. I thought the loop would just not be unrolled at all. 
However, both `case`s seem to be generated as expected. So it behaves 
like a static foreach in that regard. But when you use `li` as a dynamic 
value (e.g. `writeln(li[1])`), it's suddenly empty. Seems that dmd can't 
decide what to do, so it does a little bit of both.

Maybe I was wrong, and the loop in your code is a static foreach, but at 
some point there's a bug that makes dmd think it's dealing with run-time 
values.

The behavior is also completely inconsistent.

With ints, the program compiles and the assert passes:

----
alias AliasSeq(stuff ...) = stuff;
immutable list = AliasSeq!(1, 2);

void main()
{
     switch(1)
     {
         foreach(li; list)
         {
             case li: enum e = li; assert(e == li); return;
         }
         default:
     }
}
----

With strings, the program doesn't compile:

----
alias AliasSeq(stuff ...) = stuff;
immutable list = AliasSeq!("foo", "bar");

void main()
{
     switch("foo")
     {
         foreach(li; list)
         {
             case li: enum e = li; assert(e == li); return;
/* "Error: case must be a string or an integral constant, not li" */
         }
         default:
     }
}
----

And with structs (your case), it compiles with a deprecation warning and 
behaves schizophrenically:

----
alias AliasSeq(stuff ...) = stuff;
struct S { int x; }
immutable list = AliasSeq!(S(1), S(2));

void main()
{
     switch(1)
/* Deprecation: 'switch' skips declaration of variable */
     {
         foreach(li; list)
         {
             case li.x: enum e = li; assert(e == li); return;
/* The assert fails. */
         }
         default:
     }
}
----

In my opinion, they should all simply be rejected. But I have no idea 
what's intended by the compiler writers. It's a mess.

With enum/alias, they all compile and work as expected, of course.


More information about the Digitalmars-d-learn mailing list