May 26, 2022

Hi,

I was reading the source of std.algorithm cache and saw some code that didn't make sense to me with a comment indexing the bug report. Could anyone help to understand if this code is really necessary (meaning I have some misconception) or is it a work around a compiler bug. Here is the code simplified down as much as I could:

import std.range.primitives;
import std.traits;


struct _Cache(R)
{
    private
    {
        alias UE = Unqual!(ElementType!R);
        R source;
        UE caches;
    }

    this(R range)
    {
        source = range;
        if (!range.empty)
        {
            caches = source.front;
        }/*  else {  //Uncomment "else" to fix broken version (see below)
           caches = UE.init;
        }*/
    }
}

struct _ConstructorlessCache(R) {
        private
    {
        alias UE = Unqual!(ElementType!R);
        R source;
        UE caches;
    }
}

auto constructorlessCache(Range)(Range range) {
    auto ret = _ConstructorlessCache!Range(range);
    if (!range.empty)
    {
        ret.caches = range.front;
    }
    return ret;
}

auto cache(Range)(Range range) {
    return _Cache!(Range)(range);
}

auto map(alias fun, Range)(Range range) {
    return MapResult!(fun,Range)(range);
}


struct MapResult(alias fun, Range)
{
    alias R = Unqual!Range;
    R _input;

    bool empty() { return _input.empty; }

    auto ref front() { return fun(_input.front); }
}


void main() {
    /* Won't compile unless part near top is uncommented. Gives:
onlineapp.d(21): Error: one path skips field `caches`
onlineapp.d(75): Error: template instance `onlineapp.cache!(MapResult!(__lambda1, int[]))` error instantiating
*/
    //[1].map!(x=>[x].map!(y=>y)).cache;
    //What seems to be essentially the same code compiles fine
    [1].map!(x=>[x].map!(y=>y)).constructorlessCache;
}