Skip to content

Commit cf47453

Browse files
committed
[Serialization] Only write the underlying type of an opaque type if inlinable
Clients of a resilient module using opaque types don't need access to the underlying type unless it's used in an inlinable context. Plus, the underlying type can reference internal details which can lead to crashes when they reference implementation-only dependencies. To clean up this behavior, let's only serialize the underlying type if used by an inlinable function. rdar://105128784
1 parent b4e2969 commit cf47453

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

lib/Serialization/Serialization.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4280,16 +4280,27 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
42804280
using namespace decls_block;
42814281
verifyAttrSerializable(opaqueDecl);
42824282

4283-
auto namingDeclID = S.addDeclRef(opaqueDecl->getNamingDecl());
4284-
auto contextID = S.addDeclContextRef(opaqueDecl->getDeclContext());
4283+
auto namingDecl = opaqueDecl->getNamingDecl();
4284+
auto namingDeclID = S.addDeclRef(namingDecl);
4285+
auto DC = opaqueDecl->getDeclContext();
4286+
auto contextID = S.addDeclContextRef(DC);
42854287
auto interfaceSigID = S.addGenericSignatureRef(
42864288
opaqueDecl->getOpaqueInterfaceGenericSignature());
42874289
auto interfaceTypeID = S.addTypeRef(opaqueDecl->getDeclaredInterfaceType());
42884290

42894291
auto genericSigID = S.addGenericSignatureRef(opaqueDecl->getGenericSignature());
42904292

42914293
SubstitutionMapID underlyingSubsID = 0;
4292-
if (auto underlying = opaqueDecl->getUniqueUnderlyingTypeSubstitutions()) {
4294+
bool moduleIsResilient = DC->getParentModule()->getResilienceStrategy() ==
4295+
swift::ResilienceStrategy::Resilient;
4296+
auto *AFD = dyn_cast<AbstractFunctionDecl>(namingDecl);
4297+
if (moduleIsResilient && AFD &&
4298+
AFD->getResilienceExpansion() != swift::ResilienceExpansion::Minimal) {
4299+
// Do not write the underlying type information if the function is
4300+
// not inlinable in clients. This reflects the behavior in the
4301+
// swiftinterface where clients are only aware of the underlying type
4302+
// when the body of the function is public.
4303+
} else if (auto underlying = opaqueDecl->getUniqueUnderlyingTypeSubstitutions()) {
42934304
underlyingSubsID = S.addSubstitutionMapRef(*underlying);
42944305
} else if (opaqueDecl->hasConditionallyAvailableSubstitutions()) {
42954306
// Universally available type doesn't have any availability conditions

test/Serialization/Safety/skip-reading-internal-details.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,29 @@ public struct PublicStruct {
8686
}
8787
}
8888

89+
// resultBuilder scenario
90+
public protocol V {}
91+
92+
@resultBuilder
93+
public struct VB {
94+
public static func buildExpression<Content>(_ content: Content) -> Content where Content : V { fatalError() }
95+
public static func buildBlock() -> V { fatalError() }
96+
public static func buildBlock<Content>(_ content: Content) -> Content where Content : V { fatalError() }
97+
}
98+
99+
public struct EV : V {
100+
public init () {}
101+
}
102+
103+
public extension V {
104+
@VB
105+
func opaqueReferencingPrivate() -> some V {
106+
referencedPrivateFunc(v: EV())
107+
}
108+
109+
private func referencedPrivateFunc(v: some V) -> some V { return v }
110+
}
111+
89112
//--- Client.swift
90113

91114
import Lib
@@ -94,3 +117,6 @@ var x = PublicStruct()
94117

95118
// Trigger a typo correction that reads all members.
96119
x.notAMember() // expected-error {{value of type 'PublicStruct' has no member 'notAMember'}}
120+
121+
var v = EV()
122+
let _ = v.opaqueReferencingPrivate()

0 commit comments

Comments
 (0)