Skip to content

Commit de0aaec

Browse files
authored
Merge pull request #40011 from slavapestov/rqm-protocol-verify-mode
RequirementMachine: Implement -requirement-machine-protocol-signatures=verify
2 parents af2b72e + 967789f commit de0aaec

13 files changed

+236
-166
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4168,6 +4168,7 @@ class ProtocolDecl final : public NominalTypeDecl {
41684168
friend class StructuralRequirementsRequest;
41694169
friend class ProtocolDependenciesRequest;
41704170
friend class RequirementSignatureRequest;
4171+
friend class RequirementSignatureRequestRQM;
41714172
friend class ProtocolRequiresClassRequest;
41724173
friend class ExistentialConformsToSelfRequest;
41734174
friend class InheritedProtocolsRequest;

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,26 @@ class ProtocolDependenciesRequest :
406406
bool isCached() const { return true; }
407407
};
408408

409+
/// Compute the requirements that describe a protocol using the
410+
/// RequirementMachine.
411+
class RequirementSignatureRequestRQM :
412+
public SimpleRequest<RequirementSignatureRequestRQM,
413+
ArrayRef<Requirement>(ProtocolDecl *),
414+
RequestFlags::Cached> {
415+
public:
416+
using SimpleRequest::SimpleRequest;
417+
418+
private:
419+
friend SimpleRequest;
420+
421+
// Evaluation.
422+
ArrayRef<Requirement>
423+
evaluate(Evaluator &evaluator, ProtocolDecl *proto) const;
424+
425+
public:
426+
bool isCached() const { return true; }
427+
};
428+
409429
/// Compute the requirements that describe a protocol.
410430
class RequirementSignatureRequest :
411431
public SimpleRequest<RequirementSignatureRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ SWIFT_REQUEST(TypeChecker, StructuralRequirementsRequest,
225225
SWIFT_REQUEST(TypeChecker, ProtocolDependenciesRequest,
226226
ArrayRef<ProtocolDecl *>(ProtocolDecl *), Cached,
227227
HasNearestLocation)
228+
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequestRQM,
229+
ArrayRef<Requirement>(ProtocolDecl *), Cached,
230+
NoLocationInfo)
228231
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequest,
229232
ArrayRef<Requirement>(ProtocolDecl *), SeparatelyCached,
230233
NoLocationInfo)

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@
5454
using namespace swift;
5555
using llvm::DenseMap;
5656

57-
/// Define this to 1 to enable expensive assertions.
58-
#define SWIFT_GSB_EXPENSIVE_ASSERTIONS 0
57+
#define DEBUG_TYPE "Serialization"
58+
59+
STATISTIC(NumLazyRequirementSignaturesLoaded,
60+
"# of lazily-deserialized requirement signatures loaded");
61+
62+
#undef DEBUG_TYPE
5963

