Skip to content

Commit 498ef31

Browse files
committed
Sema: Refactor exportability checking to not use the GenericRequirementsCheckListener
1 parent 769c4c1 commit 498ef31

File tree

1 file changed

+66
-74
lines changed

1 file changed

+66
-74
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 66 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3942,6 +3942,47 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
39423942
return ResolveWitnessResult::ExplicitFailed;
39433943
}
39443944

3945+
static void checkExportability(Type depTy, Type replacementTy,
3946+
const ProtocolConformance *conformance,
3947+
NormalProtocolConformance *conformanceBeingChecked,
3948+
SourceFile *SF) {
3949+
if (!SF)
3950+
return;
3951+
3952+
SubstitutionMap subs =
3953+
conformance->getSubstitutions(SF->getParentModule());
3954+
for (auto &subConformance : subs.getConformances()) {
3955+
if (!subConformance.isConcrete())
3956+
continue;
3957+
checkExportability(depTy, replacementTy, subConformance.getConcrete(),
3958+
conformanceBeingChecked, SF);
3959+
}
3960+
3961+
const RootProtocolConformance *rootConformance =
3962+
conformance->getRootConformance();
3963+
ModuleDecl *M = rootConformance->getDeclContext()->getParentModule();
3964+
if (!SF->isImportedImplementationOnly(M))
3965+
return;
3966+
3967+
ASTContext &ctx = SF->getASTContext();
3968+
3969+
Type selfTy = rootConformance->getProtocol()->getProtocolSelfType();
3970+
if (depTy->isEqual(selfTy)) {
3971+
ctx.Diags.diagnose(
3972+
conformanceBeingChecked->getLoc(),
3973+
diag::conformance_from_implementation_only_module,
3974+
rootConformance->getType(),
3975+
rootConformance->getProtocol()->getName(), 0, M->getName());
3976+
} else {
3977+
ctx.Diags.diagnose(
3978+
conformanceBeingChecked->getLoc(),
3979+
diag::assoc_conformance_from_implementation_only_module,
3980+
rootConformance->getType(),
3981+
rootConformance->getProtocol()->getName(), M->getName(),
3982+
depTy, replacementTy->getCanonicalType());
3983+
}
3984+
}
3985+
39453986
void ConformanceChecker::ensureRequirementsAreSatisfied() {
39463987
Conformance->finishSignatureConformances();
39473988
auto proto = Conformance->getProtocol();
@@ -3956,89 +3997,18 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
39563997
auto substitutions = SubstitutionMap::getProtocolSubstitutions(
39573998
proto, substitutingType, ProtocolConformanceRef(Conformance));
39583999

3959-
SourceFile *fileForCheckingExportability = nullptr;
3960-
if (getRequiredAccessScope().isPublic() || isUsableFromInlineRequired())
3961-
fileForCheckingExportability = DC->getParentSourceFile();
3962-
3963-
class GatherConformancesListener : public GenericRequirementsCheckListener {
3964-
NormalProtocolConformance *conformanceBeingChecked;
3965-
SourceFile *SF;
3966-
3967-
void checkExportability(Type depTy, Type replacementTy,
3968-
const ProtocolConformance *conformance) {
3969-
if (!SF)
3970-
return;
3971-
3972-
SubstitutionMap subs =
3973-
conformance->getSubstitutions(SF->getParentModule());
3974-
for (auto &subConformance : subs.getConformances()) {
3975-
if (!subConformance.isConcrete())
3976-
continue;
3977-
checkExportability(depTy, replacementTy, subConformance.getConcrete());
3978-
}
3979-
3980-
const RootProtocolConformance *rootConformance =
3981-
conformance->getRootConformance();
3982-
ModuleDecl *M = rootConformance->getDeclContext()->getParentModule();
3983-
if (!SF->isImportedImplementationOnly(M))
3984-
return;
3985-
3986-
ASTContext &ctx = M->getASTContext();
3987-
3988-
Type selfTy = rootConformance->getProtocol()->getProtocolSelfType();
3989-
if (depTy->isEqual(selfTy)) {
3990-
ctx.Diags.diagnose(
3991-
conformanceBeingChecked->getLoc(),
3992-
diag::conformance_from_implementation_only_module,
3993-
rootConformance->getType(),
3994-
rootConformance->getProtocol()->getName(), 0, M->getName());
3995-
} else {
3996-
ctx.Diags.diagnose(
3997-
conformanceBeingChecked->getLoc(),
3998-
diag::assoc_conformance_from_implementation_only_module,
3999-
rootConformance->getType(),
4000-
rootConformance->getProtocol()->getName(), M->getName(),
4001-
depTy, replacementTy->getCanonicalType());
4002-
}
4003-
}
4004-
4005-
public:
4006-
GatherConformancesListener(
4007-
NormalProtocolConformance *conformance,
4008-
SourceFile *fileForCheckingExportability)
4009-
: conformanceBeingChecked(conformance),
4010-
SF(fileForCheckingExportability) { }
4011-
4012-
void satisfiedConformance(Type depTy, Type replacementTy,
4013-
ProtocolConformanceRef conformance) override {
4014-
if (conformance.isConcrete())
4015-
checkExportability(depTy, replacementTy, conformance.getConcrete());
4016-
}
4017-
4018-
bool diagnoseUnsatisfiedRequirement(
4019-
const Requirement &req, Type first, Type second,
4020-
ArrayRef<ParentConditionalConformance> parents) override {
4021-
// Invalidate the conformance to suppress further diagnostics.
4022-
if (conformanceBeingChecked->getLoc().isValid()) {
4023-
conformanceBeingChecked->setInvalid();
4024-
}
4025-
4026-
return false;
4027-
}
4028-
} listener(Conformance, fileForCheckingExportability);
4029-
40304000
auto result = TypeChecker::checkGenericArguments(
40314001
DC, Loc, Loc,
40324002
// FIXME: maybe this should be the conformance's type
40334003
proto->getDeclaredInterfaceType(),
40344004
{ proto->getSelfInterfaceType() },
40354005
proto->getRequirementSignature(),
4036-
QuerySubstitutionMap{substitutions},
4037-
&listener);
4006+
QuerySubstitutionMap{substitutions});
40384007

