digitalmars.D.bugs - [Issue 24527] New: opAssign has no effect during CTFE when an array
- d-bugmail puremagic.com (138/138) Apr 28 https://issues.dlang.org/show_bug.cgi?id=24527
https://issues.dlang.org/show_bug.cgi?id=24527 Issue ID: 24527 Summary: opAssign has no effect during CTFE when an array is wrapped in a range Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: normal Priority: P1 Component: dmd Assignee: nobody puremagic.com Reporter: issues.dlang jmdavisProg.com This code fails --- import std.range.primitives; struct Foo(R) { property empty() { return _input.empty; } property front() { return _input.front; } property front(ElementType!R val) { _input.front = val; } void popFront() { _input.popFront; } R _input; } auto foo(R)(R r) { return Foo!R(r); } unittest { struct S { int entry; void opAssign(S rhs) { this.entry = rhs.entry; } } auto test() { auto arr = [S(0), S(1), S(2), S(3), S(4)]; auto range = arr.foo; range.front = S(42); return range; } import std.algorithm.comparison; auto runtime = test; assert(equal(runtime, [S(42), S(1), S(2), S(3), S(4)])); enum ctfe = test; // First element is actually S(0), meaning that it wasn't set. assert(equal(ctfe, [S(42), S(1), S(2), S(3), S(4)])); } void main() { } --- The assignment works just fine if it's done during runtime, but it has no effect if it's done at compile time. Assigning to the array directly seems to work, so the range wrapper is affecting things somehow. Similarly, if the opAssign is removed from S, then the assignment works, so it's the combination of using a wrapper struct and defining an opAssign which is triggering this. Also, whether the range is returned is irrelevant, you can simply assert that the value changed after it was set in test, and it will fail during CTFE but succeed at runtime. I returned the range in the example so that both the compile-time and runtime results could be shown. If I changed the example so that S is internal to the test function, and add a bool that gets set when test is called, e.g. --- auto test() { bool called; struct S { int entry; void opAssign(S rhs) { called = true; this.entry = rhs.entry; } } auto arr = [S(0), S(1), S(2), S(3), S(4)]; auto range = arr.foo; called = false; range.front = S(42); assert(called); assert(range.front == S(42)); return range; } --- then it shows that opAssign is called, but it fails to actually set the value. If I change test to --- auto test() { bool called; struct S { int entry; void opAssign(S rhs) { called = true; this.entry = rhs.entry; assert(this.entry == 42); } } auto arr = [S(0), S(1), S(2), S(3), S(4)]; auto range = arr.foo; called = false; range.front = S(42); assert(called); assert(range.front == S(42)); return range; } --- then the assertion inside of opAssign actually passes, but the one checking the value after the call does not. So, it's like opAssign is operating on a copy rather than on the actual value. --
Apr 28