Is this additional type requirement needed?

Given these types:

protocol AProtocol {
    associatedtype B: BProtocol where B.A == Self
}

protocol BProtocol {
    associatedtype A: AProtocol
}

protocol CProtocol {
    associatedtype A: AProtocol
}

protocol DProtocol {
    associatedtype A: AProtocol
    
    func foo<C: CProtocol>(c: C) where C.A == A
}

the compiler complains with the error message:

Instance method requirement 'foo(c:)' cannot add constraint 'Self.A.B == Self.A.B.A.B' on 'Self'

which I think is not correct because the associated type B of AProtocol is constrained with where B.A == Self.
This should imply B.A.B == Self.B and therefore B.A.B.A == Self.B.A == Self.
Is this correct?


I currently use a "workaround" which adds an additional constraint to the associated type B of AProtocol where B.A.B == B:

protocol AProtocol {
    associatedtype B: BProtocol where B.A == Self, B.A.B == B
}

protocol BProtocol {
    associatedtype A: AProtocol
}

protocol CProtocol {
    associatedtype A: AProtocol
}

protocol DProtocol {
    associatedtype A: AProtocol
    
    func foo<C: CProtocol>(c: C) where C.A == A
}

With the addition constraint, this compiles just fine. I'm now curious if this addition requirement is really needed or should be inferred from the first constraint where B.A == Self.

Tested with Swift 5.5.2 (Xcode 13.2.1) and Swift 5.6 (Xcode 13.3 Beta 3)

Fails to compile with Swift 5.7 (Trunk Development (main) February 25, 2022). Reported as SR-15920 with an even more reduced example. Maybe related to the new generic signature minimization algorithm. cc: @Slava_Pestov)

1 Like

The problem here is that the GenericSignatureBuilder incorrectly introduces the requirement Self.A.B == Self.A.B.A.B, which trips the semantic check prohibiting protocol methods from adding new requirements on the Self type that the protocol's own where clause does not impose.

Your example type checks successfully with -Xfrontend -requirement-machine-inferred-signatures=on, so it will be fixed once that flag is on by default. You can try building your project with this flag enabled on a trunk snapshot and let me know if you encounter issues.

1 Like

Awesome, thanks! I wrongly assumed these flags were already turned on for nightlies.

My workaround also fails to compile with Swift 5.7:

protocol AProtocol {
    associatedtype B: BProtocol where B.A == Self, B.A.B == B
}

protocol BProtocol {
    associatedtype A: AProtocol
}

but with -requirement-machine-protocol-signatures=on it builds successfully. Worth filling another bug?

The only flag that’s turned on so far is -requirement-machine-protocol-signatures=verify, which runs both the GSB and Requirement Machine and compares the results. I’ll flip it to on By default soon.

At this point, probably not.

1 Like