Bug 7676 – covariance of out arguments and function subtyping doesn't work

Status
REOPENED
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-03-09T08:17:46Z
Last change time
2024-12-13T17:58:56Z
Assigned to
No Owner
Creator
Boscop
Moved to GitHub: dmd#18423 →

Comments

Comment #0 by kingboscop — 2012-03-09T08:17:46Z
The title says it all. Here is a test case (DMD 2.058): --- // Functions are contravariant in their in-arguments // and covariant in their out-arguments and return type. // But DMD seems to ignore this: import std.stdio; class A {override string toString(){return "A";}} class B : A {override string toString(){return "B";}} void fooA(out A a) {a = new A;} void fooB(out B b) {b = new B;} string barA(A a) {return a.toString();} string barB(B b) {return b.toString();} void main() { A a = new A; a = new B; // correct covariant behavior assert(a.toString() == "B"); // out arguments should be covariant, so this should work: fooB(a); // Error: function test.fooB (out B b) is not callable using argument types (A) // Error: cannot implicitly convert expression (a) of type test.A to test.B void function(out A) foo; foo = &fooA; // same type, trivial foo(a); assert(a.toString() == "A"); // this should also work without a cast because // void function(out B) is a subtype of void function(out A) // due to the covariance of out arguments foo = &fooB; // Error: cannot implicitly convert expression (& fooB) of type void function(out B b) to void function(out A) // currently it only works with a cast: // foo = cast(void function(out A))&fooB; foo(a); assert(a.toString() == "B"); B b = new B; assert(barA(b) == "B"); // correct contravariant behavior string function(B) bar; bar = &barB; // same type, trivial assert(bar(b) == "B"); // string function(A) is a subtype of string function(B) // due to the contravariance of (in) arguments // so this should work: bar = &barA; // Error: cannot implicitly convert expression (& barA) of type string function(A a) to string function(B) // currently it only works with a cast: // bar = cast(string function(B))&barA; assert(bar(b) == "B"); // this fails as it should, but for the wrong reason: fooA(b); // Error: cast(A)b is not an lvalue // it should fail because fooA's 1st argument is covariant and should therefore only accept supertypes of A (A is also a supertype of A), but B is a subtype of A } --- To me it seems that DMD treats out arguments as contravariant at first (which then fails due to the implicit cast resulting in an rvalue) and it seems to ignore covariance and contravariance for function subtyping.
Comment #1 by bugzilla — 2012-03-09T11:14:29Z
This is an enhancement because D was not designed to deal with covariance for 'out' parameters, only covariance in return type.
Comment #2 by maxhaton — 2021-01-24T07:10:02Z
Spec/DIPfodder
Comment #3 by robert.schadek — 2024-12-13T17:58:56Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18423 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB