Skip to content

Commit 0ea1367

Browse files
committed
Sema: Refactoring in preparation for conformance availability checking
Today, we check conformance exportability in two places: 1) For inlinable function bodies: in availability checking 2) For types in inlinable declaration signatures: in availability checking 3) For types in non-inlinable declaration signatures: in ExportabilityChecker I want to merge 2) and 3) together, and also generalize the conformance exportability check to check conformance availability as well. This is a preliminary refactoring towards achieving this goal.
1 parent 0c51dda commit 0ea1367

6 files changed

+258
-134
lines changed

lib/Sema/ResilienceDiagnostics.cpp

+59-74
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@
2727

2828
using namespace swift;
2929

30-
/// A uniquely-typed boolean to reduce the chances of accidentally inverting
31-
/// a check.
32-
enum class DowngradeToWarning: bool {
33-
No,
34-
Yes
35-
};
36-
3730
bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
3831
ConcreteDeclRef declRef,
3932
const DeclContext *DC,
@@ -55,16 +48,17 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
5548
// Skip this check for accessors because the associated property or subscript
5649
// will also be checked, and will provide a better error message.
5750
if (!isa<AccessorDecl>(D))
58-
if (diagnoseDeclRefExportability(loc, declRef, DC, Kind))
51+
if (diagnoseDeclRefExportability(loc, declRef, DC,
52+
None, Kind))
5953
return true;
6054

6155
return false;
6256
}
6357

6458
bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
65-
const ValueDecl *D,
66-
const DeclContext *DC,
67-
FragileFunctionKind Kind) {
59+
const ValueDecl *D,
60+
const DeclContext *DC,
61+
FragileFunctionKind Kind) {
6862
assert(Kind.kind != FragileFunctionKind::None);
6963

7064
// Local declarations are OK.
@@ -150,96 +144,87 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
150144
static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
151145
const SourceFile &userSF,
152146
const DeclContext *userDC,
147+
Optional<ExportabilityReason> reason,
153148
FragileFunctionKind fragileKind) {
154-
assert(fragileKind.kind != FragileFunctionKind::None);
149+
if (fragileKind.kind == FragileFunctionKind::None && !reason.hasValue())
150+
return false;
155151

156152
auto definingModule = D->getModuleContext();
157153

154+
auto downgradeToWarning = DowngradeToWarning::No;
158155
auto originKind = getDisallowedOriginKind(
159-
D, userSF, userDC->getInnermostDeclarationDeclContext());
156+
D, userSF, userDC->getInnermostDeclarationDeclContext(),
157+
downgradeToWarning);
160158
if (originKind == DisallowedOriginKind::None)
161159
return false;
162160

163-
// TODO: different diagnostics
164161
ASTContext &ctx = definingModule->getASTContext();
165-
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_from_hidden_module,
166-
D->getDescriptiveKind(), D->getName(),
167-
static_cast<unsigned>(fragileKind.kind),
168-
definingModule->getName(),
169-
static_cast<unsigned>(originKind));
170-
return true;
171-
}
172162

173-
static bool
174-
diagnoseGenericArgumentsExportability(SourceLoc loc,
175-
SubstitutionMap subs,
176-
const SourceFile &userSF,
177-
const DeclContext *userDC) {
178-
bool hadAnyIssues = false;
179-
for (ProtocolConformanceRef conformance : subs.getConformances()) {
180-
if (!conformance.isConcrete())
181-
continue;
182-
const ProtocolConformance *concreteConf = conformance.getConcrete();
183-
184-
SubstitutionMap subConformanceSubs =
185-
concreteConf->getSubstitutions(userSF.getParentModule());
186-
diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF, userDC);
187-
188-
const RootProtocolConformance *rootConf =
189-
concreteConf->getRootConformance();
190-
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
191-
192-
auto originKind = getDisallowedOriginKind(
193-
rootConf->getDeclContext()->getAsDecl(),
194-
userSF, userDC->getInnermostDeclarationDeclContext());
195-
if (originKind == DisallowedOriginKind::None)
196-
continue;
197-
198-
ASTContext &ctx = M->getASTContext();
199-
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
200-
rootConf->getType(),
201-
rootConf->getProtocol()->getName(), 0, M->getName(),
163+
if (fragileKind.kind == FragileFunctionKind::None) {
164+
auto errorOrWarning = downgradeToWarning == DowngradeToWarning::Yes?
165+
diag::decl_from_hidden_module_warn:
166+
diag::decl_from_hidden_module;
167+
ctx.Diags.diagnose(loc, errorOrWarning,
168+
D->getDescriptiveKind(),
169+
D->getName(),
170+
static_cast<unsigned>(*reason),
171+
definingModule->getName(),
172+
static_cast<unsigned>(originKind));
173+
174+
D->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
175+
} else {
176+
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_from_hidden_module,
177+
D->getDescriptiveKind(), D->getName(),
178+
static_cast<unsigned>(fragileKind.kind),
179+
definingModule->getName(),
202180
static_cast<unsigned>(originKind));
203-
hadAnyIssues = true;
204181
}
205-
return hadAnyIssues;
182+
return true;
206183
}
207184

