May 01
https://issues.dlang.org/show_bug.cgi?id=24531

          Issue ID: 24531
           Summary: foreach lowering fails to compile with dip1000 and
                    std.array.array
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: atila.neves@gmail.com

The code below fails to compile. This is the minimum reduction I could find. The `arrayCtfe` function is the static if branch in std.array.array for __ctfe. This particular example can be fixed with an alternative implementation that calls the range API directly like so:

------
    while(!range.empty) {
        result ~= range.front;
        range.popFront;
    }

    return result;
------

Unfortunately trying to do this in std.array results in compilation failures for other ranges, and checking that this implementation is valid for the range in question with `is(typeof)` or `__traits(compiles)` crashes the compiler.

Offending code:


-----
struct Target {
    string[] strings() @safe pure return scope const {
        return [];
    }
}

auto maybeAddDependencies(in Target target, in string projectPath) @safe pure {

    Target[] targets;
    scope srcs = targets.filter!(a => true);

    return srcs
        .map!(t => t.strings[0])
        .arrayCtfe
        ;
}

// this is the implementation in std.array.array guarded by `if(__ctfe)`
auto arrayCtfe(R)(auto ref R range) {
    import std.traits: ForeachType;
    ForeachType!R[] result; // string[]

    foreach (ref e; range) {
       result ~= e;
    }

    return result;
}
-----

--