Skip to content

Commit 3b91173

Browse files
committed
AST: Factor out guts of finishSignatureConformances() into a new AssociatedConformanceRequest
1 parent 28d1455 commit 3b91173

File tree

5 files changed

+122
-65
lines changed

5 files changed

+122
-65
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,6 +2737,30 @@ class ValueWitnessRequest
27372737
void cacheResult(Witness value) const;
27382738
};
27392739

2740+
class AssociatedConformanceRequest
2741+
: public SimpleRequest<AssociatedConformanceRequest,
2742+
ProtocolConformanceRef(NormalProtocolConformance *,
2743+
CanType, ProtocolDecl *,
2744+
unsigned),
2745+
RequestFlags::SeparatelyCached> {
2746+
public:
2747+
using SimpleRequest::SimpleRequest;
2748+
2749+
private:
2750+
friend SimpleRequest;
2751+
2752+
// Evaluation.
2753+
ProtocolConformanceRef
2754+
evaluate(Evaluator &evaluator, NormalProtocolConformance *conformance,
2755+
CanType t, ProtocolDecl *proto, unsigned index) const;
2756+
2757+
public:
2758+
// Separate caching.
2759+
bool isCached() const { return true; }
2760+
llvm::Optional<ProtocolConformanceRef> getCachedResult() const;
2761+
void cacheResult(ProtocolConformanceRef value) const;
2762+
};
2763+
27402764
struct PreCheckResultBuilderDescriptor {
27412765
AnyFunctionRef Fn;
27422766
bool SuppressDiagnostics;

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
403403
TypeWitnessAndDecl(NormalProtocolConformance *,
404404
AssociatedTypeDecl *),
405405
SeparatelyCached, NoLocationInfo)
406+
SWIFT_REQUEST(TypeChecker, AssociatedConformanceRequest,
407+
ProtocolConformanceRef(NormalProtocolConformance *,
408+
Type, ProtocolDecl *, unsigned),
409+
SeparatelyCached, NoLocationInfo)
406410
SWIFT_REQUEST(TypeChecker, ValueWitnessRequest,
407411
Witness(NormalProtocolConformance *, ValueDecl *),
408412
SeparatelyCached, NoLocationInfo)

lib/AST/ProtocolConformance.cpp

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -576,37 +576,6 @@ void NormalProtocolConformance::setAssociatedConformance(
576576
AssociatedConformances[index] = assocConf;
577577
}
578578