208-
void TypeChecker::diagnoseGenericTypeExportability(SourceLoc Loc, Type T,
209-
const DeclContext *DC) {
210-
const SourceFile *SF = DC->getParentSourceFile();
211-
if (!SF)
212-
return;
213-
214-
// FIXME: It would be nice to highlight just the part of the type that's
215-
// problematic, but unfortunately the TypeRepr doesn't have the
216-
// information we need and the Type doesn't easily map back to it.
217-
if (auto *BGT = dyn_cast<BoundGenericType>(T.getPointer())) {
218-
ModuleDecl *useModule = SF->getParentModule();
219-
auto subs = T->getContextSubstitutionMap(useModule, BGT->getDecl());
220-
(void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC);
221-
} else if (auto *TAT = dyn_cast<TypeAliasType>(T.getPointer())) {
222-
auto subs = TAT->getSubstitutionMap();
223-
(void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC);
224-
}
185+
bool
186+
TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
187+
const RootProtocolConformance *rootConf,
188+
const SourceFile &userSF,
189+
const DeclContext *userDC,
190+
Optional<ExportabilityReason> reason,
191+
FragileFunctionKind fragileKind) {
192+
if (fragileKind.kind == FragileFunctionKind::None && !reason.hasValue())
193+
return false;
194+
195+
auto originKind = getDisallowedOriginKind(
196+
rootConf->getDeclContext()->getAsDecl(),
197+
userSF, userDC->getInnermostDeclarationDeclContext());
198+
if (originKind == DisallowedOriginKind::None)
199+
return false;
200+
201+
if (!reason.hasValue())
202+
reason = ExportabilityReason::General;
203+
204+
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
205+
ASTContext &ctx = M->getASTContext();
206+
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
207+
rootConf->getType(),
208+
rootConf->getProtocol()->getName(),
209+
static_cast<unsigned>(*reason),
210+
M->getName(),
211+
static_cast<unsigned>(originKind));
212+
return true;
225213
}
226214

227215
bool
228216
TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
229217
ConcreteDeclRef declRef,
230218
const DeclContext *DC,
219+
Optional<ExportabilityReason> reason,
231220
FragileFunctionKind fragileKind) {
232221
// We're only interested in diagnosing uses from source files.
233222
auto userSF = DC->getParentSourceFile();
234223
if (!userSF)
235224
return false;
236225

237226
const ValueDecl *D = declRef.getDecl();
238-
if (diagnoseDeclExportability(loc, D, *userSF, DC, fragileKind))
239-
return true;
240-
if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(),
241-
*userSF, DC)) {
227+
if (diagnoseDeclExportability(loc, D, *userSF, DC, reason, fragileKind))
242228
return true;
243-
}
244229
return false;
245230
}

lib/Sema/TypeCheckAccess.cpp

+17-16
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,6 @@ using namespace swift;
3535

3636
namespace {
3737

38-
/// A uniquely-typed boolean to reduce the chances of accidentally inverting
39-
/// a check.
40-
///
41-
/// \see checkTypeAccess
42-
enum class DowngradeToWarning: bool {
43-
No,
44-
Yes
45-
};
46-
4738
/// Calls \p callback for each type in each requirement provided by
4839
/// \p source.
4940
static void forAllRequirementTypes(
@@ -1464,15 +1455,17 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
14641455
}
14651456
};
14661457

