www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - no size yet for forward reference error

reply Erik Smith <erik cruiserhouse.com> writes:
In the process of converting my working database interface to be 
template based, I now get the following compiler error:

Error: struct 
std.database.mock.database.Statement!int.Statement.Payload no 
size yet for forward reference

I minimized the code to make it easier reason about.  It seems to 
have something to do with Payload, but it may also have something 
to do with the ResultRange / Row circular references.

The error is reported in object.d(2762,45).  This is DMD v2.070.

Any Ideas?


unittest {
     auto db = Database!int.create();
     auto con = Connection!int(db);
}

struct Database(T) {
     static Database create() { return Database!T();}
}

struct Connection(T) {
     alias Database = .Database!T;
     alias Statement = .Statement!T;
}

struct Statement(T) {
     alias Connection = .Connection!T;
     alias Result = .Result;

     private:

     struct Payload {
         Connection con;
         this(Connection con_) {con = con_;}
         this(this) { assert(false); }
         void opAssign(Statement.Payload rhs) { assert(false); }
     }

     alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data;
     Data data_;
}

struct Result(T) {
     alias Statement = .Statement!T;
     alias ResultRange = .ResultRange!T;
     alias Range = .ResultRange;
     alias Row = .Row;

     this(Statement stmt) {data_ = Data(stmt);}
     ResultRange range() {return ResultRange(this);}
}

struct ResultRange(T) {
     alias Result = .Result!T;
     alias Row = .Row!T;
     private Result result_;
     this(Result result) {result_ = result;}
}


struct Row(T) {
     alias Result = .Result!T;
     this(Result* result) { result_ = result;}
     private Result* result_;
}
Feb 24 2016
parent reply Erik Smith <erik cruiserhouse.com> writes:
Here's a better reduction of the problem.  Commenting out either 
of the lines marked HERE eliminates the error.   It's some kind 
of interaction with templates, RefCounted, and the cross 
referencing types.

erik


module database;
import std.typecons;

unittest {
     auto con = Connection!int();
}

struct Connection(T) {
     alias Statement = .Statement!T;   // HERE
}

struct Statement(T) {
     alias Connection = .Connection!T;

     private:

     struct Payload {
         Connection con;
         this(Connection con_) {con = con_;}
     }

     alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data;
     Data data_;  // HERE
}
Feb 24 2016
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, 25 February 2016 at 04:23:52 UTC, Erik Smith wrote:
 Here's a better reduction of the problem.  Commenting out 
 either of the lines marked HERE eliminates the error.   It's 
 some kind of interaction with templates, RefCounted, and the 
 cross referencing types.

 erik


 module database;
 import std.typecons;

 unittest {
     auto con = Connection!int();
 }

 struct Connection(T) {
     alias Statement = .Statement!T;   // HERE
 }

 struct Statement(T) {
     alias Connection = .Connection!T;

     private:

     struct Payload {
         Connection con;
         this(Connection con_) {con = con_;}
     }

     alias RefCounted!(Payload, RefCountedAutoInitialize.no) 
 Data;
     Data data_;  // HERE
 }
Actually, both of your examples compile for me - both with master and with 2.070.0. I'm running on x86_64 FreeBSD (which you probably aren't), which shouldn't matter for this sort of error, but I suppose that it's possible that it's somehow system-specific, much as I wouldn't expect it to be. So, I don't what to say. :| - Jonathan M Davis
Feb 25 2016
next sibling parent reply bachmeier <no spam.com> writes:
On Thursday, 25 February 2016 at 17:33:34 UTC, Jonathan M Davis 
wrote:

 Actually, both of your examples compile for me - both with 
 master and with 2.070.0. I'm running on x86_64 FreeBSD (which 
 you probably aren't), which shouldn't matter for this sort of 
 error, but I suppose that it's possible that it's somehow 
 system-specific, much as I wouldn't expect it to be. So, I 
 don't what to say. :|

 - Jonathan M Davis
Same here. DMD 2.070.0 running on Linux Mint (built on Ubuntu 14.04).
Feb 25 2016
parent Erik Smith <erik cruiserhouse.com> writes:
I'm running OSX 10.11.2, DMD v2.070 installed via homebrew with 
--devel flag.

erik
Feb 25 2016
prev sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Thursday, 25 February 2016 at 17:33:34 UTC, Jonathan M Davis 
wrote:
 Actually, both of your examples compile for me - both with 
 master and with 2.070.0. I'm running on x86_64 FreeBSD (which 
 you probably aren't), which shouldn't matter for this sort of 
 error, but I suppose that it's possible that it's somehow 
 system-specific, much as I wouldn't expect it to be. So, I 
 don't what to say. :|
You need to compile with `-unittest`.
Feb 25 2016
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, 25 February 2016 at 20:14:20 UTC, Marc Schütz wrote:
 On Thursday, 25 February 2016 at 17:33:34 UTC, Jonathan M Davis 
 wrote:
 Actually, both of your examples compile for me - both with 
 master and with 2.070.0. I'm running on x86_64 FreeBSD (which 
 you probably aren't), which shouldn't matter for this sort of 
 error, but I suppose that it's possible that it's somehow 
 system-specific, much as I wouldn't expect it to be. So, I 
 don't what to say. :|
You need to compile with `-unittest`.
Ah, yes. I see now. And yes, that fails to compile. Well, given that you have types referring to each other, it's not all that hard to get a circular definition error. The most obvious is when you do something like struct A { B b; } struct B { A a; } And while the code in question doesn't do anything that blatant, it is having types refer to each other. What's incredibly weird is that if the RefCounted!(Payload, RefCountedAutoInitialize.no) is changed to Payload, the code works. If there were going to be a circular definition problem, then I'd think that it would occur without RefCounted being involved. I'd suggest copying RefCounted to your local file and using that version of it rather than introducing std.typecons into the mix, and then use dustmite to reduce it. Then you can track down which part of RefCounted is causing the problem. dustmite is now released with dmd, I believe, so you shouldn't need to track it down, and instructions for it can be found here: https://github.com/CyberShadow/DustMite/wiki - Jonathan M Davis
Feb 25 2016
parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
Digger shows that it stopped working after this PR:
https://github.com/D-Programming-Language/dmd/pull/4457

I could reduce it as far as this:

struct RefCounted(T) {
     struct Impl {
         T _payload;
     }

     Impl* _store;

     ~this() {
         destroy(_store._payload);
     }
}

struct Connection(T) {
     alias Statement = .Statement!T;
}

struct Statement(T) {
     alias Connection = .Connection!T;

     struct Payload {
         Connection con;
     }

     RefCounted!Payload Data;
}

Connection!int x;
Feb 25 2016
parent reply Erik Smith <erik cruiserhouse.com> writes:
Good to know that it's a bug - Thanks for the help.   I've 
created an issue to track this:

https://issues.dlang.org/show_bug.cgi?id=15726
Feb 25 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/25/2016 9:07 PM, Erik Smith wrote:
 Good to know that it's a bug - Thanks for the help.   I've created an issue to
 track this:

 https://issues.dlang.org/show_bug.cgi?id=15726
Thanks for preparing the bug report. You can probably work around the problem for the time being by making one of the mutually referencing structs a class.
Feb 25 2016
parent Erik Smith <erik cruiserhouse.com> writes:
The struct->class workaround is unworkable in this case because 
underlying C database clients are often pretty sensitive to out 
of order resource cleanup and generate errors or crash as a 
result.  The structs are essential but I will limit the design to 
avoid the issue for now.
Feb 26 2016