Merge pull request #65267 from xymus/serial-indirect-conformances

[Serialization] Keep indirect conformances knowledge with safety
This commit is contained in:
Alexis Laferrière
2023-04-19 10:52:20 -07:00
committed by GitHub
4 changed files with 66 additions and 14 deletions

View File

@@ -3124,14 +3124,11 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
if (hasSafeMembers) if (hasSafeMembers)
return true; return true;
// We can mark the extension unsafe only if it has no public // We can mark the extension unsafe only if it has no public
// conformances. // conformances.
auto protocols = ext->getLocalProtocols( auto protocols = ext->getLocalProtocols(
ConformanceLookupKind::OnlyExplicit); ConformanceLookupKind::OnlyExplicit);
bool hasSafeConformances = std::any_of(protocols.begin(), if (!protocols.empty())
protocols.end(),
isDeserializationSafe);
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.
@@ -3141,6 +3138,9 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
return false; return false;
} }
if (isa<ProtocolDecl>(decl))
return true;
auto value = cast<ValueDecl>(decl); auto value = cast<ValueDecl>(decl);
// A decl is safe if formally accessible publicly. // A decl is safe if formally accessible publicly.

View File

@@ -0,0 +1,52 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// REQUIRES: asserts
//--- Lib.swift
// RUN: %target-swift-frontend -emit-module %t/Lib.swift \
// RUN: -enable-library-evolution -swift-version 5 \
// RUN: -emit-module-path %t/Lib.swiftmodule \
// RUN: -emit-module-interface-path %t/Lib.swiftinterface
// RUN: cat %t/Lib.swiftinterface | %FileCheck %t/Lib.swift
public protocol PublicProtocol : AnyObject {}
// CHECK: public protocol PublicProtocol : AnyObject
protocol InternalProtocol: PublicProtocol {}
// CHECK-NOT: InternalProtocol
public class IndirectConformant {
public init() {}
}
extension IndirectConformant: InternalProtocol {}
// CHECK: extension Lib.IndirectConformant : Lib.PublicProtocol {}
//--- Client.swift
/// Works without safety.
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t
/// Works with safety.
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
// RUN: -enable-deserialization-safety \
// RUN: -Xllvm -debug-only=Serialization 2>&1 \
// RUN: | %FileCheck %t/Client.swift
/// Works with swiftinterface.
// RUN: rm %t/Lib.swiftmodule
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t
import Lib
func requireConformanceToPublicProtocol(_ a: PublicProtocol) {}
requireConformanceToPublicProtocol(IndirectConformant())
/// Deserialization safety should keep the original chain. We're mostly
/// documenting the current safety implementation details here, if we can get
/// without deserializing 'InternalProtocol' it would be even better.
// CHECK: Deserialized: 'IndirectConformant'
// CHECK: Deserialized: 'PublicProtocol'
// CHECK: Deserialized: 'InternalProtocol'

View File

@@ -34,12 +34,12 @@
public protocol PublicProto {} public protocol PublicProto {}
// SAFETY-PRIVATE: Serialization safety, safe: 'PublicProto' // SAFETY-PRIVATE: Serialization safety, safe: 'PublicProto'
internal protocol InternalProto {} internal protocol InternalProto {}
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto' // SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto' // NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
private protocol PrivateProto {} private protocol PrivateProto {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'PrivateProto' // SAFETY-PRIVATE: Serialization safety, safe: 'PrivateProto'
fileprivate protocol FileprivateProto {} fileprivate protocol FileprivateProto {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'FileprivateProto' // SAFETY-PRIVATE: Serialization safety, safe: 'FileprivateProto'
internal struct InternalStruct : PublicProto { internal struct InternalStruct : PublicProto {
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalStruct' // SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalStruct'

View File

@@ -47,7 +47,7 @@ extension ExtendedPublic : PublicProto {
/// Internal /// Internal
internal protocol InternalProto {} internal protocol InternalProto {}
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto' // SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto' // NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
internal struct ExtendedInternal {} internal struct ExtendedInternal {}
// SAFETY-INTERNAL: Serialization safety, unsafe: 'ExtendedInternal' // SAFETY-INTERNAL: Serialization safety, unsafe: 'ExtendedInternal'
@@ -63,7 +63,7 @@ extension ExtendedInternal : InternalProto {}
/// Private /// Private
private protocol PrivateProto {} private protocol PrivateProto {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'PrivateProto' // SAFETY-PRIVATE: Serialization safety, safe: 'PrivateProto'
private struct ExtendedPrivate {} private struct ExtendedPrivate {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedPrivate' // SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedPrivate'
extension ExtendedPrivate { extension ExtendedPrivate {
@@ -75,7 +75,7 @@ extension ExtendedPrivate : PrivateProto {}
/// Fileprivate /// Fileprivate
private protocol FileprivateProto {} private protocol FileprivateProto {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'FileprivateProto' // SAFETY-PRIVATE: Serialization safety, safe: 'FileprivateProto'
private struct ExtendedFileprivate {} private struct ExtendedFileprivate {}
// SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedFileprivate' // SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedFileprivate'
extension ExtendedFileprivate { extension ExtendedFileprivate {
@@ -87,14 +87,14 @@ extension ExtendedFileprivate : FileprivateProto {}
/// Back to public /// Back to public
extension ExtendedPublic : InternalProto { extension ExtendedPublic : InternalProto {
// SAFETY-INTERNAL: Serialization safety, unsafe: 'extension ExtendedPublic' // SAFETY-INTERNAL: Serialization safety, safe: 'extension ExtendedPublic'
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'extension ExtendedPublic' // NO-SAFETY-INTERNAL: Serialization safety, safe: 'extension ExtendedPublic'
} }
extension ExtendedPublic : PrivateProto { extension ExtendedPublic : PrivateProto {
// SAFETY-PRIVATE: Serialization safety, unsafe: 'extension ExtendedPublic' // SAFETY-PRIVATE: Serialization safety, safe: 'extension ExtendedPublic'
} }
extension ExtendedPublic : FileprivateProto { extension ExtendedPublic : FileprivateProto {
// SAFETY-PRIVATE: Serialization safety, unsafe: 'extension ExtendedPublic' // SAFETY-PRIVATE: Serialization safety, safe: 'extension ExtendedPublic'
} }
extension ExtendedPublic { extension ExtendedPublic {