1458+
} // end anonymous namespace
1459+
14671460
/// Returns the kind of origin, implementation-only import or SPI declaration,
14681461
/// that restricts exporting \p decl from the given file and context.
14691462
///
14701463
/// Local variant to swift::getDisallowedOriginKind for downgrade to warnings.
14711464
DisallowedOriginKind
1472-
getDisallowedOriginKind(const Decl *decl,
1473-
const SourceFile &userSF,
1474-
const Decl *userContext,
1475-
DowngradeToWarning &downgradeToWarning) {
1465+
swift::getDisallowedOriginKind(const Decl *decl,
1466+
const SourceFile &userSF,
1467+
const Decl *userContext,
1468+
DowngradeToWarning &downgradeToWarning) {
14761469
downgradeToWarning = DowngradeToWarning::No;
14771470
ModuleDecl *M = decl->getModuleContext();
14781471
if (userSF.isImportedImplementationOnly(M)) {
@@ -1493,6 +1486,8 @@ getDisallowedOriginKind(const Decl *decl,
14931486
return DisallowedOriginKind::None;
14941487
};
14951488

1489+
namespace {
1490+
14961491
// Diagnose public APIs exposing types that are either imported as
14971492
// implementation-only or declared as SPI.
14981493
class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
@@ -2015,6 +2010,8 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
20152010
/// Diagnose declarations whose signatures refer to unavailable types.
20162011
class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
20172012
DeclContext *DC;
2013+
Optional<ExportabilityReason> ExportReason;
2014+
FragileFunctionKind FragileKind;
20182015

20192016
void checkType(Type type, const TypeRepr *typeRepr, const Decl *context,
20202017
bool allowUnavailableProtocol=false) {
@@ -2036,12 +2033,14 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
20362033
if (allowUnavailableProtocol)
20372034
flags |= DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol;
20382035

2039-
diagnoseTypeReprAvailability(typeRepr, DC, flags);
2036+
diagnoseTypeReprAvailability(typeRepr, DC, ExportReason, FragileKind,
2037+
flags);
20402038
}
20412039

20422040
// Check the type for references to unavailable conformances.
20432041
if (type)
2044-
diagnoseTypeAvailability(type, context->getLoc(), DC);
2042+
diagnoseTypeAvailability(type, context->getLoc(), DC,
2043+
ExportReason, FragileKind);
20452044
}
20462045

20472046
void checkGenericParams(const GenericContext *ownerCtx,
@@ -2070,7 +2069,9 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
20702069

20712070
public:
20722071
explicit DeclAvailabilityChecker(Decl *D)
2073-
: DC(D->getInnermostDeclContext()) {}
2072+
: DC(D->getInnermostDeclContext()) {
2073+
FragileKind = DC->getFragileFunctionKind();
2074+
}
20742075

20752076
void visit(Decl *D) {
20762077
if (D->isImplicit())

lib/Sema/TypeCheckAccess.h

+14
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,26 @@ enum class DisallowedOriginKind : uint8_t {
4343
None
4444
};
4545

46+
/// A uniquely-typed boolean to reduce the chances of accidentally inverting
47+
/// a check.
48+
///
49+
/// \see checkTypeAccess
50+
enum class DowngradeToWarning: bool {
51+
No,
52+
Yes
53+
};
54+
4655
/// Returns the kind of origin, implementation-only import or SPI declaration,
4756
/// that restricts exporting \p decl from the given file and context.
4857
DisallowedOriginKind getDisallowedOriginKind(const Decl *decl,
4958
const SourceFile &userSF,
5059
const Decl *userContext);
5160

61+
DisallowedOriginKind getDisallowedOriginKind(const Decl *decl,
62+
const SourceFile &userSF,
63+
const Decl *userContext,
64+
DowngradeToWarning &downgradeToWarning);
65+
5266
} // end namespace swift
5367

5468
#endif

0 commit comments

Comments
 (0)