Skip to content

Commit ff9b541

Browse files
committed
AST/Sema: Sink isExported() queries from Sema to AST.
1 parent e33bf2a commit ff9b541

File tree

6 files changed

+102
-99
lines changed

6 files changed

+102
-99
lines changed

include/swift/AST/DeclExportabilityVisitor.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,18 @@ class DeclExportabilityVisitor
178178

179179
#undef UNINTERESTING
180180
};
181+
182+
/// Check if a declaration is exported as part of a module's external interface.
183+
/// This includes public and @usableFromInline decls.
184+
/// FIXME: This is legacy that should be subsumed by `DeclExportabilityVisitor`
185+
bool isExported(const Decl *D);
186+
187+
/// A specialization of `isExported` for `ValueDecl`.
188+
bool isExported(const ValueDecl *VD);
189+
190+
/// A specialization of `isExported` for `ExtensionDecl`.
191+
bool isExported(const ExtensionDecl *ED);
192+
181193
} // end namespace swift
182194

183195
#endif

lib/AST/Availability.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/AvailabilityInference.h"
2323
#include "swift/AST/AvailabilityRange.h"
2424
#include "swift/AST/Decl.h"
25+
#include "swift/AST/DeclExportabilityVisitor.h"
2526
// FIXME: [availability] Remove this when possible
2627
#include "swift/AST/DiagnosticsParse.h"
2728
#include "swift/AST/DiagnosticsSema.h"
@@ -1082,3 +1083,85 @@ swift::abstractSyntaxDeclForAvailableAttribute(const Decl *ConcreteSyntaxDecl) {
10821083

10831084
return ConcreteSyntaxDecl;
10841085
}
1086+
1087+
bool swift::isExported(const Decl *D) {
1088+
if (auto *VD = dyn_cast<ValueDecl>(D)) {
1089+
return isExported(VD);
1090+
}
1091+
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
1092+
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
1093+
if (auto *VD = PBD->getAnchoringVarDecl(i))
1094+
return isExported(VD);
1095+
}
1096+
1097+
return false;
1098+
}
1099+
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
1100+
return isExported(ED);
1101+
}
1102+
1103+
return true;
1104+
}
1105+
1106+
bool swift::isExported(const ValueDecl *VD) {
1107+
if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
1108+
return false;
1109+
if (VD->isObjCMemberImplementation())
1110+
return false;
1111+
1112+
// Is this part of the module's API or ABI?
1113+
AccessScope accessScope =
1114+
VD->getFormalAccessScope(nullptr,
1115+
/*treatUsableFromInlineAsPublic*/ true);
1116+
if (accessScope.isPublic())
1117+
return true;
1118+
1119+
// Is this a stored property in a @frozen struct or class?
1120+
if (auto *property = dyn_cast<VarDecl>(VD))
1121+
if (property->isLayoutExposedToClients())
1122+
return true;
1123+
1124+
return false;
1125+
}
1126+
1127+
static bool hasConformancesToPublicProtocols(const ExtensionDecl *ED) {
1128+
auto nominal = ED->getExtendedNominal();
1129+
if (!nominal)
1130+
return false;
1131+
1132+
// Extensions of protocols cannot introduce additional conformances.
1133+
if (isa<ProtocolDecl>(nominal))
1134+
return false;
1135+
1136+
auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit);
1137+
for (const ProtocolDecl *PD : protocols) {
1138+
AccessScope scope =
1139+
PD->getFormalAccessScope(/*useDC*/ nullptr,
1140+
/*treatUsableFromInlineAsPublic*/ true);
1141+
if (scope.isPublic())
1142+
return true;
1143+
}
1144+
1145+
return false;
1146+
}
1147+
1148+
bool swift::isExported(const ExtensionDecl *ED) {
1149+
// An extension can only be exported if it extends an exported type.
1150+
if (auto *NTD = ED->getExtendedNominal()) {
1151+
if (!isExported(NTD))
1152+
return false;
1153+
}
1154+
1155+
// If there are any exported members then the extension is exported.
1156+
for (const Decl *D : ED->getMembers()) {
1157+
if (isExported(D))
1158+
return true;
1159+
}
1160+
1161+
// If the extension declares a conformance to a public protocol then the
1162+
// extension is exported.
1163+
if (hasConformancesToPublicProtocols(ED))
1164+
return true;
1165+
1166+
return false;
1167+
}

lib/Sema/TypeCheckAccess.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
#include "TypeCheckAccess.h"
1818
#include "TypeAccessScopeChecker.h"
1919
#include "TypeCheckAvailability.h"
20-
#include "TypeChecker.h"
2120
#include "TypeCheckUnsafe.h"
21+
#include "TypeChecker.h"
2222
#include "swift/AST/ASTVisitor.h"
2323
#include "swift/AST/ASTWalker.h"
2424
#include "swift/AST/ClangModuleLoader.h"
25+
#include "swift/AST/DeclExportabilityVisitor.h"
2526
#include "swift/AST/DiagnosticsSema.h"
2627
#include "swift/AST/ExistentialLayout.h"
2728
#include "swift/AST/Import.h"

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/AST/AvailabilityScope.h"
2929
#include "swift/AST/AvailabilitySpec.h"
3030
#include "swift/AST/ClangModuleLoader.h"
31+
#include "swift/AST/DeclExportabilityVisitor.h"
3132
#include "swift/AST/DiagnosticsParse.h"
3233
#include "swift/AST/GenericEnvironment.h"
3334
#include "swift/AST/Initializer.h"
@@ -97,88 +98,6 @@ ExportContext::ExportContext(DeclContext *DC,
9798
Reason = unsigned(ExportabilityReason::General);
9899
}
99100

