Bug 6519 – Problem with inout and type inference of polysemous types
Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2011-08-17T07:46:00Z
Last change time
2011-12-12T03:05:17Z
Keywords
rejects-valid
Assigned to
nobody
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2011-08-17T07:46:59Z
D2 code:
inout(int[]) foo(inout int[] data) {
return data;
}
void main() {
enum int[] a = [1, 2];
const r1 = foo(a); // OK
enum r2 = foo(a); // Not OK
}
DMD 2.055beta gives:
test.d(7): Error: variable test2.main.r2 only fields, parameters or stack based variables can be inout
test.d(7): Error: cannot evaluate foo([1,2]) at compile time
Comment #1 by clugdbug — 2011-08-17T08:49:42Z
This is an enum bug, not a CTFE problem. Here's a reduced test case:
inout(int) foo(inout int data) {
return data;
}
enum int e1 = foo(7); // OK
enum e1 = foo(7); // fails!
It thinks that you're trying to declare an enum of type 'inout(int)'.
Comment #2 by clugdbug — 2011-08-18T00:54:22Z
Here's an example which doesn't involve CTFE at all.
inout(int) foo(inout int data) {
return 7;
}
void main()
{
pragma(msg, typeof(foo(7)).stringof); // ---> inout(int)
}
The problem may be in expression.c, functionParameters().
If at parameter matches an inout parameter with implicit conversion, the inout stays unresolved. That's necessary to allow things like:
foo(A, B)(inout(A) a, inout(B) b)
when B is int; it should work when A is immutable, and also when it is mutable.
But...
array literals are a problem. You can write:
int[] a = [1,2,3];
and also
immutable(int)[] b = [1,2,3];
In the first case, a sort of implicit .dup gets added.
Suppose we define
inout(int[]) foo(inout(int[]) x) { return x; }
Should the following compile?
int[] x = foo([1,2,3]);
immutable(int[]) y = foo([1,2,3]);
const(int[]) z = foo([1,2,3]);
Currently only z compiles. The others say you cannot convert from inout(int[])
to int[].
One solution might be to say that if _all_ inout parameters are polysemous value types, so that the return constness remains ambiguous, a tie-breaking rule is applied to all of the parameters.
There are two reasonable options:
(a) always mutable. This would mean that x would compile, but z would stop working in existing code. y would continue to be rejected.
That is, the type of foo([1,2,3]) would be typeof([1,2,3]).
(b) always const. No change to what compiles. This gives more efficient code, since array literals don't need to be duped.
A third option would be that the return type propagates to the parameters.
Then, x, y, and z would all work, and we'd have perfect forwarding.
Implicit conversion of the return type of a call to such a function, would mean implicit conversion of all the ambiguous parameters to such a function. Note that this is recursive: a parameter of an inout function could itself be the return value of another inout function.
This would be optimally efficient; there would never be an unnecessary implicit .dup of array literals. It's a bit scary though -- I worry that that there might be unintended consequences of such an idea.
Comment #3 by k.hara.pg — 2011-08-31T10:30:12Z
I think this is a duplication of bug 3748.
With my patch (https://github.com/D-Programming-Language/dmd/pull/359), the sample code in comment #0 works correctly.
(In reply to comment #2)
> Should the following compile?
> int[] x = foo([1,2,3]);
> immutable(int[]) y = foo([1,2,3]);
> const(int[]) z = foo([1,2,3]);
D's literals work like polysemous value, but basically they have mutable types.
static assert(is(typeof([1, 2]) == int[]));
Therefore typeof(foo([1, 2])) equals to int[], and only y shouldn't compile, others should.
Comment #4 by k.hara.pg — 2011-12-12T03:05:17Z
*** This issue has been marked as a duplicate of issue 3748 ***