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
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.