100-
bool swift::isExported(const ValueDecl *VD) {
101-
if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
102-
return false;
103-
if (VD->isObjCMemberImplementation())
104-
return false;
105-
106-
// Is this part of the module's API or ABI?
107-
AccessScope accessScope =
108-
VD->getFormalAccessScope(nullptr,
109-
/*treatUsableFromInlineAsPublic*/true);
110-
if (accessScope.isPublic())
111-
return true;
112-
113-
// Is this a stored property in a @frozen struct or class?
114-
if (auto *property = dyn_cast<VarDecl>(VD))
115-
if (property->isLayoutExposedToClients())
116-
return true;
117-
118-
return false;
119-
}
120-
121-
static bool hasConformancesToPublicProtocols(const ExtensionDecl *ED) {
122-
auto nominal = ED->getExtendedNominal();
123-
if (!nominal)
124-
return false;
125-
126-
// Extensions of protocols cannot introduce additional conformances.
127-
if (isa<ProtocolDecl>(nominal))
128-
return false;
129-
130-
auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit);
131-
for (const ProtocolDecl *PD : protocols) {
132-
AccessScope scope =
133-
PD->getFormalAccessScope(/*useDC*/ nullptr,
134-
/*treatUsableFromInlineAsPublic*/ true);
135-
if (scope.isPublic())
136-
return true;
137-
}
138-
139-
return false;
140-
}
141-
142-
bool swift::isExported(const ExtensionDecl *ED) {
143-
// An extension can only be exported if it extends an exported type.
144-
if (auto *NTD = ED->getExtendedNominal()) {
145-
if (!isExported(NTD))
146-
return false;
147-
}
148-
149-
// If there are any exported members then the extension is exported.
150-
for (const Decl *D : ED->getMembers()) {
151-
if (isExported(D))
152-
return true;
153-
}
154-
155-
// If the extension declares a conformance to a public protocol then the
156-
// extension is exported.
157-
if (hasConformancesToPublicProtocols(ED))
158-
return true;
159-
160-
return false;
161-
}
162-
163-
bool swift::isExported(const Decl *D) {
164-
if (auto *VD = dyn_cast<ValueDecl>(D)) {
165-
return isExported(VD);
166-
}
167-
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
168-
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
169-
if (auto *VD = PBD->getAnchoringVarDecl(i))
170-
return isExported(VD);
171-
}
172-
173-
return false;
174-
}
175-
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
176-
return isExported(ED);
177-
}
178-
179-
return true;
180-
}
181-
182101
template<typename Fn>
183102
static void forEachOuterDecl(DeclContext *DC, Fn fn) {
184103
for (; !DC->isModuleScopeContext(); DC = DC->getParent()) {
@@ -4803,12 +4722,7 @@ void swift::checkExplicitAvailability(Decl *decl) {
48034722
!isa<ExtensionDecl>(decl->getDeclContext())) return;
48044723

48054724
if (auto extension = dyn_cast<ExtensionDecl>(decl)) {
4806-
// decl should be either a ValueDecl or an ExtensionDecl.
4807-
auto extended = extension->getExtendedNominal();
4808-
if (!extended || !extended->getFormalAccessScope().isPublic())
4809-
return;
4810-
4811-
// Skip extensions without public members or conformances.
4725+
// Skip extensions when none of their members need availability.
48124726
auto members = extension->getMembers();
48134727
auto hasMembers = std::any_of(members.begin(), members.end(),
48144728
[](const Decl *D) -> bool {
@@ -4818,10 +4732,8 @@ void swift::checkExplicitAvailability(Decl *decl) {
48184732
return false;
48194733
});
48204734

4821-
auto hasProtocols = hasConformancesToPublicProtocols(extension);
4822-
4823-
if (!hasMembers && !hasProtocols) return;
4824-
4735+
if (!hasMembers && !isExported(extension))
4736+
return;
48254737
} else if (auto pbd = dyn_cast<PatternBindingDecl>(decl)) {
48264738
// Check the first var instead.
48274739
if (pbd->getNumPatternEntries() == 0)

lib/Sema/TypeCheckAvailability.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,6 @@ class ExportContext {
202202
std::optional<ExportabilityReason> getExportabilityReason() const;
203203
};
204204

205-
/// Check if a declaration is exported as part of a module's external interface.
206-
/// This includes public and @usableFromInline decls.
207-
bool isExported(const ValueDecl *VD);
208-
bool isExported(const ExtensionDecl *ED);
209-
bool isExported(const Decl *D);
210-
211205
/// Diagnose uses of unavailable declarations in expressions.
212206
void diagnoseExprAvailability(const Expr *E, DeclContext *DC);
213207

lib/Sema/TypeCheckStorage.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/AST/ASTWalker.h"
2727
#include "swift/AST/AvailabilityInference.h"
2828
#include "swift/AST/ConformanceLookup.h"
29+
#include "swift/AST/DeclExportabilityVisitor.h"
2930
#include "swift/AST/DiagnosticsParse.h"
3031
#include "swift/AST/DiagnosticsSema.h"
3132
#include "swift/AST/Expr.h"

0 commit comments

Comments
 (0)