Generics and incompatible types.

Generics and incompatible types.

I’ve been buggered with an error that has me tearing the little I have left of hair out.  

[dcc32 Error] DUnitX_PSDCarrierTypes.pas(75): E2010 Incompatible types: ‘TPSDCarrierType’ and ‘TPSDBase’

The problem is that DUnitX_PSDCarrierTypes.pas only has 73 lines.

Has anyone seen this before?  Can you remember what the underlying cause was at the time?  Property or method visibility?  Missing unit inclusion? Abstract methods?

Let me introduce the classes

In PSDBase,

  TPSDBase = class (TLockableObject, ILogInterface)

    …

   end;

and

  TTestBaseClass = class

  private

    FInstance: T;

    function GetInstance: TPSDBase;

  protected

    property Instance: TPSDBase read GetInstance;

   …

end;

In PSDCarrierTypes,

  TPSDCarrierType = class(TPSDBase)

 …

  end;

 

unit DUnitX_PSDBase;

interface

uses

  PSDBase, PSDConstants,

  DUnitX.TestFramework;

type

  ///

Basis generic test class for TPSDBase descendants

  TTestClass = class(TTestBaseClass)

  …

end;

and 

[TestFixture]

TestTPSDBase = class(TTestClass)

  …

end;

 

unit DUnitX_PSDCarrierTypes;

interface

uses

  DUnitX.TestFramework,

  PSDConstants, PSDBase, DUnitX_PSDBase, PSDCarrierTypes;

type

  [TestFixture]

  TestTPSDCarrierType= class(TTestClass)

  …

  end;

 

The main app looks has the following uses

program DUnitX_PSD_BasicUnitTests;

uses

  EMemLeaks,

  EResLeaks,

  EDialogWinAPIEurekaLogDetailed,

  EDialogWinAPIStepsToReproduce,

  EDebugExports,

  EFixSafeCallException,

  EMapWin32,

  EAppVCL,

  ExceptionLog7,

  SysUtils,

  DUnitX.AutoDetect.Console,

  DUnitX.Loggers.Console,

  DUnitX.Loggers.Xml.NUnit,

  DUnitX.TestRunner,

  DUnitX.TestFramework,

  PSDBase in ‘..PSDCommonPSDBase.pas’,

  PSDCarrierTypes in ‘..PSDCommonPSDCarrierTypes.pas’,

  DUnitX_PSDBase in ‘DUnitX_PSDBase.pas’,

  DUnitX_PSDCarrierTypes in ‘DUnitX_PSDCarrierTypes.pas’;

At first, I thought there was something weird about the order of compilation, but no – it looks normal.

14:54:39,1355491 DUnitX.ConsoleWriter.Base.dcu

14:54:39,2945261 DUnitX.Utils.dcu

14:54:39,3847109 DUnitX.IoC.dcu

14:54:39,4146560 DUnitX.Windows.Console.dcu

14:54:39,4222502 DUnitX.AutoDetect.Console.dcu

14:54:39,4371663 DUnitX.Generics.dcu

14:54:39,4582339 DUnitX.Extensibility.dcu

14:54:39,5233700 DUnitX.InternalInterfaces.dcu

14:54:39,5430712 DUnitX.WeakReference.dcu

14:54:39,5612627 DUnitX.Test.dcu

14:54:39,5751848 DUnitX.TestFixture.dcu

14:54:39,6043794 DUnitX.RunResults.dcu

14:54:39,6422193 DUnitX.TestResult.dcu

14:54:39,6714326 DUnitX.FixtureResult.dcu

14:54:39,7038809 DUnitX.Extensibility.PluginManager.dcu

14:54:39,8034689 DUnitX.TestRunner.dcu

14:54:39,8136915 DUnitX.CommandLine.dcu

14:54:39,8669545 DUnitX.MemoryLeakMonitor.Default.dcu

14:54:39,9958192 DUnitX.FixtureProviderPlugin.dcu

14:54:40,1629623 DUnitX.TestFramework.dcu

14:54:40,2033539 DUnitX.Loggers.Console.dcu

14:54:40,2217283 DUnitX.Loggers.Null.dcu

14:54:40,2732231 DUnitX.Loggers.XML.NUnit.dcu

14:54:40,3435106 StringFunctions.dcu

14:54:40,3692211 CustomDebugOut.dcu

14:54:40,3768381 Functions.dcu

14:54:40,7058753 FileFunctions.dcu

