mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
RequirementMachine: Re-use requirement machines constructed by minimization for queries
Fixes rdar://problem/88135641.
This commit is contained in:
@@ -535,13 +535,16 @@ GenericSignature buildGenericSignature(
|
||||
|
||||
/// Summary of error conditions detected by the Requirement Machine.
|
||||
enum class GenericSignatureErrorFlags {
|
||||
/// The original requirements referenced a non-existent type parameter.
|
||||
HasUnresolvedType = (1<<0),
|
||||
|
||||
/// The original requirements were in conflict with each other, meaning
|
||||
/// The original requirements referenced a non-existent type parameter,
|
||||
/// or the original requirements were in conflict with each other, meaning
|
||||
/// there are no possible concrete substitutions which statisfy the
|
||||
/// generic signature.
|
||||
HasConflict = (1<<1),
|
||||
HasInvalidRequirements = (1<<0),
|
||||
|
||||
/// The generic signature had non-redundant concrete conformance
|
||||
/// requirements, which means the rewrite system used for minimization
|
||||
/// must be discarded and a new one built for queries.
|
||||
HasConcreteConformances = (1<<1),
|
||||
|
||||
/// The Knuth-Bendix completion procedure failed to construct a confluent
|
||||
/// rewrite system.
|
||||
|
||||
@@ -1067,7 +1067,9 @@ void swift::validateGenericSignature(ASTContext &context,
|
||||
GenericSignatureWithError());
|
||||
|
||||
// If there were any errors, the signature was invalid.
|
||||
if (newSigWithError.getInt()) {
|
||||
auto errorFlags = newSigWithError.getInt();
|
||||
if (errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements) ||
|
||||
errorFlags.contains(GenericSignatureErrorFlags::CompletionFailed)) {
|
||||
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_valid,
|
||||
sig->getAsString());
|
||||
}
|
||||
|
||||
@@ -8275,7 +8275,7 @@ AbstractGenericSignatureRequest::evaluate(
|
||||
if (!rqmResult.getPointer() && !gsbResult.getPointer())
|
||||
return rqmResult;
|
||||
|
||||
if (!rqmResult.getInt().contains(GenericSignatureErrorFlags::HasConflict) &&
|
||||
if (!rqmResult.getInt().contains(GenericSignatureErrorFlags::HasInvalidRequirements) &&
|
||||
!rqmResult.getInt().contains(GenericSignatureErrorFlags::CompletionFailed) &&
|
||||
!rqmResult.getPointer()->isEqual(gsbResult.getPointer())) {
|
||||
PrintOptions opts;
|
||||
@@ -8427,7 +8427,7 @@ AbstractGenericSignatureRequestGSB::evaluate(
|
||||
|
||||
GenericSignatureErrors errorFlags;
|
||||
if (builder.hadAnyError())
|
||||
errorFlags |= GenericSignatureErrorFlags::HasUnresolvedType;
|
||||
errorFlags |= GenericSignatureErrorFlags::HasInvalidRequirements;
|
||||
auto result = std::move(builder).computeGenericSignature(
|
||||
/*allowConcreteGenericParams=*/true);
|
||||
return GenericSignatureWithError(result, errorFlags);
|
||||
@@ -8489,7 +8489,7 @@ InferredGenericSignatureRequest::evaluate(
|
||||
if (!rqmResult.getPointer() && !gsbResult.getPointer())
|
||||
return rqmResult;
|
||||
|
||||
if (!rqmResult.getInt().contains(GenericSignatureErrorFlags::HasConflict) &&
|
||||
if (!rqmResult.getInt().contains(GenericSignatureErrorFlags::HasInvalidRequirements) &&
|
||||
!rqmResult.getInt().contains(GenericSignatureErrorFlags::CompletionFailed) &&
|
||||
!rqmResult.getPointer()->isEqual(gsbResult.getPointer())) {
|
||||
PrintOptions opts;
|
||||
@@ -8635,7 +8635,7 @@ InferredGenericSignatureRequestGSB::evaluate(
|
||||
|
||||
GenericSignatureErrors errorFlags;
|
||||
if (builder.hadAnyError())
|
||||
errorFlags |= GenericSignatureErrorFlags::HasUnresolvedType;
|
||||
errorFlags |= GenericSignatureErrorFlags::HasInvalidRequirements;
|
||||
auto result = std::move(builder).computeGenericSignature(
|
||||
allowConcreteGenericParams);
|
||||
return GenericSignatureWithError(result, errorFlags);
|
||||
@@ -8705,7 +8705,7 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,
|
||||
auto rqmResult = buildViaRQM();
|
||||
auto gsbResult = buildViaGSB();
|
||||
|
||||
if (!rqmResult.getErrors().contains(GenericSignatureErrorFlags::HasConflict) &&
|
||||
if (!rqmResult.getErrors().contains(GenericSignatureErrorFlags::HasInvalidRequirements) &&
|
||||
!rqmResult.getErrors().contains(GenericSignatureErrorFlags::CompletionFailed) &&
|
||||
!compare(rqmResult.getRequirements(),
|
||||
gsbResult.getRequirements())) {
|
||||
|
||||
@@ -471,6 +471,7 @@ void RewriteSystem::minimizeRewriteSystem() {
|
||||
|
||||
assert(Complete);
|
||||
assert(!Minimized);
|
||||
assert(!Frozen);
|
||||
Minimized = 1;
|
||||
|
||||
propagateExplicitBits();
|
||||
@@ -626,7 +627,7 @@ GenericSignatureErrors RewriteSystem::getErrors() const {
|
||||
|
||||
GenericSignatureErrors result;
|
||||
|
||||
for (const auto &rule : Rules) {
|
||||
for (const auto &rule : getLocalRules()) {
|
||||
if (rule.isPermanent())
|
||||
continue;
|
||||
|
||||
@@ -636,10 +637,15 @@ GenericSignatureErrors RewriteSystem::getErrors() const {
|
||||
if (!rule.isRedundant() &&
|
||||
!rule.isProtocolTypeAliasRule() &&
|
||||
rule.containsUnresolvedSymbols())
|
||||
result |= GenericSignatureErrorFlags::HasUnresolvedType;
|
||||
result |= GenericSignatureErrorFlags::HasInvalidRequirements;
|
||||
|
||||
if (rule.isConflicting())
|
||||
result |= GenericSignatureErrorFlags::HasConflict;
|
||||
result |= GenericSignatureErrorFlags::HasInvalidRequirements;
|
||||
|
||||
if (!rule.isRedundant())
|
||||
if (auto property = rule.isPropertyRule())
|
||||
if (property->getKind() == Symbol::Kind::ConcreteConformance)
|
||||
result |= GenericSignatureErrorFlags::HasConcreteConformances;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -287,6 +287,7 @@ RewriteSystem::computeConfluentCompletion(unsigned maxRuleCount,
|
||||
unsigned maxRuleLength) {
|
||||
assert(Initialized);
|
||||
assert(!Minimized);
|
||||
assert(!Frozen);
|
||||
|
||||
// Complete might already be set, if we're re-running completion after
|
||||
// adding new rules in the property map's concrete type unification procedure.
|
||||
|
||||
@@ -332,6 +332,10 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
|
||||
return std::make_pair(CompletionResult::Success, 0);
|
||||
}
|
||||
|
||||
void RequirementMachine::freeze() {
|
||||
System.freeze();
|
||||
}
|
||||
|
||||
std::string RequirementMachine::getRuleAsStringForDiagnostics(
|
||||
unsigned ruleID) const {
|
||||
const auto &rule = System.getRule(ruleID);
|
||||
|
||||
@@ -113,6 +113,8 @@ class RequirementMachine final {
|
||||
std::pair<CompletionResult, unsigned>
|
||||
computeCompletion(RewriteSystem::ValidityPolicy policy);
|
||||
|
||||
void freeze();
|
||||
|
||||
MutableTerm getLongestValidPrefix(const MutableTerm &term) const;
|
||||
|
||||
void buildRequirementsFromRules(
|
||||
@@ -159,8 +161,8 @@ public:
|
||||
llvm::DenseMap<const ProtocolDecl *, RequirementSignature>
|
||||
computeMinimalProtocolRequirements();
|
||||
|
||||
std::vector<Requirement>
|
||||
computeMinimalGenericSignatureRequirements(bool reconstituteSugar);
|
||||
GenericSignature
|
||||
computeMinimalGenericSignature(bool reconstituteSugar);
|
||||
|
||||
ArrayRef<Rule> getLocalRules() const;
|
||||
|
||||
|
||||
@@ -288,7 +288,8 @@ RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
|
||||
|
||||
auto minimalRequirements = machine->computeMinimalProtocolRequirements();
|
||||
|
||||
if (!machine->getErrors()) {
|
||||
if (!machine->getErrors().contains(
|
||||
GenericSignatureErrorFlags::HasInvalidRequirements)) {
|
||||
if (shouldSplitConcreteEquivalenceClasses(minimalRequirements, machine.get())) {
|
||||
++attempt;
|
||||
splitConcreteEquivalenceClasses(ctx, minimalRequirements,
|
||||
@@ -345,15 +346,20 @@ RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
|
||||
/*allowConcreteGenericParams=*/false);
|
||||
}
|
||||
|
||||
if (!machine->getErrors())
|
||||
rewriteCtx.installRequirementMachine(proto, std::move(machine));
|
||||
|
||||
// Return the result for the specific protocol this request was kicked off on.
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the top-level generic signature requirements for this rewrite system.
|
||||
std::vector<Requirement>
|
||||
RequirementMachine::computeMinimalGenericSignatureRequirements(
|
||||
GenericSignature
|
||||
RequirementMachine::computeMinimalGenericSignature(
|
||||
bool reconstituteSugar) {
|
||||
assert(!Sig &&
|
||||
"Already computed minimal generic signature");
|
||||
assert(System.getProtocols().empty() &&
|
||||
"Not a top-level generic signature rewrite system");
|
||||
assert(!Params.empty() &&
|
||||
@@ -375,7 +381,14 @@ RequirementMachine::computeMinimalGenericSignatureRequirements(
|
||||
reconstituteSugar, reqs, aliases);
|
||||
assert(aliases.empty());
|
||||
|
||||
return reqs;
|
||||
auto sig = GenericSignature::get(getGenericParams(), reqs);
|
||||
|
||||
// Remember the signature for generic signature queries. In particular,
|
||||
// getConformanceAccessPath() needs the current requirement machine's
|
||||
// generic signature.
|
||||
Sig = sig.getCanonicalSignature();
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/// Check whether the inputs to the \c AbstractGenericSignatureRequest are
|
||||
@@ -549,14 +562,11 @@ AbstractGenericSignatureRequestRQM::evaluate(
|
||||
|
||||
// We pass reconstituteSugar=false to ensure that if the original
|
||||
// requirements were canonical, the final signature remains canonical.
|
||||
auto minimalRequirements =
|
||||
machine->computeMinimalGenericSignatureRequirements(
|
||||
auto result = machine->computeMinimalGenericSignature(
|
||||
/*reconstituteSugar=*/false);
|
||||
|
||||
auto result = GenericSignature::get(genericParams, minimalRequirements);
|
||||
auto errorFlags = machine->getErrors();
|
||||
|
||||
if (!errorFlags) {
|
||||
if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
|
||||
if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(),
|
||||
/*proto=*/nullptr,
|
||||
machine.get())) {
|
||||
@@ -567,7 +577,19 @@ AbstractGenericSignatureRequestRQM::evaluate(
|
||||
requirements, attempt);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorFlags) {
|
||||
// If this signature was minimized without errors or non-redundant
|
||||
// concrete conformances, we can re-use the requirement machine for
|
||||
// subsequent queries, instead of building a new requirement machine
|
||||
// from the minimized signature. Do this before verify(), which
|
||||
// performs queries.
|
||||
rewriteCtx.installRequirementMachine(result.getCanonicalSignature(),
|
||||
std::move(machine));
|
||||
}
|
||||
|
||||
if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
|
||||
// Check invariants.
|
||||
result.verify();
|
||||
}
|
||||
@@ -731,11 +753,8 @@ InferredGenericSignatureRequestRQM::evaluate(
|
||||
result, GenericSignatureErrorFlags::CompletionFailed);
|
||||
}
|
||||
|
||||
auto minimalRequirements =
|
||||
machine->computeMinimalGenericSignatureRequirements(
|
||||
auto result = machine->computeMinimalGenericSignature(
|
||||
/*reconstituteSugar=*/true);
|
||||
|
||||
auto result = GenericSignature::get(genericParams, minimalRequirements);
|
||||
auto errorFlags = machine->getErrors();
|
||||
|
||||
if (attempt == 0 &&
|
||||
@@ -747,7 +766,7 @@ InferredGenericSignatureRequestRQM::evaluate(
|
||||
|
||||
// FIXME: Handle allowConcreteGenericParams
|
||||
|
||||
if (!errorFlags) {
|
||||
if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
|
||||
// Check if we need to rebuild the signature.
|
||||
if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(),
|
||||
/*proto=*/nullptr,
|
||||
@@ -759,7 +778,19 @@ InferredGenericSignatureRequestRQM::evaluate(
|
||||
requirements, attempt);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorFlags) {
|
||||
// If this signature was minimized without errors or non-redundant
|
||||
// concrete conformances, we can re-use the requirement machine for
|
||||
// subsequent queries, instead of building a new requirement machine
|
||||
// from the minimized signature. Do this before verify(), which
|
||||
// performs queries.
|
||||
rewriteCtx.installRequirementMachine(result.getCanonicalSignature(),
|
||||
std::move(machine));
|
||||
}
|
||||
|
||||
if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
|
||||
// Check invariants.
|
||||
result.verify();
|
||||
}
|
||||
|
||||
@@ -195,6 +195,21 @@ bool RewriteContext::isRecursivelyConstructingRequirementMachine(
|
||||
return !found->second->isComplete();
|
||||
}
|
||||
|
||||
/// Given a requirement machine that built a minimized signature, attempt to
|
||||
/// re-use it for subsequent queries against the minimized signature, instead
|
||||
/// of building a new one later.
|
||||
void RewriteContext::installRequirementMachine(
|
||||
CanGenericSignature sig,
|
||||
std::unique_ptr<RequirementMachine> machine) {
|
||||
auto *machinePtr = machine.release();
|
||||
|
||||
machinePtr->freeze();
|
||||
|
||||
auto inserted = Machines.insert(std::make_pair(sig, machinePtr)).second;
|
||||
if (!inserted)
|
||||
delete machinePtr;
|
||||
}
|
||||
|
||||
/// Implement Tarjan's algorithm to compute strongly-connected components in
|
||||
/// the protocol dependency graph.
|
||||
void RewriteContext::getProtocolComponentRec(
|
||||
@@ -370,6 +385,11 @@ void RewriteContext::finishComputingRequirementSignatures(
|
||||
/// for being built with the same component.
|
||||
RequirementMachine *RewriteContext::getRequirementMachine(
|
||||
const ProtocolDecl *proto) {
|
||||
// First, get the requirement signature. If this protocol was written in
|
||||
// source, we'll minimize it and install the machine below, saving us the
|
||||
// effort of recomputing it.
|
||||
(void) proto->getRequirementSignature();
|
||||
|
||||
auto &component = getProtocolComponentImpl(proto);
|
||||
|
||||
if (component.Machine) {
|
||||
@@ -435,6 +455,24 @@ bool RewriteContext::isRecursivelyConstructingRequirementMachine(
|
||||
!component->second.ComputedRequirementSignatures);
|
||||
}
|
||||
|
||||
/// Given a reuirement machine that built the requirement signatures for a
|
||||
/// protocol connected component, attempt to re-use it for subsequent
|
||||
/// queries against the connected component, instead of building a new one
|
||||
/// later.
|
||||
void RewriteContext::installRequirementMachine(
|
||||
const ProtocolDecl *proto,
|
||||
std::unique_ptr<RequirementMachine> machine) {
|
||||
auto *machinePtr = machine.release();
|
||||
|
||||
machinePtr->freeze();
|
||||
|
||||
auto &component = getProtocolComponentImpl(proto);
|
||||
if (component.Machine == nullptr)
|
||||
component.Machine = machinePtr;
|
||||
else
|
||||
delete machinePtr;
|
||||
}
|
||||
|
||||
/// We print stats in the destructor, which should get executed at the end of
|
||||
/// a compilation job.
|
||||
RewriteContext::~RewriteContext() {
|
||||
|
||||
@@ -206,6 +206,9 @@ public:
|
||||
RequirementMachine *getRequirementMachine(CanGenericSignature sig);
|
||||
bool isRecursivelyConstructingRequirementMachine(CanGenericSignature sig);
|
||||
|
||||
void installRequirementMachine(CanGenericSignature sig,
|
||||
std::unique_ptr<RequirementMachine> machine);
|
||||
|
||||
ArrayRef<const ProtocolDecl *>
|
||||
startComputingRequirementSignatures(const ProtocolDecl *proto);
|
||||
|
||||
@@ -214,6 +217,9 @@ public:
|
||||
RequirementMachine *getRequirementMachine(const ProtocolDecl *proto);
|
||||
bool isRecursivelyConstructingRequirementMachine(const ProtocolDecl *proto);
|
||||
|
||||
void installRequirementMachine(const ProtocolDecl *proto,
|
||||
std::unique_ptr<RequirementMachine> machine);
|
||||
|
||||
~RewriteContext();
|
||||
};
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ RewriteSystem::RewriteSystem(RewriteContext &ctx)
|
||||
Initialized = 0;
|
||||
Complete = 0;
|
||||
Minimized = 0;
|
||||
Frozen = 0;
|
||||
RecordLoops = 0;
|
||||
LongestInitialRule = 0;
|
||||
}
|
||||
@@ -170,9 +171,7 @@ bool RewriteSystem::simplify(MutableTerm &term, RewritePath *path) const {
|
||||
/// \p lhs to \p rhs.
|
||||
bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
|
||||
const RewritePath *path) {
|
||||
// FIXME:
|
||||
// assert(!Complete || path != nullptr &&
|
||||
// "Rules added by completion must have a path");
|
||||
assert(!Frozen);
|
||||
|
||||
assert(!lhs.empty());
|
||||
assert(!rhs.empty());
|
||||
@@ -494,6 +493,8 @@ bool RewriteSystem::isInMinimizationDomain(const ProtocolDecl *proto) const {
|
||||
|
||||
void RewriteSystem::recordRewriteLoop(MutableTerm basepoint,
|
||||
RewritePath path) {
|
||||
assert(!Frozen);
|
||||
|
||||
RewriteLoop loop(basepoint, path);
|
||||
loop.verify(*this);
|
||||
|
||||
@@ -727,6 +728,30 @@ void RewriteSystem::computeRedundantRequirementDiagnostics(
|
||||
}
|
||||
}
|
||||
|
||||
/// Free up memory by purging unused data structures after completion
|
||||
/// (for a rewrite system built from a generic signature) or minimization
|
||||
/// (for a rewrite system built from user-written requirements).
|
||||
void RewriteSystem::freeze() {
|
||||
assert(Complete);
|
||||
assert(!Frozen);
|
||||
|
||||
for (unsigned ruleID = FirstLocalRule, e = Rules.size();
|
||||
ruleID < e; ++ruleID) {
|
||||
getRule(ruleID).freeze();
|
||||
}
|
||||
|
||||
WrittenRequirements.clear();
|
||||
CheckedOverlaps.clear();
|
||||
RelationMap.clear();
|
||||
Relations.clear();
|
||||
DifferenceMap.clear();
|
||||
Differences.clear();
|
||||
CheckedDifferences.clear();
|
||||
Loops.clear();
|
||||
RedundantRules.clear();
|
||||
ConflictingRules.clear();
|
||||
}
|
||||
|
||||
void RewriteSystem::dump(llvm::raw_ostream &out) const {
|
||||
out << "Rewrite system: {\n";
|
||||
for (const auto &rule : Rules) {
|
||||
|
||||
@@ -102,6 +102,10 @@ class RewriteSystem final {
|
||||
/// Whether we've minimized the rewrite system.
|
||||
unsigned Minimized : 1;
|
||||
|
||||
/// Whether the rewrite system is finalized, immutable, and ready for
|
||||
/// generic signature queries.
|
||||
unsigned Frozen : 1;
|
||||
|
||||
/// If set, the completion procedure records rewrite loops describing the
|
||||
/// identities among rewrite rules discovered while resolving critical pairs.
|
||||
unsigned RecordLoops : 1;
|
||||
@@ -403,6 +407,8 @@ private:
|
||||
const llvm::DenseSet<unsigned> &redundantConformances) const;
|
||||
|
||||
public:
|
||||
void freeze();
|
||||
|
||||
void dump(llvm::raw_ostream &out) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -77,6 +77,9 @@ class Rule final {
|
||||
/// dropped from the minimal set of requirements.
|
||||
unsigned Conflicting : 1;
|
||||
|
||||
/// Whether this rule is now finalized and immutable.
|
||||
unsigned Frozen : 1;
|
||||
|
||||
public:
|
||||
Rule(Term lhs, Term rhs)
|
||||
: LHS(lhs), RHS(rhs) {
|
||||
@@ -87,6 +90,7 @@ public:
|
||||
SubstitutionSimplified = false;
|
||||
Redundant = false;
|
||||
Conflicting = false;
|
||||
Frozen = false;
|
||||
}
|
||||
|
||||
const Term &getLHS() const { return LHS; }
|
||||
@@ -97,6 +101,7 @@ public:
|
||||
}
|
||||
|
||||
void setRequirementID(Optional<unsigned> requirementID) {
|
||||
assert(!Frozen);
|
||||
this->requirementID = requirementID;
|
||||
}
|
||||
|
||||
@@ -141,6 +146,10 @@ public:
|
||||
return Conflicting;
|
||||
}
|
||||
|
||||
bool isFrozen() const {
|
||||
return Frozen;
|
||||
}
|
||||
|
||||
bool containsUnresolvedSymbols() const {
|
||||
return (LHS.containsUnresolvedSymbols() ||
|
||||
RHS.containsUnresolvedSymbols());
|
||||
@@ -151,44 +160,57 @@ public:
|
||||
bool isDerivedFromConcreteProtocolTypeAliasRule() const;
|
||||
|
||||
void markLHSSimplified() {
|
||||
assert(!Frozen);
|
||||
assert(!LHSSimplified);
|
||||
LHSSimplified = true;
|
||||
}
|
||||
|
||||
void markRHSSimplified() {
|
||||
assert(!Frozen);
|
||||
assert(!RHSSimplified);
|
||||
RHSSimplified = true;
|
||||
}
|
||||
|
||||
void markSubstitutionSimplified() {
|
||||
assert(!Frozen);
|
||||
assert(!SubstitutionSimplified);
|
||||
SubstitutionSimplified = true;
|
||||
}
|
||||
|
||||
void markPermanent() {
|
||||
assert(!Frozen);
|
||||
assert(!Explicit && !Permanent &&
|
||||
"Permanent and explicit are mutually exclusive");
|
||||
Permanent = true;
|
||||
}
|
||||
|
||||
void markExplicit() {
|
||||
assert(!Frozen);
|
||||
assert(!Explicit && !Permanent &&
|
||||
"Permanent and explicit are mutually exclusive");
|
||||
Explicit = true;
|
||||
}
|
||||
|
||||
void markRedundant() {
|
||||
assert(!Frozen);
|
||||
assert(!Redundant);
|
||||
Redundant = true;
|
||||
}
|
||||
|
||||
void markConflicting() {
|
||||
assert(!Frozen);
|
||||
// It's okay to mark a rule as conflicting multiple times, but it must not
|
||||
// be a permanent rule.
|
||||
assert(!Permanent && "Permanent rule should not conflict with anything");
|
||||
Conflicting = true;
|
||||
}
|
||||
|
||||
void freeze() {
|
||||
Redundant = false;
|
||||
requirementID = None;
|
||||
Frozen = true;
|
||||
}
|
||||
|
||||
unsigned getDepth() const;
|
||||
|
||||
unsigned getNesting() const;
|
||||
|
||||
@@ -259,8 +259,15 @@ void RewriteSystem::processTypeDifference(const TypeDifference &difference,
|
||||
// the same rewrite loop in concretelySimplifyLeftHandSideSubstitutions().
|
||||
auto &lhsRule = getRule(lhsRuleID);
|
||||
if (lhsRule.getRHS() == difference.BaseTerm &&
|
||||
!lhsRule.isSubstitutionSimplified())
|
||||
!lhsRule.isSubstitutionSimplified()) {
|
||||
if (lhsRule.isFrozen()) {
|
||||
llvm::errs() << "Frozen rule should already be subst-simplified: "
|
||||
<< lhsRule << "\n\n";
|
||||
dump(llvm::errs());
|
||||
abort();
|
||||
}
|
||||
lhsRule.markSubstitutionSimplified();
|
||||
}
|
||||
}
|
||||
|
||||
/// Simplify terms appearing in the substitutions of the last symbol of \p term,
|
||||
|
||||
@@ -11,7 +11,7 @@ func foo<T : Generic<U>, U>(_: T, _: U) {
|
||||
_ = U.self
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0, τ_0_1 where τ_0_0 : Generic<τ_0_1>>
|
||||
// CHECK: Requirement machine for fresh signature < T U >
|
||||
// CHECK-NEXT: Rewrite system: {
|
||||
// CHECK-NEXT: - τ_0_0.[superclass: Generic<τ_0_1>] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[layout: AnyObject] => τ_0_0
|
||||
|
||||
@@ -21,19 +21,19 @@ public func test<T : P>(_ t: T) where T == T.A {
|
||||
//
|
||||
// The rewrite system handles this correctly though:
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0, τ_0_1 where τ_0_0 == τ_0_0.A, τ_0_1 : P, τ_0_0.A == τ_0_1.A>
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T U >
|
||||
// CHECK-NEXT: Rewrite system: {
|
||||
// CHECK-NEXT: - [P].[P] => [P] [permanent]
|
||||
// CHECK-NEXT: - [P].A => [P:A] [permanent]
|
||||
// CHECK-NEXT: - [P:A].[P] => [P:A]
|
||||
// CHECK-NEXT: - [P].[P:A] => [P:A]
|
||||
// CHECK-NEXT: - [P:A].A => [P:A].[P:A]
|
||||
// CHECK-NEXT: - τ_0_0.[P:A] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.A => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_1.[P] => τ_0_1
|
||||
// CHECK-NEXT: - τ_0_1.A => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_1.[P:A] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[P] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.A => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_1.A => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[P:A] => τ_0_0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK: Property map: {
|
||||
// CHECK-NEXT: [P] => { conforms_to: [P] }
|
||||
|
||||
@@ -26,11 +26,11 @@ protocol PBad {
|
||||
// FIXME: Terrible diagnostics.
|
||||
|
||||
protocol PWorse {
|
||||
// expected-error@-1 4{{circular reference}}
|
||||
// expected-note@-2 6{{through reference here}}
|
||||
// expected-error@-1 5{{circular reference}}
|
||||
// expected-note@-2 9{{through reference here}}
|
||||
typealias A = C
|
||||
|
||||
associatedtype T : Self.A
|
||||
// expected-note@-1 4{{while resolving type 'Self.A'}}
|
||||
// expected-note@-2 4{{through reference here}}
|
||||
// expected-note@-1 5{{while resolving type 'Self.A'}}
|
||||
// expected-note@-2 5{{through reference here}}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ protocol P2a {
|
||||
|
||||
struct MergeTest<G : P1a & P2a> {}
|
||||
|
||||
// CHECK-LABEL: Adding generic signature <τ_0_0 where τ_0_0 : P1a, τ_0_0 : P2a> {
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < G >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - τ_0_0.[P2a:T] => τ_0_0.[P1a:T]
|
||||
// CHECK: - τ_0_0.[P1a:T].[P2] => τ_0_0.[P1a:T]
|
||||
@@ -30,5 +30,3 @@ struct MergeTest<G : P1a & P2a> {}
|
||||
// CHECK: τ_0_0 => { conforms_to: [P1a P2a] }
|
||||
// CHECK: τ_0_0.[P1a:T] => { conforms_to: [P1 P2] }
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ struct MergeTest<G : P1 & P2> {
|
||||
func foo2(x: G.Z1) -> G.Z2 { return x }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Adding generic signature <τ_0_0 where τ_0_0 : P1, τ_0_0 : P2> {
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < G >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - τ_0_0.[P2:Y2] => τ_0_0.[P1:Y1]
|
||||
// CHECK: - τ_0_0.[P2:Z2] => τ_0_0.[P1:Z1]
|
||||
|
||||
@@ -27,10 +27,9 @@ struct MergeTest<G : P1a & P2a> {
|
||||
func foo2(x: G.T.Z1) -> G.T.Z2 { return x }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Adding generic signature <τ_0_0 where τ_0_0 : P1a, τ_0_0 : P2a> {
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < G >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - τ_0_0.[P2a:T] => τ_0_0.[P1a:T]
|
||||
// CHECK: - τ_0_0.[P1a:T].[P2:Y2] => τ_0_0.[P1a:T].[P1:Y1]
|
||||
// CHECK: - τ_0_0.[P1a:T].[P2:Z2] => τ_0_0.[P1a:T].[P1:Z1]
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
@@ -17,10 +17,9 @@ struct G<T : P1 & P2> {}
|
||||
// Since G.T.T == G.T.T.T == G.T.T.T.T = ... = Int, we tie off the
|
||||
// recursion by introducing a same-type requirement G.T.T => G.T.
|
||||
|
||||
// CHECK-LABEL: Adding generic signature <τ_0_0 where τ_0_0 : P1, τ_0_0 : P2> {
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - [P1:T].T => [P1:T].[P1:T]
|
||||
// CHECK: - τ_0_0.[P1:T].[concrete: Int] => τ_0_0.[P1:T]
|
||||
// CHECK: - τ_0_0.[P1:T].[P1:T] => τ_0_0.[P1:T]
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
@@ -22,10 +22,9 @@ struct G<T : P1 & P2> {}
|
||||
// Since G.T.T == G.T.T.T == G.T.T.T.T = ... = X<T.U>, we tie off the
|
||||
// recursion by introducing a same-type requirement G.T.T => G.T.
|
||||
|
||||
// CHECK-LABEL: Adding generic signature <τ_0_0 where τ_0_0 : P1, τ_0_0 : P2> {
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - [P1:T].T => [P1:T].[P1:T]
|
||||
// CHECK: - τ_0_0.[P1:T].[concrete: X<τ_0_0.[P2:U]>] => τ_0_0.[P1:T]
|
||||
// CHECK: - τ_0_0.[P1:T].[P1:T] => τ_0_0.[P1:T]
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
@@ -26,7 +26,7 @@ struct G<T : P2a & P3a> {}
|
||||
// X.T has a DependentMemberType in it; make sure that we build the
|
||||
// correct substitution schema.
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0 where τ_0_0 : P2a, τ_0_0 : P3a>
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - τ_0_0.[P2a:T].[concrete: X<τ_0_0.[P3a:U]>] => τ_0_0.[P2a:T]
|
||||
// CHECK: - τ_0_0.[P2a:T].[P2:T].[concrete: X<τ_0_0.[P3a:U].[P1:T]>] => τ_0_0.[P2a:T].[P2:T]
|
||||
@@ -35,4 +35,3 @@ struct G<T : P2a & P3a> {}
|
||||
// CHECK: τ_0_0.[P2a:T] => { conforms_to: [P2] concrete_type: [concrete: X<τ_0_0.[P3a:U]>] }
|
||||
// CHECK: τ_0_0.[P2a:T].[P2:T] => { concrete_type: [concrete: X<τ_0_0.[P3a:U].[P1:T]>] }
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
@@ -40,7 +40,7 @@ struct G<T : P1 & P2> {}
|
||||
// T.B.A => T.B
|
||||
// ...
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0 where τ_0_0 : P1, τ_0_0 : P2>
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T >
|
||||
// CHECK-LABEL: Rewrite system: {
|
||||
// CHECK: - τ_0_0.[P1:A].[concrete: S1 : P1] => τ_0_0.[P1:A]
|
||||
// CHECK: - τ_0_0.[P1:A].[P1:A] => τ_0_0.[P1:A]
|
||||
@@ -61,4 +61,3 @@ struct G<T : P1 & P2> {}
|
||||
// CHECK: τ_0_0.[P1:A].[P1:B] => { conforms_to: [P1] concrete_type: [concrete: S2] }
|
||||
// CHECK: τ_0_0.[P1:B].[P1:B] => { conforms_to: [P1] concrete_type: [concrete: S1] }
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
@@ -13,13 +13,13 @@ extension P where Self : Derived {
|
||||
func passesDerived() { derivedMethod() }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0 where τ_0_0 : Derived, τ_0_0 : P>
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < Self >
|
||||
// CHECK-NEXT: Rewrite system: {
|
||||
// CHECK-NEXT: - [P].[P] => [P] [permanent]
|
||||
// CHECK-NEXT: - [P].[superclass: Base] => [P]
|
||||
// CHECK-NEXT: - [P].[layout: _NativeClass] => [P]
|
||||
// CHECK-NEXT: - τ_0_0.[superclass: Derived] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[P] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[superclass: Derived] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[superclass: Base] => τ_0_0
|
||||
// CHECK-NEXT: - τ_0_0.[layout: _NativeClass] => τ_0_0
|
||||
// CHECK-NEXT: }
|
||||
|
||||
@@ -38,10 +38,10 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
|
||||
// CHECK-RULE-NEXT: Rewrite system: {
|
||||
// CHECK-RULE: - τ_0_0.[P2:X] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<τ_0_0.[P2:A2], String, τ_0_0.[P2:B2]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<Int, String, τ_0_0.[P1:B1]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P1:A1].[concrete: String] => τ_0_0.[P1:A1]
|
||||
// CHECK-RULE: - τ_0_0.[P2:A2].[concrete: Int] => τ_0_0.[P2:A2]
|
||||
// CHECK-RULE: - τ_0_0.[P2:B2] => τ_0_0.[P1:B1]
|
||||
// CHECK-RULE: - τ_0_0.[P2:A2].[concrete: Int] => τ_0_0.[P2:A2]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<Int, String, τ_0_0.[P1:B1]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.B2 => τ_0_0.[P1:B1]
|
||||
// CHECK-RULE: }
|
||||
// CHECK-RULE: Property map: {
|
||||
|
||||
@@ -42,10 +42,10 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
|
||||
// CHECK-RULE: - [P2:X].[layout: _NativeClass] => [P2:X]
|
||||
// CHECK-RULE: - τ_0_0.[P2:X] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<Int, τ_0_0.[P1:A1], τ_0_0.[P1:B1]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<Int, String, τ_0_0.[P1:B1]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.[P2:A2].[concrete: Int] => τ_0_0.[P2:A2]
|
||||
// CHECK-RULE: - τ_0_0.[P2:B2] => τ_0_0.[P1:B1]
|
||||
// CHECK-RULE: - τ_0_0.[P1:A1].[concrete: String] => τ_0_0.[P1:A1]
|
||||
// CHECK-RULE: - τ_0_0.[P2:B2] => τ_0_0.[P1:B1]
|
||||
// CHECK-RULE: - τ_0_0.[P1:X].[superclass: Generic<Int, String, τ_0_0.[P1:B1]>] => τ_0_0.[P1:X]
|
||||
// CHECK-RULE: - τ_0_0.B2 => τ_0_0.[P1:B1]
|
||||
// CHECK-RULE: }
|
||||
// CHECK-RULE: Property map: {
|
||||
|
||||
@@ -33,7 +33,7 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
|
||||
takesDerived(T.X.self, T.A2.self)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Requirement machine for <τ_0_0 where τ_0_0 : P1, τ_0_0 : P2>
|
||||
// CHECK-LABEL: Requirement machine for fresh signature < T >
|
||||
// CHECK-NEXT: Rewrite system: {
|
||||
// CHECK: - [P1:X].[superclass: Base<[P1:A1]>] => [P1:X] [explicit]
|
||||
// CHECK: - [P1:X].[layout: _NativeClass] => [P1:X]
|
||||
@@ -48,8 +48,8 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
|
||||
// CHECK-NEXT: [P1] => { conforms_to: [P1] }
|
||||
// CHECK-NEXT: [P1:X] => { layout: _NativeClass superclass: [superclass: Base<[P1:A1]>] }
|
||||
// CHECK-NEXT: [P2] => { conforms_to: [P2] }
|
||||
// CHECK-NEXT: [P2:A2] => { conforms_to: [Q] }
|
||||
// CHECK-NEXT: [P2:X] => { layout: _NativeClass superclass: [superclass: Derived<[P2:A2]>] }
|
||||
// CHECK-NEXT: [P2:A2] => { conforms_to: [Q] }
|
||||
// CHECK-NEXT: [Q] => { conforms_to: [Q] }
|
||||
// CHECK-NEXT: τ_0_0 => { conforms_to: [P1 P2] }
|
||||
// CHECK-NEXT: τ_0_0.[P1:X] => { layout: _NativeClass superclass: [superclass: Derived<τ_0_0.[P2:A2]>] }
|
||||
|
||||
Reference in New Issue
Block a user