Skip to content

Commit 991a6de

Browse files
authored
Merge pull request #71131 from slavapestov/conformance-checker-vs-type-witnesses-untangling
Sema: Decouple type witness resolution from the ConformanceChecker
2 parents 36a20a5 + 979fc28 commit 991a6de

21 files changed

+852
-1028
lines changed

include/swift/AST/ProtocolConformance.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ enum class ProtocolConformanceState {
8686
Complete = 0,
8787
/// The conformance is known but is not yet complete.
8888
Incomplete,
89-
/// The conformance's type witnesses are currently being resolved.
90-
CheckingTypeWitnesses,
9189
/// The conformance is being checked.
9290
Checking,
9391

@@ -225,7 +223,6 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance
225223
/// Determine whether this conformance is incomplete.
226224
bool isIncomplete() const {
227225
return getState() == ProtocolConformanceState::Incomplete ||
228-
getState() == ProtocolConformanceState::CheckingTypeWitnesses ||
229226
getState() == ProtocolConformanceState::Checking;
230227
}
231228

include/swift/AST/TypeCheckRequests.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2870,6 +2870,24 @@ class ReferencedAssociatedTypesRequest
28702870
bool isCached() const { return true; }
28712871
};
28722872

2873+
class ResolveTypeWitnessesRequest
2874+
: public SimpleRequest<ResolveTypeWitnessesRequest,
2875+
evaluator::SideEffect(NormalProtocolConformance *),
2876+
RequestFlags::Cached> {
2877+
public:
2878+
using SimpleRequest::SimpleRequest;
2879+
2880+
private:
2881+
friend SimpleRequest;
2882+
2883+
// Evaluation.
2884+
evaluator::SideEffect
2885+
evaluate(Evaluator &evaluator, NormalProtocolConformance *conformance) const;
2886+
2887+
public:
2888+
bool isCached() const { return true; }
2889+
};
2890+
28732891
class ValueWitnessRequest
28742892
: public SimpleRequest<ValueWitnessRequest,
28752893
Witness(NormalProtocolConformance *, ValueDecl *),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ SWIFT_REQUEST(TypeChecker, AssociatedConformanceRequest,
432432
SWIFT_REQUEST(TypeChecker, ReferencedAssociatedTypesRequest,
433433
TinyPtrVector<AssociatedTypeDecl *>(ValueDecl *),
434434
Cached, NoLocationInfo)
435+
SWIFT_REQUEST(TypeChecker, ResolveTypeWitnessesRequest,
436+
evaluator::SideEffect(NormalProtocolConformance *),
437+
Cached, NoLocationInfo)
435438
SWIFT_REQUEST(TypeChecker, ValueWitnessRequest,
436439
Witness(NormalProtocolConformance *, ValueDecl *),
437440
SeparatelyCached, NoLocationInfo)

lib/AST/ASTContext.cpp

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,56 +2780,69 @@ ASTContext::MissingWitness::MissingWitness(ValueDecl *requirement,
27802780
: requirement(requirement),
27812781
matches(matches.begin(), matches.end()) { }
27822782

2783-
void ASTContext::addDelayedConformanceDiag(
2784-
NormalProtocolConformance *conformance, bool isError,
2785-
std::function<void(NormalProtocolConformance *)> callback) {
2786-
if (isError)
2787-
conformance->setInvalid();
2788-
2789-
auto &diagnostics = getImpl().DelayedConformanceDiags[conformance];
2783+
static void maybeEmitFallbackConformanceDiagnostic(
2784+
ASTContext &ctx,
2785+
NormalProtocolConformance *conformance,
2786+
DelayedConformanceDiags &diagnostics) {
27902787

2791-
if (isError && !diagnostics.HadError) {
2792-
diagnostics.HadError = true;
2788+
if (diagnostics.HadError)
2789+
return;
27932790

2794-
auto *proto = conformance->getProtocol();
2795-
auto *dc = conformance->getDeclContext();
2796-
auto *sf = dc->getParentSourceFile();
2797-
auto *mod = sf->getParentModule();
2798-
assert(mod->isMainModule());
2791+
diagnostics.HadError = true;
27992792

2800-
// If we have at least one primary file and the conformance is declared in a
2801-
// non-primary file, emit a fallback diagnostic.
2802-
if ((!sf->isPrimary() && !mod->getPrimarySourceFiles().empty()) ||
2803-
TypeCheckerOpts.EnableLazyTypecheck) {
2804-
auto complainLoc = evaluator.getInnermostSourceLoc([&](SourceLoc loc) {
2805-
if (loc.isInvalid())
2806-
return false;
2793+
auto *proto = conformance->getProtocol();
2794+
auto *dc = conformance->getDeclContext();
2795+
auto *sf = dc->getParentSourceFile();
2796+
auto *mod = sf->getParentModule();
2797+
assert(mod->isMainModule());
28072798

2808-
auto *otherSF = mod->getSourceFileContainingLocation(loc);
2809-
if (otherSF == nullptr)
2810-
return false;
2799+
// If we have at least one primary file and the conformance is declared in a
2800+
// non-primary file, emit a fallback diagnostic.
2801+
if ((!sf->isPrimary() && !mod->getPrimarySourceFiles().empty()) ||
2802+
ctx.TypeCheckerOpts.EnableLazyTypecheck) {
2803+
auto complainLoc = ctx.evaluator.getInnermostSourceLoc([&](SourceLoc loc) {
2804+
if (loc.isInvalid())
2805+
return false;
28112806

2812-
return otherSF->isPrimary();
2813-
});
2807+
auto *otherSF = mod->getSourceFileContainingLocation(loc);
2808+
if (otherSF == nullptr)
2809+
return false;
28142810

2815-
if (complainLoc.isInvalid()) {
2816-
complainLoc = conformance->getLoc();
2817-
}
2811+
return otherSF->isPrimary();
2812+
});
28182813

2819-
Diags.diagnose(complainLoc,
2820-
diag::type_does_not_conform,
2821-
dc->getSelfInterfaceType(),
2822-
proto->getDeclaredInterfaceType());
2814+
if (complainLoc.isInvalid()) {
2815+
complainLoc = conformance->getLoc();
28232816
}
2817+
2818+
ctx.Diags.diagnose(complainLoc,
2819+
diag::type_does_not_conform,
2820+
dc->getSelfInterfaceType(),
2821+
proto->getDeclaredInterfaceType());
28242822
}
2823+
}
2824+
2825+
void ASTContext::addDelayedConformanceDiag(
2826+
NormalProtocolConformance *conformance, bool isError,
2827+
std::function<void(NormalProtocolConformance *)> callback) {
2828+
if (isError)
2829+
conformance->setInvalid();
2830+
2831+
auto &diagnostics = getImpl().DelayedConformanceDiags[conformance];
2832+
2833+
if (isError)
2834+
maybeEmitFallbackConformanceDiagnostic(*this, conformance, diagnostics);
28252835

28262836
diagnostics.Diags.push_back({isError, callback});
28272837
}
28282838

28292839
void ASTContext::addDelayedMissingWitness(
28302840
NormalProtocolConformance *conformance,
28312841
ASTContext::MissingWitness missingWitness) {
2842+
conformance->setInvalid();
2843+
28322844
auto &diagnostics = getImpl().DelayedConformanceDiags[conformance];
2845+
maybeEmitFallbackConformanceDiagnostic(*this, conformance, diagnostics);
28332846
diagnostics.MissingWitnesses.push_back(missingWitness);
28342847
}
28352848

lib/AST/ASTVerifier.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2803,7 +2803,6 @@ class Verifier : public ASTWalker {
28032803
// Ignore incomplete conformances; we didn't need them.
28042804
return;
28052805

2806-
case ProtocolConformanceState::CheckingTypeWitnesses:
28072806
case ProtocolConformanceState::Checking:
28082807
dumpRef(decl);
28092808
Out << " has a protocol conformance that is still being checked "

lib/AST/ProtocolConformance.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,12 @@ NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
493493

494494
// If this conformance is in a state where it is inferring type witnesses but
495495
// we didn't find anything, fail.
496-
if (getState() == ProtocolConformanceState::CheckingTypeWitnesses) {
496+
//
497+
// FIXME: This is unsound, because we may not have diagnosed anything but
498+
// still end up with an ErrorType in the AST.
499+
if (getDeclContext()->getASTContext().evaluator.hasActiveRequest(
500+
ResolveTypeWitnessesRequest{
501+
const_cast<NormalProtocolConformance *>(this)})) {
497502
return { Type(), nullptr };
498503
}
499504

lib/AST/SubstitutionMap.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,10 +436,13 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
436436
if (!normal->hasComputedAssociatedConformances()) {
437437
// If we're in the process of checking the type witnesses, fail
438438
// gracefully.
439-
// FIXME: Seems like we should be able to get at the intermediate state
440-
// to use that.
441-
if (normal->getState() == ProtocolConformanceState::CheckingTypeWitnesses)
439+
//
440+
// FIXME: This is unsound, because we may not have diagnosed anything but
441+
// still end up with an ErrorType in the AST.
442+
if (proto->getASTContext().evaluator.hasActiveRequest(
443+
ResolveTypeWitnessesRequest{normal})) {
442444
return ProtocolConformanceRef::forInvalid();
445+
}
443446
}
444447

445448
// Get the associated conformance.

0 commit comments

Comments
 (0)