March 17, 2016
On 3/16/16 9:48 PM, tsbockman wrote:
> On Wednesday, 16 March 2016 at 11:22:02 UTC, rikki cattermole wrote:
>> Change those static if's to just plain old ifs.
>
> This only works (sometimes) because D's value range propagation doesn't
> understand comparisons or normal if statements very well. This will
> hopefully be fixed sooner or later:
>      https://github.com/D-Programming-Language/dmd/pull/1913
>      https://github.com/D-Programming-Language/dmd/pull/5229
>
> The only future-proof way to fix the "statement is not reachable"
> warning, is to guard the potentially unreachable code with a `static if`
> whose predicate precisely describes the circumstances in which it
> becomes unreachable...
>
> ....Which itself is a terrible solution that doesn't scale well at all
> to complex generic code and violates the "DRY" principle.
>
> We really ought to just remove the warning. It just doesn't mesh well
> with D's super-powered meta-programming features.

Yes. I agree. The way I look at it is that the code *is* reached in some cases, so it should compile (and just remove that section in that instance).

IMO any time a template value is used for branching, it should turn that warning off.

-Steve
March 17, 2016
On Thursday, 17 March 2016 at 17:12:07 UTC, Steven Schveighoffer wrote:
> Yes. I agree. The way I look at it is that the code *is* reached in some cases, so it should compile (and just remove that section in that instance).
>
> IMO any time a template value is used for branching, it should turn that warning off.
>
> -Steve

That's what I think it should do, also. However, when we discussed it before, Daniel Murphy pretty much told me there is no practical way to actually implement that behavior in the compiler.

So, the next best thing is to just remove the warning entirely.
March 19, 2016
On Wednesday, 16 March 2016 at 17:08:20 UTC, Johan Engelen wrote:
> On Wednesday, 16 March 2016 at 11:47:35 UTC, QAston wrote:
>> 
>> import std.meta;
>> template isBool(U)() = is(U == bool);
>> static if (!allSatisfy!(isBool, T)) {
>>     return true;  // no longer emits a warning
>> }
>>
>> Something like this should work.
>
> Thanks, but:
>
> On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:
>> (I have heavily simplified the real-world code, please don't discuss alternative solutions to the "is(U==bool)" in particular. For sake of argument, assume that the predicate is a complicated beast.)

This method will work regarless of the predicate, just check if the predicate isn't matched for the whole array using allSatisfy/anySatisfy.
March 31, 2016
On 3/16/2016 4:18 AM, Johan Engelen wrote:
>    I've found discussions, but not an actual "recommended" solution for the
> problem of "statement is not reachable" warnings in templates with early
> returns, e.g.:
> ```
> bool nobool(T...)() {
>      foreach (i, U; T) {
>          static if (is(U == bool)) {
>              return false;
>          }
>      }
>      return true;  // emits "Warning: statement is not reachable"
> }


bool nobool(T...)() {
     bool result = true;
     foreach (i, U; T) {
         static if (is(U == bool)) {
             result = false;
             break;
         }
         else
         {
             ...
         }
     }
     return result;  // emits "Warning: statement is not reachable"
}

Note that the optimizer will remove the dead loads.
April 01, 2016
On Friday, 1 April 2016 at 01:21:32 UTC, Walter Bright wrote:
> On 3/16/2016 4:18 AM, Johan Engelen wrote:
>>    I've found discussions, but not an actual "recommended" solution for the
>> problem of "statement is not reachable" warnings in templates with early
>> returns, e.g.:
>> ```
>> bool nobool(T...)() {
>>      foreach (i, U; T) {
>>          static if (is(U == bool)) {
>>              return false;
>>          }
>>      }
>>      return true;  // emits "Warning: statement is not reachable"
>> }
>
>
> bool nobool(T...)() {
>      bool result = true;
>      foreach (i, U; T) {
>          static if (is(U == bool)) {
>              result = false;
>              break;
>          }
>          else
>          {
>              ...
>          }
>      }
>      return result;  // emits "Warning: statement is not reachable"
> }

As you can see from my first post, that is the solution I used first  (without the "break;" addition), but it works until...

> Note that the optimizer will remove the dead loads.

... until someone adds a (imho useful) diagnostic of dead stores/loads. :-)
In that case, I guess inverting all bools and then inverting the return value at the end will work (using default initialization of result); but this is not possible in a slightly more complicated case with non-bool return types.

