I have a protocol, used to erase the generic parameters:
protocol PropertyBagProtocol
{
func getValue<ownerT, valueT>(for keyPath: PartialKeyPath<ownerT>) -> valueT
func setValue<ownerT, valueT>(_ value: valueT, for keyPath: PartialKeyPath<ownerT>)
}
Then I have the "main part" of a generic class:
class PropertyBag<ownerT>
{
private var owner: ownerT
init(for owner: ownerT)
{
self.owner = owner
}
lazy var properties: [PartialKeyPath<ownerT> : PropertyProtocol] =
{
var properties = [PartialKeyPath<ownerT> : PropertyProtocol]()
… // other code
return properties
}()
}
Then I have an extension to the generic class, to implement the type-erasing protocol:
extension PropertyBag : PropertyBagProtocol
{
func getValue<ownerT, valueT>(for keyPath: PartialKeyPath<ownerT>) -> valueT
{
do
{
return try properties[keyPath]?.getValue() *** error
}
catch
{
fatalError()
}
}
func setValue<ownerT, valueT>(_ value: valueT, for keyPath: PartialKeyPath<ownerT>)
{
do
{
try properties[keyPath]?.setValue(value) *** error
}
catch
{
fatalError()
}
}
}
The error is: Cannot subscript a value of type '[PartialKeyPath<ownerT> : PropertyProtocol]' with an index of type 'PartialKeyPath<ownerT>'
If I redefine the generic methods to avoid the same generic parameter name:
protocol PropertyBagProtocol
{
func getValue<ownerType, valueT>(for keyPath: PartialKeyPath<ownerType>) -> valueT
func setValue<ownerType, valueT>(_ value: valueT, for keyPath: PartialKeyPath<ownerType>)
}
… then this just gives the same errors with the different parameter name:
extension PropertyBag : PropertyBagProtocol
{
func getValue<ownerType, valueT>(for keyPath: PartialKeyPath<ownerType>) -> valueT
{
do
{
return try properties[keyPath]?.getValue() *** error
}
catch
{
fatalError()
}
}
func setValue<ownerType, valueT>(_ value: valueT, for keyPath: PartialKeyPath<ownerType>)
{
do
{
try properties[keyPath]?.setValue(value) *** error
}
catch
{
fatalError()
}
}
}
Error is now: Cannot subscript a value of type '[PartialKeyPath<ownerT> : PropertyProtocol]' with an index of type 'PartialKeyPath<ownerType>'
If I insert the following guard clause to cast from the method's generic parameter type to the class's generic parameter type:
…
guard let keyPath = keyPath as? PartialKeyPath<ownerT> else
{
fatalError()
}
…
That solves the error but I then get the following warning: Cast from 'PartialKeyPath<ownerType>' to unrelated type 'PartialKeyPath<ownerT>' always fails.
Except that, if I ignore the warning and run the code, the cast succeeds perfectly
I have seen a similar false positive when casting generic types in other situations but I would really appreciate it if anyone has got any ideas how to go about implementing a generic method from a non-generic protocol in a generic class that uses the same parameter type.