I'm getting a compiler error from Swift 3.0.1 that's got me stumped. The error states that there's ambiguity in the type of a computed property but I can't see how.
I have a protocol Generic with a property root. This protocol has a generic constraint that root must be a subclass of type Root.
class Root { }
protocol Generic {
associatedtype RootType: Root
var root: RootType { get }
}
I then define a protocol extension that states:
If a
Genericis a subclass ofRoot, returnselffrom therootproperty.
So basically: if it's already a Root, you can just forward self.
extension Generic where Self: Root {
var root: Self {
return self
}
}
I also have a GenericWrapper class that is a subclass of Root and wraps an instance of Generic (to perform Root operations with a Generic proxy).
class GenericWrapper<T: Generic>: Root {
var generic: T
init(generic: T) {
self.generic = generic
}
}
Finally, I define a Specialised protocol, and an extension to it that states:
If a
SpecialisedimplementsGeneric, return aGenericWrapperfrom therootproperty.
protocol Specialised { }
extension Specialised where Self: Generic {
var root: GenericWrapper<Self> {
get {
return GenericWrapper(generic: self)
}
}
}
Then when I try to implement a class that implements Generic and Specialised, I'm getting this error.
class SpecialisedImplementation: Generic, Specialised {
// errors:
// Ambiguous inference of associated type 'RootType': 'GenericWrapper<SpecialisedImplementation>' vs. 'SpecialisedImplementation'
// Matching requirement 'root' to this declaration inferred associated type to 'GenericWrapper<SpecialisedImplementation>'
// Matching requirement 'root' to this declaration inferred associated type to 'SpecialisedImplementation'
}
The reason I'm confused is because the ambiguity states that the SpecialisedImplementation class matches the requirement from the extension to Generic when Generic: Root, but SpecialisedImplementation doesn't inherit from Root so it shouldn't surely?
The diagnostic is confusing; the real problem here is that it's too circular and it's going beyond what the compiler can handle.
It tries to resolve Generic, and finds it can't without assuming that SpecialisedImplementation is a subclass of Root (which isn't true, but it's desperate to find a way to make it work). And it tries to make Specialised work, but it can only do that if Generic already worked, but the only way to get Generic to work is to make it Root.
You want it to assume everything you say is true at the same time, but it's not that smart. It's trying to build it up piecemeal, one protocol at a time, and gets confused. Open a bugreport at bugs.swift.org.
(But this is also almost certainly wildly too complicated. In particular, I'd work hard to get rid of that Root class if you possibly can; mixing protocols and classes and generics all together is a recipe for lots of very confusing compiler problems.)
I'm going with this being a compiler bug and have opened a bug report. For anyone else experiencing a similar issue, I've managed to work around it by removing the Self requirement from the Generic extension:
class Root { }
protocol Generic {
associatedtype RootType: Root
var root: RootType { get }
}
extension Generic where Self: Root {
// ===================
// don't use Self here
// ===================
var root: Root {
return self
}
}
class GenericWrapper<T: Generic>: Root {
var generic: T
init(generic: T) {
self.generic = generic
}
}
protocol Specialised { }
extension Specialised where Self: Generic {
var root: GenericWrapper<Self> {
get {
return GenericWrapper(generic: self)
}
}
}
class SpecialisedImplementation: Generic, Specialised {
// no errors!
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With