6064
namespace {
6165
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
@@ -8702,3 +8706,92 @@ InferredGenericSignatureRequest::evaluate(
87028706
allowConcreteGenericParams);
87038707
return GenericSignatureWithError(result, hadError);
87048708
}
8709+
8710+
ArrayRef<Requirement>
8711+
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
8712+
ProtocolDecl *proto) const {
8713+
ASTContext &ctx = proto->getASTContext();
8714+
8715+
// First check if we have a deserializable requirement signature.
8716+
if (proto->hasLazyRequirementSignature()) {
8717+
++NumLazyRequirementSignaturesLoaded;
8718+
// FIXME: (transitional) increment the redundant "always-on" counter.
8719+
if (ctx.Stats)
8720+
++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded;
8721+
8722+
auto contextData = static_cast<LazyProtocolData *>(
8723+
ctx.getOrCreateLazyContextData(proto, nullptr));
8724+
8725+
SmallVector<Requirement, 8> requirements;
8726+
contextData->loader->loadRequirementSignature(
8727+
proto, contextData->requirementSignatureData, requirements);
8728+
if (requirements.empty())
8729+
return None;
8730+
return ctx.AllocateCopy(requirements);
8731+
}
8732+
8733+
auto buildViaGSB = [&]() {
8734+
GenericSignatureBuilder builder(proto->getASTContext());
8735+
8736+
// Add all of the generic parameters.
8737+
for (auto gp : *proto->getGenericParams())
8738+
builder.addGenericParameter(gp);
8739+
8740+
// Add the conformance of 'self' to the protocol.
8741+
auto selfType =
8742+
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
8743+
auto requirement =
8744+
Requirement(RequirementKind::Conformance, selfType,
8745+
proto->getDeclaredInterfaceType());
8746+
8747+
builder.addRequirement(
8748+
requirement,
8749+
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
8750+
builder, selfType, proto),
8751+
nullptr);
8752+
8753+
auto reqSignature = std::move(builder).computeGenericSignature(
8754+
/*allowConcreteGenericParams=*/false,
8755+
/*requirementSignatureSelfProto=*/proto);
8756+
return reqSignature.getRequirements();
8757+
};
8758+
8759+
auto buildViaRQM = [&]() {
8760+
return evaluateOrDefault(
8761+
ctx.evaluator,
8762+
RequirementSignatureRequestRQM{const_cast<ProtocolDecl *>(proto)},
8763+
ArrayRef<Requirement>());
8764+
};
8765+
8766+
switch (ctx.LangOpts.RequirementMachineProtocolSignatures) {
8767+
case RequirementMachineMode::Disabled:
8768+
return buildViaGSB();
8769+
8770+
case RequirementMachineMode::Enabled:
8771+
return buildViaRQM();
8772+
8773+
case RequirementMachineMode::Verify: {
8774+
auto rqmResult = buildViaRQM();
8775+
auto gsbResult = buildViaGSB();
8776+
8777+
if (rqmResult.size() != gsbResult.size() ||
8778+
!std::equal(rqmResult.begin(), rqmResult.end(),
8779+
gsbResult.begin())) {
8780+
llvm::errs() << "RequirementMachine protocol signature minimization is broken:\n";
8781+
llvm::errs() << "Protocol: " << proto->getName() << "\n";
8782+
8783+
auto rqmSig = GenericSignature::get(
8784+
proto->getGenericSignature().getGenericParams(), rqmResult);
8785+
llvm::errs() << "RequirementMachine says: " << rqmSig << "\n";
8786+
8787+
auto gsbSig = GenericSignature::get(
8788+
proto->getGenericSignature().getGenericParams(), gsbResult);
8789+
llvm::errs() << "GenericSignatureBuilder says: " << gsbSig << "\n";
8790+
8791+
abort();
8792+
}
8793+
8794+
return gsbResult;
8795+
}
8796+
}
8797+
}

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,12 @@ bool RewritePath::replaceRuleWithPath(unsigned ruleID,
193193

194194
SmallVector<RewriteStep, 4> newSteps;
195195

196+
// Keep track of Decompose/Compose pairs. Any rewrite steps in
197+
// between do not need to be re-contextualized, since they
198+
// operate on new terms that were pushed on the stack by the
199+
// Compose operation.
200+
unsigned decomposeCount = 0;
201+
196202
for (const auto &step : Steps) {
197203
switch (step.Kind) {
198204
case RewriteStep::ApplyRewriteRule: {
@@ -202,13 +208,24 @@ bool RewritePath::replaceRuleWithPath(unsigned ruleID,
202208
}
203209

204210
auto adjustStep = [&](RewriteStep newStep) {
205-
newStep.StartOffset += step.StartOffset;
211+
bool inverse = newStep.Inverse ^ step.Inverse;
212+
213+
if (newStep.Kind == RewriteStep::Decompose && inverse) {
214+
assert(decomposeCount > 0);
215+
--decomposeCount;
216+
}
206217

207-
if (newStep.Kind == RewriteStep::ApplyRewriteRule)
218+
if (decomposeCount == 0) {
219+
newStep.StartOffset += step.StartOffset;
208220
newStep.EndOffset += step.EndOffset;
221+
}
209222

210-
newStep.Inverse ^= step.Inverse;
223+
newStep.Inverse = inverse;
211224
newSteps.push_back(newStep);
225+
226+
if (newStep.Kind == RewriteStep::Decompose && !inverse) {
227+
++decomposeCount;
228+
}
212229
};
213230

214231
if (step.Inverse) {

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,6 @@ void PropertyMap::addProperty(
296296
props->addProperty(property, Context,
297297
inducedRules, Debug.contains(DebugFlags::ConcreteUnification));
298298
}
299-
void PropertyMap::dump(llvm::raw_ostream &out) const {
300-
out << "Property map: {\n";
301-
for (const auto &props : Entries) {
302-
out << " ";
303-
props->dump(out);
304-
out << "\n";
305-
}
306-
out << "}\n";
307-
}
308299

309300
/// Build the property map from all rules of the form T.[p] => T, where
310301
/// [p] is a property symbol.
@@ -318,19 +309,18 @@ void PropertyMap::dump(llvm::raw_ostream &out) const {
318309
/// left hand side has a length exceeding \p maxDepth.
319310
///
320311
/// Otherwise, the status is CompletionResult::Success.
321-
std::pair<RewriteSystem::CompletionResult, unsigned>
322-
RewriteSystem::buildPropertyMap(PropertyMap &map,
323-
unsigned maxIterations,
324-
unsigned maxDepth) {
325-
map.clear();
312+
std::pair<CompletionResult, unsigned>
313+
PropertyMap::buildPropertyMap(unsigned maxIterations,
314+
unsigned maxDepth) {
315+
clear();
326316

327317
// PropertyMap::addRule() requires that shorter rules are added
328318
// before longer rules, so that it can perform lookups on suffixes and call
329319
// PropertyBag::copyPropertiesFrom(). However, we don't have to perform a
330320
// full sort by term order here; a bucket sort by term length suffices.
331321
SmallVector<std::vector<std::pair<Term, Symbol>>, 4> properties;
332322

333-
for (const auto &rule : Rules) {
323+
for (const auto &rule : System.getRules()) {
334324
if (rule.isSimplified())
335325
continue;
336326

@@ -355,34 +345,44 @@ RewriteSystem::buildPropertyMap(PropertyMap &map,
355345

356346
for (const auto &bucket : properties) {
357347
for (auto pair : bucket) {
358-
map.addProperty(pair.first, pair.second, inducedRules);
348+
addProperty(pair.first, pair.second, inducedRules);
359349
}
360350
}
361351

362352
// We collect terms with fully concrete types so that we can re-use them
363353
// to tie off recursion in the next step.
364-
map.computeConcreteTypeInDomainMap();
354+
computeConcreteTypeInDomainMap();
365355

366356
// Now, we merge concrete type rules with conformance rules, by adding
367357
// relations between associated type members of type parameters with
368358
// the concrete type witnesses in the concrete type's conformance.
369-
map.concretizeNestedTypesFromConcreteParents(inducedRules);
359+
concretizeNestedTypesFromConcreteParents(inducedRules);
370360

371361
// Some of the induced rules might be trivial; only count the induced rules
372362
// where the left hand side is not already equivalent to the right hand side.
373363
unsigned addedNewRules = 0;
374364
for (auto pair : inducedRules) {
375-
if (addRule(pair.first, pair.second)) {
365+
if (System.addRule(pair.first, pair.second)) {
376366
++addedNewRules;
377367

378-
const auto &newRule = Rules.back();
379-
if (newRule.getLHS().size() > maxDepth)
368+
const auto &newRule = System.getRules().back();
369+
if (newRule.getDepth() > maxDepth)
380370
return std::make_pair(CompletionResult::MaxDepth, addedNewRules);
381371
}
382372
}
383373

384-
if (Rules.size() > maxIterations)
374+
if (System.getRules().size() > maxIterations)
385375
return std::make_pair(CompletionResult::MaxIterations, addedNewRules);
386376

387377
return std::make_pair(CompletionResult::Success, addedNewRules);
378+
}
379+
380+
void PropertyMap::dump(llvm::raw_ostream &out) const {
381+
out << "Property map: {\n";
382+
for (const auto &props : Entries) {
383+
out << " ";
384+
props->dump(out);
385+
out << "\n";
386+
}
387+
out << "}\n";
388388
}

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,13 @@ class PropertyMap {
163163

164164
PropertyBag *lookUpProperties(const MutableTerm &key) const;
165165

166+
std::pair<CompletionResult, unsigned>
167+
buildPropertyMap(unsigned maxIterations,
168+
unsigned maxDepth);
169+
166170
void dump(llvm::raw_ostream &out) const;
167171

172+
private:
168173
void clear();
169174
void addProperty(Term key, Symbol property,
170175
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules);
@@ -173,7 +178,6 @@ class PropertyMap {
173178
void concretizeNestedTypesFromConcreteParents(
174179
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const;
175180

176-
private:
177181
void concretizeNestedTypesFromConcreteParent(
178182
Term key, RequirementKind requirementKind,
179183
CanType concreteType, ArrayRef<Term> substitutions,

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -528,16 +528,16 @@ void RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy)
528528
// Check for failure.
529529
auto checkCompletionResult = [&]() {
530530
switch (result.first) {
531-
case RewriteSystem::CompletionResult::Success:
531+
case CompletionResult::Success:
532532
break;
533533

534-
case RewriteSystem::CompletionResult::MaxIterations:
534+
case CompletionResult::MaxIterations:
535535
llvm::errs() << "Generic signature " << Sig
536536
<< " exceeds maximum completion step count\n";
537537
System.dump(llvm::errs());
538538
abort();
539539

540-
case RewriteSystem::CompletionResult::MaxDepth:
540+
case CompletionResult::MaxDepth:
541541
llvm::errs() << "Generic signature " << Sig
542542
<< " exceeds maximum completion depth\n";
543543
System.dump(llvm::errs());
@@ -553,8 +553,7 @@ void RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy)
553553
// Build the property map, which also performs concrete term
554554
// unification; if this added any new rules, run the completion
555555
// procedure again.
556-
result = System.buildPropertyMap(
557-
Map,
556+
result = Map.buildPropertyMap(
558557
RequirementMachineStepLimit,
559558
RequirementMachineDepthLimit);
560559

0 commit comments

Comments
 (0)