Skip to content

Commit 3044c05

Browse files
committed
Sema: Wrap up some availability-related state in a new ExportContext type
The ExportContext describes the restrictions, if any, on what declarations can be uttered in a specific place in the program. Here, the place is either the signature of a declaration, or the body of a function.
1 parent 9f08ab3 commit 3044c05

6 files changed

+247
-228
lines changed

lib/Sema/ResilienceDiagnostics.cpp

+29-24
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ using namespace swift;
2929

3030
bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
3131
const ValueDecl *D,
32-
const DeclContext *DC,
33-
FragileFunctionKind Kind) {
34-
assert(Kind.kind != FragileFunctionKind::None);
32+
ExportContext where) {
33+
auto fragileKind = where.getFragileFunctionKind();
34+
if (fragileKind.kind == FragileFunctionKind::None)
35+
return false;
3536

3637
// Do some important fast-path checks that apply to all cases.
3738

@@ -40,33 +41,33 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
4041
return false;
4142

4243
// Check whether the declaration is accessible.
43-
if (diagnoseInlinableDeclRefAccess(loc, D, DC, Kind))
44+
if (diagnoseInlinableDeclRefAccess(loc, D, where))
4445
return true;
4546

4647
// Check whether the declaration comes from a publically-imported module.
4748
// Skip this check for accessors because the associated property or subscript
4849
// will also be checked, and will provide a better error message.
4950
if (!isa<AccessorDecl>(D))
50-
if (diagnoseDeclRefExportability(loc, D, DC,
51-
None, Kind))
51+
if (diagnoseDeclRefExportability(loc, D, where))
5252
return true;
5353

5454
return false;
5555
}
5656

5757
bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
5858
const ValueDecl *D,
59-
const DeclContext *DC,
60-
FragileFunctionKind Kind) {
61-
assert(Kind.kind != FragileFunctionKind::None);
59+
ExportContext where) {
60+
auto *DC = where.getDeclContext();
61+
auto fragileKind = where.getFragileFunctionKind();
62+
assert(fragileKind.kind != FragileFunctionKind::None);
6263

6364
// Local declarations are OK.
6465
if (D->getDeclContext()->isLocalContext())
6566
return false;
6667

6768
// Public declarations or SPI used from SPI are OK.
6869
if (D->getFormalAccessScope(/*useDC=*/nullptr,
69-
Kind.allowUsableFromInline).isPublic() &&
70+
fragileKind.allowUsableFromInline).isPublic() &&
7071
!(D->isSPI() && !DC->getInnermostDeclarationDeclContext()->isSPI()))
7172
return false;
7273

@@ -126,10 +127,10 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
126127
loc, diagID,
127128
D->getDescriptiveKind(), diagName,
128129
D->getFormalAccessScope().accessLevelForDiagnostics(),
129-
static_cast<unsigned>(Kind.kind),
130+
static_cast<unsigned>(fragileKind.kind),
130131
isAccessor);
131132

