Now that `InferredGenericSignatureRequest` creates
`StructuralRequirement`s from of the generic signature with valid source
locations, additional redundancy warnings are produced. Update tests
with the new warnings.
We infer requirements from types appearing in parameter and result types,
like this:
func foo<T>(_: Set<T>) // 'T : Hashable' inferred from 'Set<T>'
Normally we muffle the warning if the requirement is re-stated redundantly:
func foo<T>(_: Set<T>) where T : Hashable // no warning
However, in some cases we failed to do this if the requirement was inferred
from a type appearing in a 'where' clause, like this:
struct G<A, B> {}
extension G where B : Hashable, A == Set<B> {}
This is because in this case the redundancy was detected by
RewriteSystem::addRule() returning false.
The simplest fix here is to change InferredGenericSignatureRequest
to re-order requirements so that inferred requirements appear last.
This way, if any are redundant, we won't diagnose them since it is
the inferred requirement that is redundant and not the user-written
one.
Fixes rdar://problem/92092635.
A protocol conformance requirement together with a superclass requirement
can collapse down to a same-type requirement if the protocol itself has
a 'where' clause:
protocol P {
associatedtype T where T == Self
}
class C : P {}
extension P where T : C {}
(Self : P) and (Self.T : C) imply that (Self == C), because protocol P
says that Self.T == Self, and the witness of P.T in C is C, so when we
substitute that in we get Self == C.
Part of rdar://problem/80503090.
This rewrites the existing redundant requirements algorithm
to be simpler, and fix an incorrect behavior in the case where
we're building a protocol requirement signature.
Consider the following example:
protocol P {
associatedtype A : P
associatedtype B : P where A.B == B
}
The requirement B : P has two conformance paths here:
(B : P)
(A : P)(B : P)
The naive redundancy algorithm would conclude that (B : P) is
redundant because it can be derived as (A : P)(B : P). However,
if we drop (B : P), we lose the derived conformance path
as well, since it involves the same requirement (B : P).
The above example actually worked before this change, because we
handled this case in getMinimalConformanceSource() by dropping any
derived conformance paths that involve the requirement itself
appearing in the "middle" of the path.
However, this is insufficient because you can have a "cycle"
here with length more than 1. For example,
protocol P {
associatedtype A : P where A == B.C
associatedtype B : P where B == A.C
associatedtype C : P where C == A.B
}
The requirement A : P has two conformance paths here:
(A : P)
(B : P)(C : P)
Similarly, B : P has these two paths:
(B : P)
(A : P)(C : P)
And C : P has these two paths:
(C : P)
(A : P)(B : P)
Since each one of A : P, B : P and C : P has a derived conformance
path that does not involve itself, we would conclude that all three
were redundant. But this was wrong; while (B : P)(C : P) is a valid
derived path for A : P that allows us to drop A : P, once we commit to
dropping A : P, we can no longer use the other derived paths
(A : P)(C : P) for B : P, and (A : P)(B : P) for C : P, respectively,
because they involve A : P, which we dropped.
The problem is that we were losing information here. The explicit
requirement A : P can be derived as (B : P)(C : P), but we would
just say that it was implied by B : P alone.
For non-protocol generic signatures, just looking at the root is
still sufficient.
However, when building a requirement signature of a self-recursive
protocol, instead of looking at the root explicit requirement only,
we need to look at _all_ intermediate steps in the path that involve
the same protocol.
This is implemented in a new getBaseRequirements() method, which
generalizes the operation of getting the explicit requirement at
the root of a derived conformance path by returning a vector of
one or more explicit requirements that appear in the path.
Also the new algorithm computes redundancy online instead of building
a directed graph and then computing SCCs. This is possible by
recording newly-discovered redundant requirements immediately,
and then using the set of so-far-redundant requirements when
evaluating a path.
This commit introduces a small regression in an existing test case
involving a protocol with a 'derived via concrete' requirement.
Subsequent commits in this PR fix the regression and remove the
'derived via concrete' mechanism, since it is no longer necessary.
Fixes https://bugs.swift.org/browse/SR-14510 / rdar://problem/76883924.
We rebuild a signature after dropping redundant conformance requirements,
since conformance requirements change the canonical type and conformance
access path computation.
When doing this, instead of using the canonical requirements from the
signature, use the original as-written requirements.
This fixes some weirdness around concrete same-type requirements.
There's a philosophical benefit here too -- since we rebuild the
signature without ever having built the old signature, we never create
an invalid GenericSignature in the ASTContext.
Fixes rdar://problem/75690903.
We would invalidate the cache if the superclass changed, but
not the concrete type. Let's do the same with the concrete
type.
This fixes one small part of rdar://problem/75656022.