In another piece of code, the return type is a struct with an immutable member. That's when I gave up on working around the warning and just disabled it.
Simplified, something like this:

struct IMM {
    immutable bool result;
}
IMM immut(T...)() {
    IMM retval = IMM(true);
    foreach (i, U; T) {
        static if (is(U == bool)) {
            retval = IMM(false);  //  "Error: cannot modify struct retval IMM with immutable member".
        }
    }
    return retval;
}


April 01, 2016
On Friday, 1 April 2016 at 01:21:32 UTC, Walter Bright wrote:
> On 3/16/2016 4:18 AM, Johan Engelen wrote:
>>    I've found discussions, but not an actual "recommended" solution for the
>> problem of "statement is not reachable" warnings in templates with early
>> returns, e.g.:
>> ```
>> bool nobool(T...)() {
>>      foreach (i, U; T) {
>>          static if (is(U == bool)) {
>>              return false;
>>          }
>>      }
>>      return true;  // emits "Warning: statement is not reachable"
>> }
>
>
> bool nobool(T...)() {
>      bool result = true;
>      foreach (i, U; T) {
>          static if (is(U == bool)) {
>              result = false;
>              break;
>          }
>          else
>          {
>              ...
>          }
>      }
>      return result;  // emits "Warning: statement is not reachable"
> }
>
> Note that the optimizer will remove the dead loads.

Actually, I would expect every call of this fuction to be replaced by a boolean constant, since the result depends only on compile-time information.

What happened to "obvious code should be correct"? Can we try to find a solution that doesn't look like a hack? I don't think that we should ask users of the language to uglify their code just to workaround a deficiency in the compiler. Instead, we should improve the lowering of the static foreach construct so the information that it is syntactically a loop is preserved after loop unrolling.
June 18, 2017
Reviving this thread to see whether anything has changed on the topic.

I now have this monster:
```
struct FMT {
  // has immutable members. FMT cannot be assigned to.
}

FMT monsterThatCompilerAccepts(T)(){
    alias TP = Tuple!(__traits(getAttributes, T));
    foreach(i, att; TP){
        static if( ... ) {
            return FMT( ... );
        }

        // Make sure we return a default value in the last iteration.
        // Prevents "statement not reachable" warning when placed here instead of outside the foreach.
        else static if (i + 1 == TP.length) {
            return FMT( ... );
        }
    }
    static if (TP.length == 0) {
        return FMT( ... );
    }
}

FMT codeThatIsUnderstandableButNotAccepted(T)(){
    alias TP = Tuple!(__traits(getAttributes, T));
    foreach(i, att; TP){
        static if( ... ) {
            return FMT( ... );
        }
    }
    return FMT( ... );
}
```

Thanks,
  Johan
June 18, 2017
On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:
> Reviving this thread to see whether anything has changed on the topic.
>

If Timon gets static for each into the language, it can look a little better.

-Steve


June 18, 2017
On Sunday, 18 June 2017 at 09:56:50 UTC, Steven Schveighoffer wrote:
> On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:
>> Reviving this thread to see whether anything has changed on the topic.
>>
>
> If Timon gets static for each into the language, it can look a little better.

Can you help me understand what you mean? How will it improve things? (static foreach would disable the "statement not reachable" analysis?)

-Johan

June 18, 2017
On Sunday, 18 June 2017 at 11:11:59 UTC, Johan Engelen wrote:
> On Sunday, 18 June 2017 at 09:56:50 UTC, Steven Schveighoffer wrote:
>> On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:
>>> Reviving this thread to see whether anything has changed on the topic.
>>>
>>
>> If Timon gets static for each into the language, it can look a little better.
>
> Can you help me understand what you mean? How will it improve things? (static foreach would disable the "statement not reachable" analysis?)

The new static foreach is AFAIK supposed to execute the loop instead of unrolling it, i.e. the expansion of

---
foreach (i, U; T) {
    static if (is(U == bool)) {
        return false;
    }
}
return true;
---

to

---
    static if (is(U1 == bool)) {
        return false;
    }
    static if (is(U2 == bool)) {
        return false;
    }
    ...
return true;
---

, which triggers that "statement is not reachable"  if at least one of U1,U2,... = T is bool, will not occur if you instead use `static foreach (i, U; T)`.