Associated types can't be inferred from derived protocol

Is this a bug or intended behavior?

protocol P {
    associatedtype X
    func f() -> X
}

protocol Q: P {
    func g() -> X
}

extension Q {
    func f() -> X { return g() }
}

// ⚠️ Type 'A' does not conform to protocol 'P'
class A: Q {
    // 'P.X' is not inferred
    // typealias X = Int
    func g() -> Int { return 0 }
}

You need to define the type for X:

class A: Q {
  typealias X = Int
  func g() -> Int { return 0 }
}

We already defined the type in the signature of g: () -> Int. X should be inferred from g(), just like f() did.

class A: P {
    // Okay
    func f() -> Int { return 0 }
}

class B: Q {
    // Error!
    func g() -> Int { return 0 }
}
1 Like

Oh, I see.

@jrose @Slava_Pestov do you think X should be inferred here?

Dig in further and now it more like a bug:

Redeclare (shadow?) the associated type can fix the error somehow.

public protocol CFMutableCopying {
    associatedtype MutableCopyType
    func mutableCopy(allocator: CFAllocator) -> MutableCopyType
}

public protocol CFMutableCopyingWithCapacity: CFMutableCopying {
    // redeclare here
    associatedtype MutableCopyType
    func mutableCopy(allocator: CFAllocator, capacity: CFIndex) -> MutableCopyType
}

public extension CFMutableCopyingWithCapacity {
    @inlinable func mutableCopy(allocator: CFAllocator) -> MutableCopyType {
        return mutableCopy(allocator: allocator, capacity: 0)
    }
}

extension CFString: CFMutableCopyingWithCapacity {
    // Okay
    @inlinable public func mutableCopy(allocator: CFAllocator, capacity: CFIndex) -> CFMutableString {
        return CFStringCreateMutableCopy(allocator, capacity, self)
    }
}

Extend derived protocol with restriction can also fix the error.

protocol R {
    associatedtype X
    // not work if `x` is a function.
    var x: X { get }
}

protocol S: R {
    var y: X { get }
}


extension S /* add restriction here */ where X == Int {
    var x: X { y }
}

class C: S {
    // Okay
    let y = 0
}

See this thread:

1 Like

Thanks, I see, associated type inference is intentionally limited.

But this?

// Type 'CFBinaryHeap' does not conform to protocol 'CFMutableCopying'
extension CFBinaryHeap: CFMutableType, CFMutableCopyingWithCapacity {
    // ...
}
// Okay! Just adjusted the order.
extension CFBinaryHeap: CFMutableCopyingWithCapacity, CFMutableType {
    // ...
}

I understand it's about how associated type is inferred, but it really blows up my mind.

1 Like