[Serialization] Tweaks to deserialization safety writer logic

Apply reviewers comments and fix test.
This commit is contained in:
Alexis Laferrière
2023-01-19 09:29:53 -08:00
parent 77d8c464df
commit a91bb4965a
2 changed files with 12 additions and 12 deletions

View File

@@ -3099,22 +3099,20 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
/// XRef errors and such. /// XRef errors and such.
/// ///
/// \p decl should be either an \c ExtensionDecl or a \c ValueDecl. /// \p decl should be either an \c ExtensionDecl or a \c ValueDecl.
static bool declIsDeserializationSafe(const Decl *decl) { static bool isDeserializationSafe(const Decl *decl) {
if (auto ext = dyn_cast<ExtensionDecl>(decl)) { if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
// Consider extensions as safe as their extended type. // Consider extensions as safe as their extended type.
auto nominalType = ext->getExtendedNominal(); auto nominalType = ext->getExtendedNominal();
if (!nominalType || if (!nominalType ||
!declIsDeserializationSafe(nominalType)) !isDeserializationSafe(nominalType))
return false; return false;
// We can mark the extension unsafe only if it has no public members. // We can mark the extension unsafe only if it has no public members.
auto members = ext->getMembers(); auto members = ext->getMembers();
int membersCount = 0;
auto hasSafeMembers = std::any_of(members.begin(), members.end(), auto hasSafeMembers = std::any_of(members.begin(), members.end(),
[&membersCount](const Decl *D) -> bool { [](const Decl *D) -> bool {
membersCount ++;
if (auto VD = dyn_cast<ValueDecl>(D)) if (auto VD = dyn_cast<ValueDecl>(D))
return declIsDeserializationSafe(VD); return isDeserializationSafe(VD);
return true; return true;
}); });
if (hasSafeMembers) if (hasSafeMembers)
@@ -3126,12 +3124,12 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
ConformanceLookupKind::OnlyExplicit); ConformanceLookupKind::OnlyExplicit);
bool hasSafeConformances = std::any_of(protocols.begin(), bool hasSafeConformances = std::any_of(protocols.begin(),
protocols.end(), protocols.end(),
declIsDeserializationSafe); isDeserializationSafe);
if (hasSafeConformances) if (hasSafeConformances)
return true; return true;
// Truly empty extensions are safe, it may happen in swiftinterfaces. // Truly empty extensions are safe, it may happen in swiftinterfaces.
if (membersCount == 0 && protocols.size() == 0) if (members.empty() && protocols.size() == 0)
return true; return true;
return false; return false;
@@ -3152,7 +3150,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
if (auto accessor = dyn_cast<AccessorDecl>(value)) if (auto accessor = dyn_cast<AccessorDecl>(value))
// Accessors are as safe as their storage. // Accessors are as safe as their storage.
if (declIsDeserializationSafe(accessor->getStorage())) if (isDeserializationSafe(accessor->getStorage()))
return true; return true;
// Frozen fields are always safe. // Frozen fields are always safe.
@@ -3168,7 +3166,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
// Property wrappers storage is as safe as the wrapped property. // Property wrappers storage is as safe as the wrapped property.
if (VarDecl *wrapped = var->getOriginalWrappedProperty()) if (VarDecl *wrapped = var->getOriginalWrappedProperty())
if (declIsDeserializationSafe(wrapped)) if (isDeserializationSafe(wrapped))
return true; return true;
} }
@@ -3178,7 +3176,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
/// Write a \c DeserializationSafetyLayout record only when \p decl is unsafe /// Write a \c DeserializationSafetyLayout record only when \p decl is unsafe
/// to deserialize. /// to deserialize.
/// ///
/// \sa declIsDeserializationSafe /// \sa isDeserializationSafe
void writeDeserializationSafety(const Decl *decl) { void writeDeserializationSafety(const Decl *decl) {
using namespace decls_block; using namespace decls_block;
@@ -3217,7 +3215,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
// Don't look at decls inside functions and // Don't look at decls inside functions and
// check the ValueDecls themselves. // check the ValueDecls themselves.
auto declIsSafe = DC->isLocalContext() || auto declIsSafe = DC->isLocalContext() ||
declIsDeserializationSafe(decl); isDeserializationSafe(decl);
#ifdef NDEBUG #ifdef NDEBUG
// In release builds, bail right away if the decl is safe. // In release builds, bail right away if the decl is safe.
// In debug builds, wait to bail after the debug prints and asserts. // In debug builds, wait to bail after the debug prints and asserts.
@@ -3246,6 +3244,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
); );
#ifndef NDEBUG #ifndef NDEBUG
// Bail out here in debug builds, release builds would bailed out earlier.
if (declIsSafe) if (declIsSafe)
return; return;
#endif #endif

View File

@@ -72,6 +72,7 @@ public struct PublicStruct {
// SAFETY-PRIVATE: Serialization safety, safe: 'inlinableFunc()' // SAFETY-PRIVATE: Serialization safety, safe: 'inlinableFunc()'
public func publicFunc() {} public func publicFunc() {}
// SAFETY-PRIVATE: Serialization safety, safe: 'publicFunc()' // SAFETY-PRIVATE: Serialization safety, safe: 'publicFunc()'
@available(SwiftStdlib 5.1, *) // for the `some` keyword.
public func opaqueTypeFunc() -> some PublicProto { public func opaqueTypeFunc() -> some PublicProto {
return InternalStruct() return InternalStruct()
} }