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.
Instead of kicking off an AbstractGenericSignatureRequest recursively,
handle the rebuilding in a loop in {Abstract,Inferred}GenericSignatureRequest.
This also avoids an unnecessary call to verify() when rebuilding.
I'll clean this up, comment it and generalize it to work with protocol requirement
signatures soon. Landing this now to unblock the Linux corelibs-foundation build.
Fixes rdar://problem/89791117.
Complete support is behind a flag, because it can result in a non-convergent
rewrite system if the opaque result type has a recursive conformance of its
own (eg, `some View` for SwiftUI's View protocol).
Without the flag, it's good enough for simple examples; you just can't have
a requirement that mentions a nested type of a type parameter equated to
the concrete type.
Fixes rdar://problem/88135291, https://bugs.swift.org/browse/SR-15983.
Without this, we only considered a protocol refinement rule redundant if
it was derived by directly-stated protocol refinements. But this broke
when completion introduced a 'transitive' refinement [P].[R] => [P]
from two directly-stated refinements [P].[Q] => [P] and [Q].[R] => [Q].
Fixes rdar://problem/90402503.
Completion has a maximum rule limit since the Knuth-Bendix algorithm
is a semi-decision procedure that does not terminate on all inputs.
However, this means that generic signatures which import a large
number of complex protocols can hit the limit even if they are
convergent.
Since imported rules are essentially free, ignore them here, to
avoid having to increase the limit by hand.
Now the default limit is 4000 local rules per requirement machine;
it seems implausible that you would exceed this, but if anyone has
an example we can bump the limit again.
This fixes a regression from the rule sharing implementation; I forgot
to handle the imported rules in builder.ImportedRules here.
This makes the usage of RuleBuilder in conditional requirement
inference look like the other usages of RuleBuilder, except
that the results are passed to RewriteSystem::addRules() instead
of RewriteSystem::initialize().
All the pieces are now in place so that the RuleBuilder can assemble
a confluent rewrite system for downstream protocol dependencies,
instead of building rules from protocol requirement signatures.