40394008
switch (result) {
40404009
case RequirementCheckResult::Success:
4041-
return;
4010+
// Go on to check exportability.
4011+
break;
40424012

40434013
case RequirementCheckResult::Failure:
40444014
Conformance->setInvalid();
@@ -4054,6 +4024,28 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
40544024
}
40554025
return;
40564026
}
4027+
4028+
// Now check that our associated conformances are at least as visible as
4029+
// the conformance itself.
4030+
//
4031+
// FIXME: Do we need to check SPI here too?
4032+
if (getRequiredAccessScope().isPublic() || isUsableFromInlineRequired()) {
4033+
auto *fileForCheckingExportability = DC->getParentSourceFile();
4034+
4035+
for (auto req : proto->getRequirementSignature()) {
4036+
if (req.getKind() == RequirementKind::Conformance) {
4037+
auto depTy = req.getFirstType();
4038+
auto *proto = req.getSecondType()->castTo<ProtocolType>()->getDecl();
4039+
auto conformance = Conformance->getAssociatedConformance(depTy, proto);
4040+
if (conformance.isConcrete()) {
4041+
auto *concrete = conformance.getConcrete();
4042+
auto replacementTy = DC->mapTypeIntoContext(concrete->getType());
4043+
checkExportability(depTy, replacementTy, concrete,
4044+
Conformance, fileForCheckingExportability);
4045+
}
4046+
}
4047+
}
4048+
}
40574049
}
40584050

40594051
#pragma mark Protocol conformance checking

0 commit comments

Comments
 (0)