mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Consider this example:
protocol P1 {
associatedtype A : P2
}
protocol P2 {
associatedtype A
}
func foo<T : P2>(_: T) where T.A : P1, T.A.A == T {}
We cannot drop 'T : P2', even though it can be derived from
T.A.A == T and Self.A : P2 in protocol P1, because we actually
need the conformance T : P2 in order to recover the concrete
type for T.A.
This was handled via a hack which would ensure that the
conformance path (T.A : P1)(Self.A : P2) was not a candidate
derivation for T : P2, because T : P2 is one of the conformances
used to construct the subject type T.A in the conformance path.
This hack did not generalize to "cycles" of length greater than 1
however:
func foo<T : P2, U : P2>(_: T, _: U)
where T.A : P1, T.A.A == U, U.A : P1, U.A.A == T {}
We used to drop both T : P2 and U : P2, because each one had a
conformance path (U.A : P1)(Self.A : P2) and (T.A : P1)(Self.A : P2),
respectively; however, once we drop T : P2 and U : P2, these two
paths become invalid for the same reason that the concrete type
for T.A and U.A can no longer be recovered.
The correct fix is to recursively visit the subject type of each
base requirement when evaluating a conformance path, and not
consider any requirement whose subject type's parent type cannot
be recovered. This proceeds recursively.
In the worst case, this algorithm is exponential in the number of
conformance requirements, but it is not always exponential, and
a generic signature is not going to have a large number of
conformance requirements anyway (hopefully). Also, the old logic
in getMinimalConformanceSource() wasn't cheap either.
Perhaps some clever minimization can speed this up too, but I'm
going to focus on correctness first, before looking at performance
here.
Fixes rdar://problem/74890907.
22 lines
896 B
Swift
22 lines
896 B
Swift
// RUN: %target-typecheck-verify-swift
|
|
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
|
|
|
|
protocol P1 {
|
|
associatedtype A : P2
|
|
}
|
|
|
|
protocol P2 {
|
|
associatedtype A
|
|
}
|
|
|
|
// CHECK: Generic signature: <T, U where T : P2, T == U.A.A, U == T.A.A, T.A : P1, U.A : P1>
|
|
func testTU<T : P2, U : P2>(_: T, _: U) where T.A : P1, T.A.A == U, U.A : P1, U.A.A == T {}
|
|
// expected-warning@-1 {{redundant conformance constraint 'U' : 'P2'}}
|
|
// expected-note@-2 {{conformance constraint 'U' : 'P2' implied here}}
|
|
|
|
// CHECK: Generic signature: <T, U where T == U.A.A, U : P2, U == T.A.A, T.A : P1, U.A : P1>
|
|
func testU<T, U : P2>(_: T, _: U) where T.A : P1, T.A.A == U, U.A : P1, U.A.A == T {}
|
|
|
|
// CHECK: Generic signature: <T, U where T : P2, T == U.A.A, U == T.A.A, T.A : P1, U.A : P1>
|
|
func testT<T : P2, U>(_: T, _: U) where T.A : P1, T.A.A == U, U.A : P1, U.A.A == T {}
|