digitalmars.D - chunkBy bug?
- JG (160/160) Sep 04 2020 The following code won't compile:
- JG (1/1) Sep 04 2020 Sorry for posting to general. I meant to post to learn.
- H. S. Teoh (6/23) Sep 04 2020 [...]
- JG (6/32) Sep 05 2020 Thanks for your reply. I was getting the same error with both dmd
- H. S. Teoh (9/13) Sep 06 2020 The problem was caused by nested structs needing a context pointer, and
- Seb (7/27) Sep 06 2020 It's hard to read this and compare against the original
- JG (17/22) Sep 07 2020 I compiled dmd and phobos from source. Using the same code as
The following code won't compile: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main ---- Is this expected behavior? I can get it to run as expected by modifying the source of chunkBy as follows: ---- import std.range; import std.stdio; import std.traits; import std.functional; private template ChunkByImplIsUnary(alias pred, Range) { alias e = lvalueOf!(ElementType!Range); static if (is(typeof(binaryFun!pred(e, e)) : bool)) enum ChunkByImplIsUnary = false; else static if (is(typeof(unaryFun!pred(e) == unaryFun!pred(e)) : bool)) enum ChunkByImplIsUnary = true; else static assert(0, "chunkBy expects either a binary predicate or "~ "a unary predicate on range elements of type: "~ ElementType!Range.stringof); } // Outer range struct Impl(Range) { size_t groupNum; Range current; Range next; } // Inner range struct Group(alias eq, Range) { import std.typecons : RefCounted; private size_t groupNum; private Range start; private Range current; private RefCounted!(Impl!Range) mothership; this(RefCounted!(Impl!Range) origin) { groupNum = origin.groupNum; start = origin.current.save; current = origin.current.save; assert(!start.empty, "Passed range 'r' must not be empty"); mothership = origin; // Note: this requires reflexivity. assert(eq(start.front, current.front), "predicate is not reflexive"); } property bool empty() { return groupNum == size_t.max; } property auto ref front() { return current.front; } void popFront() { current.popFront(); // Note: this requires transitivity. if (current.empty || !eq(start.front, current.front)) { if (groupNum == mothership.groupNum) { // If parent range hasn't moved on yet, help it along by // saving location of start of next Group. mothership.next = current.save; } groupNum = size_t.max; } } property auto save() { auto copy = this; copy.current = current.save; return copy; } } private struct ChunkByImpl(alias pred, Range) if (isForwardRange!Range) { import std.typecons : RefCounted; enum bool isUnary = ChunkByImplIsUnary!(pred, Range); static if (isUnary) alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b)); else alias eq = binaryFun!pred; static assert(isForwardRange!(Group!(eq,Range))); private RefCounted!(Impl!Range) impl; this(Range r) { impl = RefCounted!(Impl!Range)(0, r, r.save); } property bool empty() { return impl.current.empty; } property auto front() { static if (isUnary) { import std.typecons : tuple; return tuple(unaryFun!pred(impl.current.front), Group(impl)); } else { return Group!(eq,Range)(impl); } } void popFront() { // Scan for next group. If we're lucky, one of our Groups would have // already set .next to the start of the next group, in which case the // loop is skipped. while (!impl.next.empty && eq(impl.current.front, impl.next.front)) { impl.next.popFront(); } impl.current = impl.next.save; // Indicate to any remaining Groups that we have moved on. impl.groupNum++; } property auto save() { // Note: the new copy of the range will be detached from any existing // satellite Groups, and will not benefit from the .next acceleration. return typeof(this)(impl.current.save); } static assert(isForwardRange!(typeof(this)), typeof(this).stringof ~ " must be a forward range"); } auto chunkBy(alias pred, Range)(Range r) if (isInputRange!Range) { return ChunkByImpl!(pred, Range)(r); } void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.chunkBy!((a,b)=>a%i==b%i)); } } ---
Sep 04 2020
Sorry for posting to general. I meant to post to learn.
Sep 04 2020
On Sat, Sep 05, 2020 at 03:30:33AM +0000, JG via Digitalmars-d wrote:The following code won't compile: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main ----[...] Are you using LDC? IIRC there was a recent bug fixed in dmd that fixes this problem in some cases, but LDC still has this bug. Maybe try with dmd to see if it works? --T
Sep 04 2020
On Saturday, 5 September 2020 at 04:10:58 UTC, H. S. Teoh wrote:On Sat, Sep 05, 2020 at 03:30:33AM +0000, JG via Digitalmars-d wrote:Thanks for your reply. I was getting the same error with both dmd and ldc, I will try updating. For clarity do you know what precisely is causing the problem? My "fix" was to un-nest the structs used in chunkBy. Was the bug in dmd, something to do with nested structs?The following code won't compile: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main ----[...] Are you using LDC? IIRC there was a recent bug fixed in dmd that fixes this problem in some cases, but LDC still has this bug. Maybe try with dmd to see if it works? --T
Sep 05 2020
On Sat, Sep 05, 2020 at 11:14:08AM +0000, JG via Digitalmars-d wrote: [...]Thanks for your reply. I was getting the same error with both dmd and ldc, I will try updating. For clarity do you know what precisely is causing the problem? My "fix" was to un-nest the structs used in chunkBy. Was the bug in dmd, something to do with nested structs?The problem was caused by nested structs needing a context pointer, and an alias function parameter also needing a context pointer. Older versions of dmd could only handle 1 context pointer at a time, so was unable to handle this case. T -- Some ideas are so stupid that only intellectuals could believe them. -- George Orwell
Sep 06 2020
On Saturday, 5 September 2020 at 03:30:33 UTC, JG wrote:The following code won't compile: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main ---- Is this expected behavior?No.I can get it to run as expected by modifying the source of chunkBy as follows:It's hard to read this and compare against the original implementation here. If this issue still persists with master, why don't you simply open a PR for Phobos? Bug fixes are always welcome!
Sep 06 2020
On Sunday, 6 September 2020 at 17:08:06 UTC, Seb wrote:It's hard to read this and compare against the original implementation here. If this issue still persists with master, why don't you simply open a PR for Phobos? Bug fixes are always welcome!I compiled dmd and phobos from source. Using the same code as before: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- and compiling with the new version of dmd produces: ../../dlang/dmd/generated/osx/release/64/../../../../../phobos/std/algorith /iteration.d(2058): Error: function chunkByFix.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access delegate __lambda1 in frame of function D main I will see if I can figure out how to attempt a PR for phobos.
Sep 07 2020