@@ -3942,6 +3942,47 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
3942
3942
return ResolveWitnessResult::ExplicitFailed;
3943
3943
}
3944
3944
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
+
3945
3986
void ConformanceChecker::ensureRequirementsAreSatisfied () {
3946
3987
Conformance->finishSignatureConformances ();
3947
3988
auto proto = Conformance->getProtocol ();
@@ -3956,89 +3997,18 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
3956
3997
auto substitutions = SubstitutionMap::getProtocolSubstitutions (
3957
3998
proto, substitutingType, ProtocolConformanceRef (Conformance));
3958
3999
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
-
4030
4000
auto result = TypeChecker::checkGenericArguments (
4031
4001
DC, Loc, Loc,
4032
4002
// FIXME: maybe this should be the conformance's type
4033
4003
proto->getDeclaredInterfaceType (),
4034
4004
{ proto->getSelfInterfaceType () },
4035
4005
proto->getRequirementSignature (),
4036
- QuerySubstitutionMap{substitutions},
4037
- &listener);
4006
+ QuerySubstitutionMap{substitutions});
4038
4007
4039
4008
switch (result) {
4040
4009
case RequirementCheckResult::Success:
4041
- return ;
4010
+ // Go on to check exportability.
4011
+ break ;
4042
4012
4043
4013
case RequirementCheckResult::Failure:
4044
4014
Conformance->setInvalid ();
@@ -4054,6 +4024,28 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
4054
4024
}
4055
4025
return ;
4056
4026
}
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
+ }
4057
4049
}
4058
4050
4059
4051
#pragma mark Protocol conformance checking
0 commit comments