14:54:40,7107884 TINEFunctions.dcu

14:54:40,7191973 TineInterfaces.dcu

14:54:40,7319419 PSDConstants.dcu

14:54:40,7487508 TineClasses.dcu

14:54:40,7766713 PSDXMLLog.dcu

14:54:40,7834018 PSDLogEvent.dcu

14:54:40,7919438 PSDLogExceptionManager.dcu

14:54:40,8042575 PSDLogDrivers.dcu

14:54:40,8155411 tiConsts.dcu

14:54:40,8266076 PSDResourcePool.dcu

14:54:40,8517546 PSDConnectivityStatus.dcu

14:54:40,8632446 PSD_Db_Abstract.dcu

14:54:40,8960845 PSD_TCPTelegramBase.dcu

14:54:40,9079624 PSD_TCP_Types.dcu

14:54:40,9199220 PSD_TCPTelegrams.dcu

14:54:41,0200024 PSDBase.dcu

14:54:41,1065126 PSDCarrierTypes.dcu

14:54:41,1135979 DUnitX_PSDBase.dcu

…then the compilation fails for unit DUnitX_PSDCarrierType, 2 lines beyond end of unit.

17 thoughts on “Generics and incompatible types.


  1. I have seen this before. It is obviously a compiler bug. In my case, it was because I had an AS statement , i.e. in your case it would be


    T as TPDSBAse


    when I changed it to


    TPDFBase(T),


    everything started compiling correctly. Now, I also did a bunch of other changes to try to fix it, but this seemed to be the one that did the trick for me.


  2. Had a few ‘ as ‘, but it was other classes.  Changed them to TypeName(Reference) – but it didn’t help.  I also merged the TTestBaseClass into TTestClass and removed TTestBaseClass from the PSDBase Unit. Still stuck T.T


  3. Stefan Glienke – Although that brings it down to 22 units, it is far from trivial to prune more code.  TPSDBase is a big-ass service class (4500 lines).  I wonder if EMBT will accept that much code for identifying the problem, and at the same time keep that code to themselves?


  4. By the way the E2010 is correct: TPSDCarrierType and TPSDBase are not compatible . They are only compatible the other way around. So somewhere in your code you are assigning a TPSDBase to a TPSDCarrierType (most likely in some of the generic types). This might be caused by type constaints. So check for that.


    Edit: the Instance property and its getter needs to to be T and not TPSDBase.


  5. Stefan Glienke – Thanks for proving that I am an idiot!  😉


    In DUnitX_PSDBase,


    procedure TTestClass.CreateFromJSON(const aJSON: String);


    begin


      FInstance := TPSDBase.CreateFromJSON (aJSON);


      Assert.IsTrue(Assigned(Instance));


    end;


    should read


    procedure TTestClass.CreateFromJSON(const aJSON: String);


    begin


      TPSDBase(FInstance) := T.CreateFromJSON (aJSON);


      Assert.IsTrue(Assigned(Instance));


    end;


    Now it compiles!


    I guess I have to make a sample of this and submit a QC, because the error leads you on a wild goose chase.  Imaging if my Generics code was nested even deeper…


  6. Stefan Glienke Well normally I’m the last one to blame the compiler… but when you get BS error messages like that, refering to lines that doesn’t exist, it’s hard to avoid 😉


  7. The error is correct. If you read the documentation of E2010 you see “The first type in this message is the type expected, and the second type is the type that was given.”


    The problem with generics is the compiler obviously does not stop at the correct line. I would even argue that the line fInstance := TPSDBase.Create is not valid.  The compiler does not complain about it because of the constraint but it is only valid for one particular case: if T is TPSDBase but not for any other subclass of TPSDBase)


  8. Stefan Glienke Yeah, but it’s hard to trust the rest of the message when it refers to imaginary lines of code…


    While it made sense in this case, I’ve had a lot of cases when the error message was completely bogus when dealing with generics.


    Though as mentioned in the forums, most of my issues have been fixed so hopefully XE6 will be decent when it comes to generics.


  9. Stefan Glienke – Should prolly mention that the problem is even more confusing if the descendent class is in a different unit, since the error appears to be in that second unit, instead of the first.


  10. You are free to report the issue with the bogus/wrong line number compiler error and mention that 🙂 My report is about the issue that the use of a constraint does hide the error until you instantiate the class while it should be triggered even without ever instantiating it.

Leave a Reply