Update
In the original question, there was a problem that I identified (see below). However, the fix that I am describing is great for XE3 and later, but the program below does not compile in XE2. Thus, I conclude that this is an XE2 generator compiler error.
In any case, the workaround for Delphi XE2 :
{$APPTYPE CONSOLE} type IStorageObject = interface(IInterface) end; TObjectStorage<T: IStorageObject> = class(TObject) end; IKeyStorageObject<TKey> = interface(IStorageObject) end; TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>) end; TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>) end; begin TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create; end.
Original answer
It would be better if you provided a complete program in which a compiler error was detected. You need to try to instantiate the object to see this error.
But, I think I reproduced your problem. Therefore, I believe the problem is that this code:
TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...
applies the general constraint to both TKey and T Now, obviously, you want the constraint to be applied to T , so you need to write:
TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...
Here's a short program that compiles after changing Delphi XE3 :
{$APPTYPE CONSOLE} type IStorageObject = interface(IInterface) end; TObjectStorage<T: IStorageObject> = class(TObject) end; IKeyStorageObject<TKey> = interface(IStorageObject) end; TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>) end; TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>) end; begin TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create; end.
This is a pretty nuance, changing a comma to a semicolon. Programming with significant punctuation is never very fun. However, you are familiar with the difference between commas and half-columns in formal parameter lists, and therefore it should not be too unexpected to see the same difference drawn here.
The documentation covers your opinion:
Parameters of several types
When specifying restrictions, you highlight several parameters such as semicolons, as you do with the declaration of the parameter list:
type TFoo<T: ISerializable; V: IComparable>
Like parameter declarations, you can group several type parameters together in a comma list to bind to the same restrictions:
type TFoo<S, U: ISerializable> ...
In the above example, S and U bound to an ISerializable constraint.