Skip to content

Commit 811a201

Browse files
authored
Merge pull request #84675 from slavapestov/rqm-protocol-failure-bookkeeping
RequirementMachine: New way of propagating failure when building rewrite system for protocol
2 parents ee156f2 + 244d2af commit 811a201

18 files changed

+78
-50
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,11 @@ enum class GenericSignatureErrorFlags {
606606

607607
/// The Knuth-Bendix completion procedure failed to construct a confluent
608608
/// rewrite system.
609-
CompletionFailed = (1<<2)
609+
CompletionFailed = (1<<2),
610+
611+
/// A request evaluator cycle prevented us from computing this generic
612+
/// signature.
613+
CircularReference = (1<<3),
610614
};
611615

612616
using GenericSignatureErrors = OptionSet<GenericSignatureErrorFlags>;

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7451,7 +7451,7 @@ RequirementSignature ProtocolDecl::getRequirementSignature() const {
74517451
RequirementSignatureRequest{const_cast<ProtocolDecl *>(this)},
74527452
[this]() {
74537453
return RequirementSignature::getPlaceholderRequirementSignature(
7454-
this, GenericSignatureErrors());
7454+
this, GenericSignatureErrorFlags::CircularReference);
74557455
});
74567456
}
74577457

lib/AST/GenericSignature.cpp

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,33 +1400,13 @@ RequirementSignature RequirementSignature::getPlaceholderRequirementSignature(
14001400
const ProtocolDecl *proto, GenericSignatureErrors errors) {
14011401
auto &ctx = proto->getASTContext();
14021402

1403-
SmallVector<ProtocolDecl *, 2> inheritedProtos;
1404-
for (auto *inheritedProto : proto->getInheritedProtocols()) {
1405-
inheritedProtos.push_back(inheritedProto);
1406-
}
1407-
1403+
// Pretend the protocol inherits from Copyable and Escapable.
1404+
SmallVector<Requirement, 2> requirements;
14081405
for (auto ip : InvertibleProtocolSet::allKnown()) {
14091406
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
1410-
inheritedProtos.push_back(otherProto);
1411-
}
1412-
1413-
ProtocolType::canonicalizeProtocols(inheritedProtos);
1414-
1415-
SmallVector<Requirement, 2> requirements;
1416-
1417-
for (auto *inheritedProto : inheritedProtos) {
14181407
requirements.emplace_back(RequirementKind::Conformance,
14191408
proto->getSelfInterfaceType(),
1420-
inheritedProto->getDeclaredInterfaceType());
1421-
}
1422-
1423-
for (auto *assocTypeDecl : proto->getAssociatedTypeMembers()) {
1424-
for (auto ip : InvertibleProtocolSet::allKnown()) {
1425-
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
1426-
requirements.emplace_back(RequirementKind::Conformance,
1427-
assocTypeDecl->getDeclaredInterfaceType(),
1428-
otherProto->getDeclaredInterfaceType());
1429-
}
1409+
otherProto->getDeclaredInterfaceType());
14301410
}
14311411

14321412
// Maintain invariants.

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,12 @@ Type ProtocolConformanceRef::getTypeWitness(AssociatedTypeDecl *assocType,
202202
auto conformingType = abstract->getType();
203203
ASSERT(abstract->getProtocol() == assocType->getProtocol());
204204

205-
if (auto *archetypeType = conformingType->getAs<ArchetypeType>())
206-
return archetypeType->getNestedType(assocType);
205+
if (auto *archetypeType = conformingType->getAs<ArchetypeType>()) {
206+
auto witnessType = archetypeType->getNestedType(assocType);
207+
if (!witnessType)
208+
return ErrorType::get(assocType->getASTContext());
209+
return witnessType;
210+
}
207211

208212
return DependentMemberType::get(conformingType, assocType);
209213
}

