Skip to content

Commit 10f53c0

Browse files
committed
[NFC] Refactor getAdopteeSelfSameTypeConstraint
This method performs a linear-ish search over all the generic requirements and tries to pull out a matching written requirement so it can provide a richer diagnostic. Unpack this search, teach it to walk resolved requirements, and clean up the code here.
1 parent a748d8e commit 10f53c0

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,43 +3103,57 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind) {
31033103
///
31043104
/// \returns None if there is no such constraint; a non-empty optional that
31053105
/// may have the \c RequirementRepr for the actual constraint.
3106-
static Optional<RequirementRepr *>
3106+
static Optional<std::pair<RequirementRepr *, Requirement>>
31073107
getAdopteeSelfSameTypeConstraint(ClassDecl *selfClass, ValueDecl *witness) {
31083108
auto genericSig =
31093109
witness->getInnermostDeclContext()->getGenericSignatureOfContext();
31103110
if (!genericSig) return None;
31113111

3112-
for (const auto &req : genericSig->getRequirements()) {
3112+
// First, search for any bogus requirements.
3113+
auto it = llvm::find_if(genericSig->getRequirements(),
3114+
[&selfClass](const auto &req) {
31133115
if (req.getKind() != RequirementKind::SameType)
3114-
continue;
3116+
return false;
31153117

3116-
if (req.getFirstType()->getAnyNominal() == selfClass ||
3117-
req.getSecondType()->getAnyNominal() == selfClass) {
3118-
// Try to find the requirement-as-written.
3119-
GenericParamList *genericParams = nullptr;
3120-
3121-
if (auto func = dyn_cast<AbstractFunctionDecl>(witness))
3122-
genericParams = func->getGenericParams();
3123-
else if (auto subscript = dyn_cast<SubscriptDecl>(witness))
3124-
genericParams = subscript->getGenericParams();
3125-
if (genericParams) {
3126-
for (auto &req : genericParams->getRequirements()) {
3127-
if (req.getKind() != RequirementReprKind::SameType)
3128-
continue;
3118+
return req.getFirstType()->getAnyNominal() == selfClass
3119+
|| req.getSecondType()->getAnyNominal() == selfClass;
3120+
});
3121+
if (it == genericSig->getRequirements().end()) {
3122+
return None;
3123+
}
31293124

3130-
if (req.getFirstType()->getAnyNominal() == selfClass ||
3131-
req.getSecondType()->getAnyNominal() == selfClass)
3132-
return &req;
3133-
}
3134-
}
3125+
// Got it! Now try to find the requirement-as-written.
3126+
GenericParamList *genericParams = nullptr;
3127+
if (auto func = dyn_cast<AbstractFunctionDecl>(witness))
3128+
genericParams = func->getGenericParams();
3129+
else if (auto subscript = dyn_cast<SubscriptDecl>(witness))
3130+
genericParams = subscript->getGenericParams();
31353131

3136-
// Form an optional(nullptr) to indicate that we don't have the
3137-
// requirement itself.
3138-
return nullptr;
3139-
}
3132+
// A null repr indicates we don't have a valid location to diagnose. But
3133+
// at least we have a requirement we can signal is bogus.
3134+
Optional<std::pair<RequirementRepr *, Requirement>> target
3135+
= std::make_pair((RequirementRepr *)nullptr, Requirement(*it));
3136+
if (!genericParams) {
3137+
return target;
31403138
}
31413139

3142-
return None;
3140+
// Resolve and search for a written requirement to match our bogus one.
3141+
WhereClauseOwner(cast<GenericContext>(witness), genericParams)
3142+
.visitRequirements(TypeResolutionStage::Structural,
3143+
[&](Requirement req, RequirementRepr *repr) {
3144+
if (req.getKind() != RequirementKind::SameType) {
3145+
return false;
3146+
}
3147+
3148+
if (req.getFirstType()->getAnyNominal() != selfClass &&
3149+
req.getSecondType()->getAnyNominal() != selfClass) {
3150+
return false;
3151+
}
3152+
3153+
target.emplace(repr, req);
3154+
return true;
3155+
});
3156+
return target;
31433157
}
31443158

31453159
void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
@@ -3239,7 +3253,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
32393253
});
32403254
}
32413255
} else if (selfKind.requirement) {
3242-
if (auto constraint = getAdopteeSelfSameTypeConstraint(classDecl,
3256+
if (auto targetPair = getAdopteeSelfSameTypeConstraint(classDecl,
32433257
witness)) {
32443258
// A "Self ==" constraint works incorrectly with subclasses. Complain.
32453259
auto proto = Conformance->getProtocol();
@@ -3254,11 +3268,11 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
32543268
proto->getDeclaredType());
32553269
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
32563270

3257-
if (auto requirementRepr = *constraint) {
3271+
if (auto requirementRepr = targetPair->first) {
32583272
diags.diagnose(requirementRepr->getSeparatorLoc(),
32593273
diag::witness_self_weaken_same_type,
3260-
requirementRepr->getFirstType(),
3261-
requirementRepr->getSecondType())
3274+
targetPair->second.getFirstType(),
3275+
targetPair->second.getSecondType())
32623276
.fixItReplace(requirementRepr->getSeparatorLoc(), ":");
32633277
}
32643278
}

0 commit comments

Comments
 (0)