132-
if (Kind.allowUsableFromInline) {
133+
if (fragileKind.allowUsableFromInline) {
133134
Context.Diags.diagnose(D, diag::resilience_decl_declared_here,
134135
D->getDescriptiveKind(), diagName, isAccessor);
135136
} else {
@@ -143,15 +144,15 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
143144
bool
144145
TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
145146
const ValueDecl *D,
146-
const DeclContext *DC,
147-
Optional<ExportabilityReason> reason,
148-
FragileFunctionKind fragileKind) {
149-
if (fragileKind.kind == FragileFunctionKind::None && !reason.hasValue())
147+
ExportContext where) {
148+
if (!where.mustOnlyReferenceExportedDecls())
150149
return false;
151150

152151
auto definingModule = D->getModuleContext();
153152

154153
auto downgradeToWarning = DowngradeToWarning::No;
154+
155+
auto *DC = where.getDeclContext();
155156
auto originKind = getDisallowedOriginKind(
156157
D,
157158
*DC->getParentSourceFile(),
@@ -162,6 +163,9 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
162163

163164
ASTContext &ctx = definingModule->getASTContext();
164165

166+
auto fragileKind = where.getFragileFunctionKind();
167+
auto reason = where.getExportabilityReason();
168+
165169
if (fragileKind.kind == FragileFunctionKind::None) {
166170
auto errorOrWarning = downgradeToWarning == DowngradeToWarning::Yes?
167171
diag::decl_from_hidden_module_warn:
@@ -187,24 +191,25 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
187191
bool
188192
TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
189193
const RootProtocolConformance *rootConf,
190-
const SourceFile &userSF,
191-
const DeclContext *userDC,
192-
Optional<ExportabilityReason> reason,
193-
FragileFunctionKind fragileKind) {
194-
if (fragileKind.kind == FragileFunctionKind::None && !reason.hasValue())
194+
ExportContext where) {
195+
if (!where.mustOnlyReferenceExportedDecls())
195196
return false;
196197

198+
auto *DC = where.getDeclContext();
197199
auto originKind = getDisallowedOriginKind(
198200
rootConf->getDeclContext()->getAsDecl(),
199-
userSF, userDC->getInnermostDeclarationDeclContext());
201+
*DC->getParentSourceFile(),
202+
DC->getInnermostDeclarationDeclContext());
200203
if (originKind == DisallowedOriginKind::None)
201204
return false;
202205

206+
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
207+
ASTContext &ctx = M->getASTContext();
208+
209+
auto reason = where.getExportabilityReason();
203210
if (!reason.hasValue())
204211
reason = ExportabilityReason::General;
205212

206-
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
207-
ASTContext &ctx = M->getASTContext();
208213
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
209214
rootConf->getType(),
210215
rootConf->getProtocol()->getName(),

lib/Sema/TypeCheckAccess.cpp

+8-67
Original file line numberDiff line numberDiff line change
@@ -1483,63 +1483,11 @@ swift::getDisallowedOriginKind(const Decl *decl,
14831483
return DisallowedOriginKind::None;
14841484
};
14851485

1486-
static bool isExported(const ValueDecl *VD) {
1487-
if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
1488-
return false;
1489-
1490-
// Is this part of the module's API or ABI?
1491-
AccessScope accessScope =
1492-
VD->getFormalAccessScope(nullptr,
1493-
/*treatUsableFromInlineAsPublic*/true);
1494-
if (accessScope.isPublic())
1495-
return true;
1496-
1497-
// Is this a stored property in a non-resilient struct or class?
1498-
auto *property = dyn_cast<VarDecl>(VD);
1499-
if (!property || !property->hasStorage() || property->isStatic())
1500-
return false;
1501-
auto *parentNominal = dyn_cast<NominalTypeDecl>(property->getDeclContext());
1502-
if (!parentNominal || parentNominal->isResilient())
1503-
return false;
1504-
1505-
// Is that struct or class part of the module's API or ABI?
1506-
AccessScope parentAccessScope = parentNominal->getFormalAccessScope(
1507-
nullptr, /*treatUsableFromInlineAsPublic*/true);
1508-
if (parentAccessScope.isPublic())
1509-
return true;
1510-
1511-
return false;
1512-
}
1513-
1514-
static bool isExported(Decl *D) {
1515-
if (auto *VD = dyn_cast<ValueDecl>(D)) {
1516-
return isExported(VD);
1517-
}
1518-
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
1519-
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
1520-
if (auto *VD = PBD->getAnchoringVarDecl(i))
1521-
return isExported(VD);
1522-
}
1523-
1524-
return false;
1525-
}
1526-
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
1527-
if (auto *NTD = ED->getExtendedNominal())
1528-
return isExported(NTD);
1529-
1530-
return false;
1531-
}
1532-
1533-
return true;
1534-
}
1535-
15361486
namespace {
15371487

15381488
/// Diagnose declarations whose signatures refer to unavailable types.
15391489
class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
1540-
DeclContext *DC;
1541-
FragileFunctionKind FragileKind;
1542-
bool Exported;
1490+
ExportContext Where;
15431491

15441492
void checkType(Type type, const TypeRepr *typeRepr, const Decl *context,
15451493
ExportabilityReason reason=ExportabilityReason::General,
@@ -1548,10 +1496,6 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
15481496
if (type && type->hasError())
15491497
return;
15501498

1551-
Optional<ExportabilityReason> optReason;
1552-
if (Exported)
1553-
optReason = reason;
1554-
15551499
DeclAvailabilityFlags flags = None;
15561500

15571501
// We allow a type to conform to a protocol that is less available than
@@ -1568,8 +1512,8 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
15681512
if (auto *varDecl = dyn_cast<VarDecl>(context))
15691513
loc = varDecl->getNameLoc();
15701514

1571-
diagnoseTypeAvailability(typeRepr, type, loc, DC,
1572-
optReason, FragileKind, flags);
1515+
diagnoseTypeAvailability(typeRepr, type, loc,
1516+
Where.forReason(reason), flags);
15731517
}
15741518

15751519
void checkGenericParams(const GenericContext *ownerCtx,
@@ -1598,10 +1542,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
15981542

15991543
public:
16001544
explicit DeclAvailabilityChecker(Decl *D)
1601-
: DC(D->getInnermostDeclContext()) {
1602-
FragileKind = DC->getFragileFunctionKind();
1603-
Exported = isExported(D);
1604-
}
1545+
: Where(ExportContext::forDeclSignature(D)) {}
16051546

16061547
// Force all kinds to be handled at a lower level.
16071548
void visitDecl(Decl *D) = delete;
@@ -1798,7 +1739,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
17981739
/*allowUnavailableProtocol=*/true);
17991740
});
18001741

1801-
bool wasExported = Exported;
1742+
auto wasWhere = Where;
18021743

18031744
// 2) If the extension contains exported members, the as-written
18041745
// extended type should be exportable.
@@ -1810,14 +1751,14 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
18101751
return isExported(valueMember);
18111752
});
18121753

1813-
Exported = wasExported && hasExportedMembers;
1754+
Where = wasWhere.forExported(hasExportedMembers);
18141755
checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), ED,
18151756
ExportabilityReason::ExtensionWithPublicMembers);
18161757

18171758
// 3) If the extension contains exported members or defines conformances,
18181759
// the 'where' clause must only name exported types.
1819-
Exported = wasExported && (hasExportedMembers ||
1820-
!ED->getInherited().empty());
1760+
Where = wasWhere.forExported(hasExportedMembers ||
1761+
!ED->getInherited().empty());
18211762
checkConstrainedExtensionRequirements(ED, hasExportedMembers);
18221763
}
18231764

0 commit comments

Comments
 (0)