Bug 3674 – forward reference error with multiple overloads with same name
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2010-01-05T00:24:00Z
Last change time
2015-06-09T01:28:19Z
Keywords
patch, rejects-valid
Assigned to
nobody
Creator
r.sagitario
Comments
Comment #0 by r.sagitario — 2010-01-05T00:24:36Z
The following code fails to compile:
public interface IQGraphicsItem
{
public QGraphicsObject toGraphicsObject();
public QGraphicsObject toGraphicsObject() const;
}
public class QGraphicsLineItem : IQGraphicsItem
{
public final QGraphicsObject toGraphicsObject() { return null; } // Line 10
public final QGraphicsObject toGraphicsObject() const { return null; }
}
public abstract class QGraphicsObject : IQGraphicsItem // line 14
{
public final QGraphicsObject toGraphicsObject() { return null; }
public final QGraphicsObject toGraphicsObject() const { return null; }
}
with error:
test.d(14): Error: class test.QGraphicsObject base class is forward referenced by QGraphicsObject
Actually the error is caused on by the reference in line 11.
The error does not happen there is only a single method toGraphicsObject().
Comment #1 by r.sagitario — 2010-01-05T00:36:08Z
The error occurs when dmd tries to match the overloaded member function to the functions in the base class, but hits the slightly different prototype. It then tries to check the return type for covariance, which fails on the forward referenced class.
here's a patch (or maybe just a workaround as I'm not perfectly sure what this does to erronous declarations), but it also fixes the problem, if the return type is actually a forward referenced covariant class.
Index: func.c
===================================================================
--- func.c (revision 324)
+++ func.c (working copy)
@@ -510,9 +510,20 @@
/* Only need to have a tintro if the vptr
* offsets differ
*/
+ unsigned errors = global.errors;
+ global.gag++; // suppress printing of error messages
int offset;
- if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+ int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset);
+ global.gag--; // suppress printing of error messages
+ if(errors != global.errors)
{
+ // any error in isBaseOf() is a forward reference error, so we bail out
+ global.errors = errors;
+ cd->sizeok = 2; // can't finish due to forward reference
+ return;
+ }
+ if (baseOf)
+ {
ti = fdv->type;
#if 0
if (offset)
Comment #2 by e.insafutdinov — 2010-01-06T00:14:03Z
As it implies from the testcase this is a blocker for QtD.
Comment #3 by bugzilla — 2010-01-17T23:55:32Z
Changeset 338
Comment #4 by r.sagitario — 2010-01-20T14:48:34Z
The current revision (342) now shows a different error, even with a slightly reduced test case:
public class IQGraphicsItem
{
public QGraphicsObject toGraphicsObject();
public QGraphicsObject toGraphicsObject() const;
}
public abstract class QGraphicsObject : IQGraphicsItem
{
public final QGraphicsObject toGraphicsObject() { return null; } // Line 10
public final QGraphicsObject toGraphicsObject() const { return null; } // Line 11
}
and causes
test.d(11): Error: function test.QGraphicsObject.toGraphicsObject cannot override final function test.QGraphicsObject.toGraphicsObject
This is what happens:
dmd searches its vtbl for a covariant function that is overridden by "toGraphicsObject() const". The rules in Type::covariant() state, that it's ok to match the non-const version of toGraphicsObject(). This triggers two problems:
- The first match is taken, not the best.
- The class's vtbl is searched, not the vtbl of the base class. As the non-const version of the function is already matched and placed into the vtbl, the function type might have changed due to covariance. In this case, it is final now.
Here's a patch to solve both issues:
Index: func.c
===================================================================
--- func.c (revision 342)
+++ func.c (working copy)
@@ -382,7 +382,7 @@
}
// Find index of existing function in vtbl[] to override
- vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0);
+ vi = cd->baseClass ? findVtblIndex(&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) : -1;
switch (vi)
{
case -1:
@@ -426,7 +426,7 @@
return;
default:
- { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi];
+ { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl.data[vi];
// This function is covariant with fdv
if (fdv->isFinal())
error("cannot override final function %s", fdv->toPrettyChars());
@@ -1689,11 +1689,15 @@
int FuncDeclaration::findVtblIndex(Array *vtbl, int dim)
{
+ FuncDeclaration *mismatch = 0;
+ int bestvi = -1;
for (int vi = 0; vi < dim; vi++)
{
FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration();
if (fdv && fdv->ident == ident)
{
+ if (type->equals(fdv->type))
+ return vi;
int cov = type->covariant(fdv->type);
//printf("\tbaseclass cov = %d\n", cov);
switch (cov)
@@ -1702,14 +1706,15 @@
break;
case 1:
- return vi;
+ bestvi = vi; // covariant, but not identical
+ break;
case 2:
+ if(!mismatch) // give a second chance to find exact match
+ mismatch = fdv;
//type->print();
//fdv->type->print();
//printf("%s %s\n", type->deco, fdv->type->deco);
- error("of type %s overrides but is not covariant with %s of type %s",
- type->toChars(), fdv->toPrettyChars(), fdv->type->toChars());
break;
case 3:
@@ -1720,7 +1725,10 @@
}
}
}
- return -1;
+ if(bestvi < 0 && mismatch)
+ error("of type %s overrides but is not covariant with %s of type %s",
+ type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars());
+ return bestvi;
}
/****************************************************
Comment #5 by e.insafutdinov — 2010-01-21T13:37:38Z
When fixing this also make sure this testcase passes:
public class IQGraphicsItem
{
public QGraphicsObject toGraphicsObject();
public const(QGraphicsObject) toGraphicsObject() const;
}
public abstract class QGraphicsObject : IQGraphicsItem
{
public final QGraphicsObject toGraphicsObject() { return null; }
public final const(QGraphicsObject) toGraphicsObject() const { return null; }
}
As it currently doesn't, with a different error message.
Thanks.
Comment #6 by bugzilla — 2010-01-21T20:21:23Z
Changeset 344 for second problem.
Comment #7 by r.sagitario — 2010-01-22T00:39:03Z
Thanks, it works now. This also fixes issue 3282 which is what happened if you did not use "final" to produce an error at compile time. See comments there for another quirk.