computing a concrete same-type or superclass for conflict diagnostics.
Otherwise, diagnostics will show fresh type parameters when the concrete
type is generic.
initializing a RequirementMachine for a written protocol signature.
These generic parameters are used for re-sugaring when computing a
type from a term, so if the recorded 'Self' parameter is canonicalized,
it shows up in diagnostics as 'tau_0_0'.
A protocol typealias 'typealias T = X' introduces a same-type requirement
'Self.T == Self.X'. However the right hand side of the requirement was
wrapped in a sugared TypeAliasType.
This meant if the requirement surfaced in a redundancy diagnostic, it
would print as 'Self.T == Self.T'. It could also trigger a request cycle
via isInterestingTypealias() in DiagnosticEngine.cpp.
A requirement machine built from existing protocol requirement signatures only
exists to cache those rules and allow them to be inherited by other machines.
Recording loops is unnecessary in this case, since no minimization will be
performed.
Property map construction is still not incremental, and considers
all rules. Skipping subst-simplified rules here violates invariants
checked by the next commit.
For efficiency I want to keep replacement paths for redundant rules
unsubstituted, so that earlier replacement paths can reference
redundant rules that appear later in the RedundantRules array.
Right now we expand replacement paths so that their RewriteSteps
only mention non-redundant rules.
This patch refactors the computeRedundantRequirementDiagnostics()
method a bit:
The impliedRequirements set is now named nonExplicitNonRedundantRules,
and in addition to storing these rules themselves, the set also
stores any _redundant_ rules that reference these rules via their
replacement paths.
Since this is computing a transitive closure, we walk the
RedundantRules array in reverse. A replacement path can only
reference a redundant rule if that redundant rule appears later
in the array.
I don't have a reduced test case. It was possible for computing the requirement
signatures of a connected component to have finished, and yet for the
ProtocolDecl::hasComputedRequirementSignature() method to return false, if
we had evaluated a RequirementSignatureRequestRQM but not the top-level
RequirementSignatureRequest.
Instead, track whether we've computed the signatures for a component directly.
I don't have a reduced test case. It would arise with associated type inference,
which uses this predicate to break nasty cycles.
Also fix a weird latent bug. In lookupConcreteNestedType(), we would
push nullptr onto the concreteDecls vector if the opaque archetype
did not have a nested type with this name. However, this did not
turn out to be a problem, since in this code path we would only
have a single element in this vector, and the later call to
std::min_element() did not end up dereferencing the null pointer.
However this is very dodgy, so tweak the code to prevent this from
happening and add a test case (which already passed anyway).
Note that this changes the behavior of a test slightly when the
-disable-concrete-contraction flag is used. This is because we're
not using the Requirement Machine that minimized the signature
and not the Requirement Machine built from the minimized
signature; the former includes a concrete conformance rule.
The isConcreteType() query returns true on the former when
given the generic parameter τ_0_0.
Since -disable-concrete-contraction is only meant for debugging,
I'm just removing that line from the test.