lib/AST/RequirementMachine/GenericSignatureQueries.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ static Type substPrefixType(Type type, unsigned suffixLength, Type prefixType,
353353
Type RequirementMachine::getReducedTypeParameter(
354354
CanType t,
355355
ArrayRef<GenericTypeParamType *> genericParams) const {
356+
if (Failed)
357+
return ErrorType::get(t);
358+
356359
// Get a simplified term T.
357360
auto term = Context.getMutableTermForType(t, /*proto=*/nullptr);
358361
System.simplify(term);
@@ -801,6 +804,9 @@ void RequirementMachine::verify(const MutableTerm &term) const {
801804
}
802805
}
803806

807+
if (Failed)
808+
return;
809+
804810
MutableTerm erased;
805811

806812
// First, "erase" resolved associated types from the term, and try

lib/AST/RequirementMachine/RequirementBuilder.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,9 @@ RequirementMachine::buildRequirementsFromRules(
395395
bool reconstituteSugar,
396396
std::vector<Requirement> &reqs,
397397
std::vector<ProtocolTypeAlias> &aliases) const {
398+
if (Failed)
399+
return;
400+
398401
RequirementBuilder builder(System, Map, genericParams, reconstituteSugar);
399402

400403
builder.addRequirementRules(requirementRules);

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ RequirementMachine::initWithProtocolSignatureRequirements(
289289
RuleBuilder builder(Context, System.getReferencedProtocols());
290290
builder.initWithProtocolSignatureRequirements(protos);
291291

292+
// Remember if any of our upstream protocols failed to complete.
293+
Failed = builder.Failed;
294+
292295
// Add the initial set of rewrite rules to the rewrite system.
293296
System.initialize(/*recordLoops=*/false, protos,
294297
std::move(builder.ImportedRules),
@@ -337,6 +340,9 @@ RequirementMachine::initWithGenericSignature(GenericSignature sig) {
337340
builder.initWithGenericSignature(sig.getGenericParams(),
338341
sig.getRequirements());
339342

343+
// Remember if any of our upstream protocols failed to complete.
344+
Failed = builder.Failed;
345+
340346
// Add the initial set of rewrite rules to the rewrite system.
341347
System.initialize(/*recordLoops=*/false,
342348
/*protos=*/ArrayRef<const ProtocolDecl *>(),
@@ -390,6 +396,9 @@ RequirementMachine::initWithProtocolWrittenRequirements(
390396
RuleBuilder builder(Context, System.getReferencedProtocols());
391397
builder.initWithProtocolWrittenRequirements(component, protos);
392398

399+
// Remember if any of our upstream protocols failed to complete.
400+
Failed = builder.Failed;
401+
393402
// Add the initial set of rewrite rules to the rewrite system.
394403
System.initialize(/*recordLoops=*/true, component,
395404
std::move(builder.ImportedRules),
@@ -437,6 +446,9 @@ RequirementMachine::initWithWrittenRequirements(
437446
RuleBuilder builder(Context, System.getReferencedProtocols());
438447
builder.initWithWrittenRequirements(genericParams, requirements);
439448

449+
// Remember if any of our upstream protocols failed to complete.
450+
Failed = builder.Failed;
451+
440452
// Add the initial set of rewrite rules to the rewrite system.
441453
System.initialize(/*recordLoops=*/true,
442454
/*protos=*/ArrayRef<const ProtocolDecl *>(),
@@ -553,10 +565,6 @@ ArrayRef<Rule> RequirementMachine::getLocalRules() const {
553565
return System.getLocalRules();
554566
}
555567

556-
bool RequirementMachine::isComplete() const {
557-
return Complete;
558-
}
559-
560568
GenericSignatureErrors RequirementMachine::getErrors() const {
561569
// FIXME: Assert if we had errors but we didn't emit any diagnostics?
562570
return System.getErrors();

lib/AST/RequirementMachine/RequirementMachine.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ class RequirementMachine final {
6464
bool Dump = false;
6565
bool Complete = false;
6666

67+
/// Whether completion failed, either for this rewrite system, or one of
68+
/// its imported protocols. In this case, name lookup might find type
69+
/// parameters that are not valid according to the rewrite system, because
70+
/// not all conformance requirements will be present. This flag allows
71+
/// us to skip certain verification checks in that case.
72+
bool Failed = false;
73+
6774
/// Parameters to prevent runaway completion and property map construction.
6875
unsigned MaxRuleCount;
6976
unsigned MaxRuleLength;
@@ -110,7 +117,9 @@ class RequirementMachine final {
110117
ArrayRef<GenericTypeParamType *> genericParams,
111118
ArrayRef<StructuralRequirement> requirements);
112119

113-
bool isComplete() const;
120+
bool isComplete() const {
121+
return Complete;
122+
}
114123

115124
std::pair<CompletionResult, unsigned>
116125
computeCompletion(RewriteSystem::ValidityPolicy policy);
@@ -139,6 +148,10 @@ class RequirementMachine final {
139148
public:
140149
~RequirementMachine();
141150

151+
bool isFailed() const {
152+
return Failed;
153+
}
154+
142155
// Generic signature queries. Generally you shouldn't have to construct a
143156
// RequirementMachine instance; instead, call the corresponding methods on
144157
// GenericSignature, which lazily create a RequirementMachine for you.

lib/AST/RequirementMachine/RuleBuilder.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,19 +106,10 @@ void RuleBuilder::initWithProtocolSignatureRequirements(
106106
addPermanentProtocolRules(proto);
107107

108108
auto reqs = proto->getRequirementSignature();
109-
110-
// If completion failed, we'll have a totally empty requirement signature,
111-
// but to maintain invariants around what constitutes a valid rewrite term
112-
// between getTypeForTerm() and isValidTypeParameter(), we need to add rules
113-
// for inherited protocols.
114-
if (reqs.getErrors().contains(GenericSignatureErrorFlags::CompletionFailed)) {
115-
for (auto *inheritedProto : proto->getAllInheritedProtocols()) {
116-
Requirement req(RequirementKind::Conformance,
117-
proto->getSelfInterfaceType(),
118-
inheritedProto->getDeclaredInterfaceType());
119-
120-
addRequirement(req.getCanonical(), proto);
121-
}
109+
auto errors = reqs.getErrors();
110+
if (errors.contains(GenericSignatureErrorFlags::CompletionFailed) ||
111+
errors.contains(GenericSignatureErrorFlags::CircularReference)) {
112+
Failed = 1;
122113
}
123114

124115
for (auto req : reqs.getRequirements())
@@ -495,6 +486,9 @@ void RuleBuilder::collectRulesFromReferencedProtocols() {
495486
continue;
496487
}
497488

489+
if (machine->isFailed())
490+
Failed = 1;
491+
498492
// We grab the machine's local rules, not *all* of its rules, to avoid
499493
// duplicates in case multiple machines share a dependency on a downstream
500494
// protocol component.

lib/AST/RequirementMachine/RuleBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,15 @@ struct RuleBuilder {
8383
/// Used to ensure the initWith*() methods are only called once.
8484
unsigned Initialized : 1;
8585

86+
/// Whether completion failed for any of our upstream protocol components.
87+
unsigned Failed : 1;
88+
8689
RuleBuilder(RewriteContext &ctx,
8790
llvm::DenseSet<const ProtocolDecl *> &referencedProtocols)
8891
: Context(ctx), ReferencedProtocols(referencedProtocols) {
8992
Dump = ctx.getASTContext().LangOpts.DumpRequirementMachine;
9093
Initialized = 0;
94+
Failed = 0;
9195
}
9296

9397
void initWithGenericSignature(ArrayRef<GenericTypeParamType *> genericParams,

0 commit comments

Comments
 (0)