579-
/// A stripped-down version of Type::subst that only works on the protocol
580-
/// Self type wrapped in zero or more DependentMemberTypes.
581-
static Type
582-
recursivelySubstituteBaseType(ModuleDecl *module,
583-
NormalProtocolConformance *conformance,
584-
DependentMemberType *depMemTy) {
585-
Type origBase = depMemTy->getBase();
586-
587-
// Recursive case.
588-
if (auto *depBase = origBase->getAs<DependentMemberType>()) {
589-
Type substBase = recursivelySubstituteBaseType(
590-
module, conformance, depBase);
591-
return depMemTy->substBaseType(module, substBase);
592-
}
593-
594-
// Base case. The associated type's protocol should be either the
595-
// conformance protocol or an inherited protocol.
596-
auto *reqProto = depMemTy->getAssocType()->getProtocol();
597-
assert(origBase->isEqual(reqProto->getSelfInterfaceType()));
598-
599-
ProtocolConformance *reqConformance = conformance;
600-
601-
// If we have an inherited protocol just look up the conformance.
602-
if (reqProto != conformance->getProtocol()) {
603-
reqConformance = module->lookupConformance(conformance->getType(), reqProto)
604-
.getConcrete();
605-
}
606-
607-
return reqConformance->getTypeWitness(depMemTy->getAssocType());
608-
}
609-
610579
/// Collect conformances for the requirement signature.
611580
void NormalProtocolConformance::finishSignatureConformances() {
612581
if (Loader)
@@ -617,43 +586,14 @@ void NormalProtocolConformance::finishSignatureConformances() {
617586

618587
createAssociatedConformanceArray();
619588

620-
auto *proto = getProtocol();
621-
ModuleDecl *module = getDeclContext()->getParentModule();
589+
auto &ctx = getDeclContext()->getASTContext();
622590

623591
forEachAssociatedConformance(
624592
[&](Type origTy, ProtocolDecl *reqProto, unsigned index) {
625-
Type substTy;
626-
627-
if (origTy->isEqual(proto->getSelfInterfaceType())) {
628-
substTy = getType();
629-
} else {
630-
auto *depMemTy = origTy->castTo<DependentMemberType>();
631-
substTy = recursivelySubstituteBaseType(module, this, depMemTy);
632-
}
633-
634-
// Looking up a conformance for a contextual type and mapping the
635-
// conformance context produces a more accurate result than looking
636-
// up a conformance from an interface type.
637-
//
638-
// This can happen if the conformance has an associated conformance
639-
// depending on an associated type that is made concrete in a
640-
// refining protocol.
641-
//
642-
// That is, the conformance of an interface type G<T> : P really
643-
// depends on the generic signature of the current context, because
644-
// performing the lookup in a "more" constrained extension than the
645-
// one where the conformance was defined must produce concrete
646-
// conformances.
647-
//
648-
// FIXME: Eliminate this, perhaps by adding a variant of
649-
// lookupConformance() taking a generic signature.
650-
if (substTy->hasTypeParameter())
651-
substTy = getDeclContext()->mapTypeIntoContext(substTy);
652-
653-
auto assocConf = module->lookupConformance(substTy, reqProto,
654-
/*allowMissing=*/true)
655-
.mapConformanceOutOfContext();
656-
setAssociatedConformance(index, assocConf);
593+
auto canTy = origTy->getCanonicalType();
594+
evaluateOrDefault(ctx.evaluator,
595+
AssociatedConformanceRequest{this, canTy, reqProto, index},
596+
ProtocolConformanceRef::forInvalid());
657597
return false;
658598
});
659599
}

lib/AST/TypeCheckRequests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,26 @@ void ValueWitnessRequest::cacheResult(Witness type) const {
11961196
// FIXME: Refactor this to be the thing that warms the cache.
11971197
}
11981198

1199+
//----------------------------------------------------------------------------//
1200+
// AssociatedConformanceRequest computation.
1201+
//----------------------------------------------------------------------------//
1202+
1203+
llvm::Optional<ProtocolConformanceRef>
1204+
AssociatedConformanceRequest::getCachedResult() const {
1205+
auto *conformance = std::get<0>(getStorage());
1206+
unsigned index = std::get<3>(getStorage());
1207+
1208+
return conformance->getAssociatedConformance(index);
1209+
}
1210+
1211+
void AssociatedConformanceRequest::cacheResult(
1212+
ProtocolConformanceRef assocConf) const {
1213+
auto *conformance = std::get<0>(getStorage());
1214+
unsigned index = std::get<3>(getStorage());
1215+
1216+
conformance->setAssociatedConformance(index, assocConf);
1217+
}
1218+
11991219
//----------------------------------------------------------------------------//
12001220
// PreCheckResultBuilderRequest computation.
12011221
//----------------------------------------------------------------------------//

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7008,6 +7008,75 @@ ValueWitnessRequest::evaluate(Evaluator &eval,
70087008
return known->second;
70097009
}
70107010

7011+
/// A stripped-down version of Type::subst that only works on the protocol
7012+
/// Self type wrapped in zero or more DependentMemberTypes.
7013+
static Type
7014+
recursivelySubstituteBaseType(ModuleDecl *module,
7015+
NormalProtocolConformance *conformance,
7016+
DependentMemberType *depMemTy) {
7017+
Type origBase = depMemTy->getBase();
7018+
7019+
// Recursive case.
7020+
if (auto *depBase = origBase->getAs<DependentMemberType>()) {
7021+
Type substBase = recursivelySubstituteBaseType(
7022+
module, conformance, depBase);
7023+
return depMemTy->substBaseType(module, substBase);
7024+
}
7025+
7026+
// Base case. The associated type's protocol should be either the
7027+
// conformance protocol or an inherited protocol.
7028+
auto *reqProto = depMemTy->getAssocType()->getProtocol();
7029+
assert(origBase->isEqual(reqProto->getSelfInterfaceType()));
7030+
7031+
ProtocolConformance *reqConformance = conformance;
7032+
7033+
// If we have an inherited protocol just look up the conformance.
7034+
if (reqProto != conformance->getProtocol()) {
7035+
reqConformance = module->lookupConformance(conformance->getType(), reqProto)
7036+
.getConcrete();
7037+
}
7038+
7039+
return reqConformance->getTypeWitness(depMemTy->getAssocType());
7040+
}
7041+
7042+
ProtocolConformanceRef
7043+
AssociatedConformanceRequest::evaluate(Evaluator &eval,
7044+
NormalProtocolConformance *conformance,
7045+
CanType origTy, ProtocolDecl *reqProto,
7046+
unsigned index) const {
7047+
auto *module = conformance->getDeclContext()->getParentModule();
7048+
Type substTy;
7049+
7050+
if (origTy->isEqual(conformance->getProtocol()->getSelfInterfaceType())) {
7051+
substTy = conformance->getType();
7052+
} else {
7053+
auto *depMemTy = origTy->castTo<DependentMemberType>();
7054+
substTy = recursivelySubstituteBaseType(module, conformance, depMemTy);
7055+
}
7056+
7057+
// Looking up a conformance for a contextual type and mapping the
7058+
// conformance context produces a more accurate result than looking
7059+
// up a conformance from an interface type.
7060+
//
7061+
// This can happen if the conformance has an associated conformance
7062+
// depending on an associated type that is made concrete in a
7063+
// refining protocol.
7064+
//
7065+
// That is, the conformance of an interface type G<T> : P really
7066+
// depends on the generic signature of the current context, because
7067+
// performing the lookup in a "more" constrained extension than the
7068+
// one where the conformance was defined must produce concrete
7069+
// conformances.
7070+
//
7071+
// FIXME: Eliminate this, perhaps by adding a variant of
7072+
// lookupConformance() taking a generic signature.
7073+
if (substTy->hasTypeParameter())
7074+
substTy = conformance->getDeclContext()->mapTypeIntoContext(substTy);
7075+
7076+
return module->lookupConformance(substTy, reqProto, /*allowMissing=*/true)
7077+
.mapConformanceOutOfContext();
7078+
}
7079+
70117080
ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC,
70127081
NominalTypeDecl *TypeDecl,
70137082
ValueDecl *Requirement) {

0 commit comments

Comments
 (0)