Bug 10926 – Wrong expression printed when ternary operator used as lvalue

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-08-30T04:51:36Z
Last change time
2020-12-13T20:00:15Z
Keywords
diagnostic, pull
Assigned to
No Owner
Creator
bearophile_hugs
See also
https://issues.dlang.org/show_bug.cgi?id=21479

Comments

Comment #0 by bearophile_hugs — 2013-08-30T04:51:36Z
void main() { const(int)[] a, b; int[] c, d; (true ? a : b) ~= 10; // OK pragma(msg, typeof(true ? a : c)); // const(int)[] (true ? a : c) ~= 20; // line 6, Error: a is not an lvalue (true ? c : d) ~= 30; // OK } DMD 2.064alpha gives: test.d(6): Error: a is not an lvalue
Comment #1 by bearophile_hugs — 2013-08-30T07:49:31Z
See also Issue 10315
Comment #2 by yebblies — 2013-11-12T07:20:32Z
No rejects-valid here, it simply prints the wrong expression. https://github.com/D-Programming-Language/dmd/pull/2750
Comment #3 by bearophile_hugs — 2013-11-12T10:00:09Z
(In reply to comment #2) > No rejects-valid here, it simply prints the wrong expression. > > https://github.com/D-Programming-Language/dmd/pull/2750 Please help me understand. This is a reduced test code: void main() { const(int)[] a; int[] c; (true ? a : c) ~= 20; } Before this fix it gave: temp.d(4): Error: a is not an lvalue Now it gives: temp.d(4): Error: cast(const(int)[])c is not an lvalue How is the error message improved? c is a fully mutable array. Why isn't this output a rejects-valid still? Both a and c can be appended. The common type between a and c should be const(int)[], that is appendable. (If I receive no good answer I'll reopen this issue later.)
Comment #4 by yebblies — 2013-11-12T10:14:59Z
(In reply to comment #3) > (In reply to comment #2) > > No rejects-valid here, it simply prints the wrong expression. > > > > https://github.com/D-Programming-Language/dmd/pull/2750 > > Please help me understand. This is a reduced test code: > > > void main() { > const(int)[] a; > int[] c; > (true ? a : c) ~= 20; > } > > > Before this fix it gave: > temp.d(4): Error: a is not an lvalue > > Now it gives: > temp.d(4): Error: cast(const(int)[])c is not an lvalue > > How is the error message improved? c is a fully mutable array. > > Why isn't this output a rejects-valid still? Both a and c can be appended. The > common type between a and c should be const(int)[], that is appendable. > > (If I receive no good answer I'll reopen this issue later.) c can be appended to, but cast(const(int)[])c cannot, because it is an rvalue. Would this make any sense? (cast(const(int)[])c) ~= 20;
Comment #5 by bearophile_hugs — 2013-11-12T10:29:09Z
(In reply to comment #4) > Would this make any sense? > > (cast(const(int)[])c) ~= 20; You are probably right, but it's quite surprising: void main() { const(int)[] a, b; int[] c, d; (true ? a : b) ~= 10; // OK (true ? c : d) ~= 20; // OK (true ? a : c) ~= 30; // Error: cast(const(int)[])c is not an lvalue if (true) a ~= 40; // OK else c ~= 40; // OK } So if both are fully mutable, or both have const items then you can append to them, but if one of them is mutable and the other has const items, then it can't append and you have to use a regular if statement. Thank you for your answer, I'll keep this issue closed.
Comment #6 by yebblies — 2013-11-12T20:12:14Z
(In reply to comment #5) > (In reply to comment #4) > > > Would this make any sense? > > > > (cast(const(int)[])c) ~= 20; > > > You are probably right, but it's quite surprising: > > > void main() { > const(int)[] a, b; > int[] c, d; > (true ? a : b) ~= 10; // OK > (true ? c : d) ~= 20; // OK > (true ? a : c) ~= 30; // Error: cast(const(int)[])c is not an lvalue > if (true) > a ~= 40; // OK > else > c ~= 40; // OK > } > > > So if both are fully mutable, or both have const items then you can append to > them, but if one of them is mutable and the other has const items, then it > can't append and you have to use a regular if statement. > > Thank you for your answer, I'll keep this issue closed. For a more involved answer: Appending modifies length, so it must be done on lvalues. `b ? a : c` can be transformed into an lvalue like this: `*(b ? &a : &c)` But if the types are different, it would have to end up as `*(b ? &a : cast(const(int)[]*)&c)` Which would allow `(b ? a : c) = a;` And that could cause 'c' to point to the data in 'a', which could be immutable. ======================================= This could be possible, if a new re-write was introduced: b ? a : c op ... -> b ? (a op ...) : (c op ...) But I'm not entirely sure we want that.