When computing an overlap between a property-like rule (T.[p] => T for some
property symbol [p]) and another rule, try harder to ensure that the new
rule is a property-like rule.
In a conformance-valid rewrite system, all rules that are not LHS- or RHS-
simplified will eventually either be property-like or same-type rules, but
we need to maintain this invariant for that rules that become simplified
as well, to ensure that rewrite loops have a certain structure that is
important for the minimal conformances algorithm.
I don't quite understand why to be honest, but I'm close to figuring it
out.
Fixes rdar://problem/91232987.
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).