Skip to content

Commit 044611d

Browse files
committed
RequirementMachine: Another cycle-breaking hack for associated type inference
1 parent 47f3341 commit 044611d

File tree

6 files changed

+45
-5
lines changed

6 files changed

+45
-5
lines changed

include/swift/AST/ASTContext.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,11 @@ class ASTContext final {
12311231
bool isRecursivelyConstructingRequirementMachine(
12321232
CanGenericSignature sig);
12331233

1234+
/// This is a hack to break cycles. Don't introduce new callers of this
1235+
/// method.
1236+
bool isRecursivelyConstructingRequirementMachine(
1237+
const ProtocolDecl *proto);
1238+
12341239
/// Retrieve a generic signature with a single unconstrained type parameter,
12351240
/// like `<T>`.
12361241
CanGenericSignature getSingleGenericParameterSignature() const;

lib/AST/ASTContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,11 @@ bool ASTContext::isRecursivelyConstructingRequirementMachine(
20172017
return getRewriteContext().isRecursivelyConstructingRequirementMachine(sig);
20182018
}
20192019

2020+
bool ASTContext::isRecursivelyConstructingRequirementMachine(
2021+
const ProtocolDecl *proto) {
2022+
return getRewriteContext().isRecursivelyConstructingRequirementMachine(proto);
2023+
}
2024+
20202025
Optional<llvm::TinyPtrVector<ValueDecl *>>
20212026
OverriddenDeclsRequest::getCachedResult() const {
20222027
auto decl = std::get<0>(getStorage());

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ RequirementMachine *RewriteContext::getRequirementMachine(
651651
<< "machine for:";
652652
for (auto *proto : component.Protos)
653653
llvm::errs() << " " << proto->getName();
654+
llvm::errs() << "\n";
654655
abort();
655656
}
656657

@@ -668,6 +669,23 @@ RequirementMachine *RewriteContext::getRequirementMachine(
668669
return newMachine;
669670
}
670671

672+
bool RewriteContext::isRecursivelyConstructingRequirementMachine(
673+
const ProtocolDecl *proto) {
674+
auto found = Protos.find(proto);
675+
if (found == Protos.end())
676+
return false;
677+
678+
auto component = Components.find(found->second.ComponentID);
679+
if (component == Components.end())
680+
return false;
681+
682+
if (!component->second.Machine ||
683+
component->second.Machine->isComplete())
684+
return false;
685+
686+
return true;
687+
}
688+
671689
/// We print stats in the destructor, which should get executed at the end of
672690
/// a compilation job.
673691
RewriteContext::~RewriteContext() {

lib/AST/RequirementMachine/RewriteContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class RewriteContext final {
180180
bool isRecursivelyConstructingRequirementMachine(CanGenericSignature sig);
181181

182182
RequirementMachine *getRequirementMachine(const ProtocolDecl *proto);
183+
bool isRecursivelyConstructingRequirementMachine(const ProtocolDecl *proto);
183184

184185
~RewriteContext();
185186
};

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4562,19 +4562,29 @@ CheckTypeWitnessResult
45624562
swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
45634563
const NormalProtocolConformance *Conf,
45644564
SubstOptions options) {
4565+
auto &ctx = assocType->getASTContext();
4566+
45654567
if (type->hasError())
4566-
return ErrorType::get(assocType->getASTContext());
4568+
return ErrorType::get(ctx);
45674569

45684570
const auto proto = Conf->getProtocol();
45694571
const auto dc = Conf->getDeclContext();
4570-
const auto genericSig = proto->getGenericSignature();
4572+
const auto sig = proto->getGenericSignature();
4573+
4574+
// FIXME: The RequirementMachine will assert on re-entrant construction.
4575+
// We should find a more principled way of breaking this cycle.
4576+
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
4577+
ctx.isRecursivelyConstructingRequirementMachine(proto) ||
4578+
proto->isComputingRequirementSignature())
4579+
return ErrorType::get(ctx);
4580+
45714581
const auto depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
45724582
assocType);
45734583

45744584
Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type)
45754585
: type;
45764586

4577-
if (auto superclass = genericSig->getSuperclassBound(depTy)) {
4587+
if (auto superclass = sig->getSuperclassBound(depTy)) {
45784588
if (superclass->hasTypeParameter()) {
45794589
// Replace type parameters with other known or tentative type witnesses.
45804590
superclass = superclass.subst(
@@ -4596,7 +4606,7 @@ swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
45964606
auto *module = dc->getParentModule();
45974607

45984608
// Check protocol conformances.
4599-
for (const auto reqProto : genericSig->getRequiredProtocols(depTy)) {
4609+
for (const auto reqProto : sig->getRequiredProtocols(depTy)) {
46004610
if (module->lookupConformance(contextType, reqProto)
46014611
.isInvalid())
46024612
return CheckTypeWitnessResult(reqProto->getDeclaredInterfaceType());
@@ -4617,7 +4627,7 @@ swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
46174627
}
46184628
}
46194629

4620-
if (genericSig->requiresClass(depTy) &&
4630+
if (sig->requiresClass(depTy) &&
46214631
!contextType->satisfiesClassConstraint())
46224632
return CheckTypeWitnessResult(module->getASTContext().getAnyObjectType());
46234633

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ Type AssociatedTypeInference::computeFixedTypeWitness(
819819
// FIXME: The RequirementMachine will assert on re-entrant construction.
820820
// We should find a more principled way of breaking this cycle.
821821
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
822+
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
822823
conformedProto->isComputingRequirementSignature())
823824
continue;
824825

0 commit comments

Comments
 (0)