AST: Functions nested in exportable functions are also exportable.

Centralize the exportability checking logic for nested functions in the
`DeclExportabilityVisitor` utility. This logic was previously added to SILGen
but there should not be special casing for nested functions at that layer.
This commit is contained in:
Allan Shortlidge
2024-06-28 16:08:35 -07:00
parent 8a40393287
commit d48f949f8c
3 changed files with 26 additions and 18 deletions

View File

@@ -50,6 +50,20 @@ public:
bool visitDecl(const Decl *D) = delete;
bool visitValueDecl(const ValueDecl *valueDecl) = delete;
bool visitAbstractFunctionDecl(const AbstractFunctionDecl *afd) {
// If this function is nested within another function that is exportable to
// clients then it is also exportable.
auto dc = afd->getDeclContext();
do {
if (auto parent = dyn_cast<AbstractFunctionDecl>(dc)) {
if (DeclExportabilityVisitor().visit(parent))
return true;
}
} while ((dc = dc->getParent()));
return false;
}
bool visitExtensionDecl(const ExtensionDecl *ext) {
// Extensions must extend exportable types to be exportable.
auto nominalType = ext->getExtendedNominal();
@@ -135,7 +149,6 @@ public:
DEFAULT_TO_ACCESS_LEVEL(TypeAlias);
DEFAULT_TO_ACCESS_LEVEL(AssociatedType);
DEFAULT_TO_ACCESS_LEVEL(AbstractStorage);
DEFAULT_TO_ACCESS_LEVEL(AbstractFunction);
DEFAULT_TO_ACCESS_LEVEL(Macro);
DEFAULT_TO_ACCESS_LEVEL(EnumElement);

View File

@@ -784,20 +784,6 @@ bool SILGenModule::shouldSkipDecl(Decl *D) {
if (D->isExposedToClients())
return false;
if (isa<AbstractFunctionDecl>(D)) {
// If this function is nested within another function that is exposed to
// clients then it should be emitted.
auto dc = D->getDeclContext();
do {
if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
if (afd->isExposedToClients())
return false;
} while ((dc = dc->getParent()));
// We didn't find a parent function that is exposed.
return true;
}
return true;
}

View File

@@ -70,11 +70,20 @@ public struct PublicStruct {
// SAFETY-PRIVATE: Serialization safety, unsafe: 'init(fileprivateInit:)'
@inlinable public func inlinableFunc() {
typealias localTypealias = Int
}
// SAFETY-PRIVATE: Serialization safety, safe: 'inlinableFunc()'
public func publicFunc() {}
typealias localTypealias = Int
func inlinableFunc_nested() {}
// SAFETY-PRIVATE-NOT: inlinableFunc_nested()
inlinableFunc_nested()
}
public func publicFunc() {
// SAFETY-PRIVATE: Serialization safety, safe: 'publicFunc()'
func publicFunc_nested() {}
// SAFETY-PRIVATE-NOT: publicFunc_nested()
publicFunc_nested()
}
@available(SwiftStdlib 5.1, *) // for the `some` keyword.
public func opaqueTypeFunc() -> some PublicProto {