Skip to content

Commit b7fd963

Browse files
authored
Merge pull request #59213 from jckarter/keypath-aeic
SILGen: Don't reference external property descriptors for @_alwaysEmitIntoClient properties.
2 parents 58081c8 + 53e8e7b commit b7fd963

File tree

3 files changed

+59
-15
lines changed

3 files changed

+59
-15
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3583,21 +3583,47 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
35833583
/// Returns true if a key path component for the given property or
35843584
/// subscript should be externally referenced.
35853585
auto shouldUseExternalKeyPathComponent = [&]() -> bool {
3586-
return (!forPropertyDescriptor &&
3587-
(baseDecl->getModuleContext() != SwiftModule ||
3588-
baseDecl->isResilient(SwiftModule, expansion)) &&
3589-
// Protocol requirements don't have nor need property descriptors.
3590-
!isa<ProtocolDecl>(baseDecl->getDeclContext()) &&
3591-
// Properties that only dispatch via ObjC lookup do not have nor
3592-
// need property descriptors, since the selector identifies the
3593-
// storage.
3594-
// Properties that are not public don't need property descriptors
3595-
// either.
3596-
(!baseDecl->requiresOpaqueAccessors() ||
3597-
(!getAccessorDeclRef(getRepresentativeAccessorForKeyPath(baseDecl))
3598-
.isForeign &&
3599-
getAccessorDeclRef(getRepresentativeAccessorForKeyPath(baseDecl))
3600-
.getLinkage(ForDefinition) <= SILLinkage::PublicNonABI)));
3586+
// The property descriptor has the canonical key path component information
3587+
// so doesn't have to refer to another external descriptor.
3588+
if (forPropertyDescriptor) {
3589+
return false;
3590+
}
3591+
3592+
// Don't need to use the external component if we're inside the resilience
3593+
// domain of its defining module.
3594+
if (baseDecl->getModuleContext() == SwiftModule
3595+
&& !baseDecl->isResilient(SwiftModule, expansion)) {
3596+
return false;
3597+
}
3598+
3599+
// Protocol requirements don't have nor need property descriptors.
3600+
if (isa<ProtocolDecl>(baseDecl->getDeclContext())) {
3601+
return false;
3602+
}
3603+
3604+
// Always-emit-into-client properties can't reliably refer to a property
3605+
// descriptor that may not exist in older versions of their home dylib.
3606+
// Their definition is also always entirely visible to clients so it isn't
3607+
// needed.
3608+
if (baseDecl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
3609+
return false;
3610+
}
3611+
3612+
// Properties that only dispatch via ObjC lookup do not have nor
3613+
// need property descriptors, since the selector identifies the
3614+
// storage.
3615+
// Properties that are not public don't need property descriptors
3616+
// either.
3617+
if (baseDecl->requiresOpaqueAccessors()) {
3618+
auto representative = getAccessorDeclRef(
3619+
getRepresentativeAccessorForKeyPath(baseDecl));
3620+
if (representative.isForeign)
3621+
return false;
3622+
if (representative.getLinkage(ForDefinition) > SILLinkage::PublicNonABI)
3623+
return false;
3624+
}
3625+
3626+
return true;
36013627
};
36023628

36033629
auto strategy = storage->getAccessStrategy(AccessSemantics::Ordinary,

validation-test/Evolution/Inputs/keypaths.swift.gyb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,9 @@ public final class AFinalClass {
123123

124124
}
125125

126+
public struct AEIC {
127+
#if AFTER
128+
@_alwaysEmitIntoClient
129+
public var aeic: Int { return 0 }
130+
#endif
131+
}

validation-test/Evolution/test_keypaths.swift.gyb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,16 @@ tests.test("AFinalClass.${name}") {
102102

103103
% end
104104

105+
#if AFTER
106+
tests.test("AlwaysEmitIntoClient") {
107+
// AEIC declarations are vendored into their importing module, so
108+
// equality doesn't currently work reliably with them. We can however
109+
// test that the reference to the property works and is backward-compatible
110+
// when using the `after` test suite with the `before` dylib.
111+
let kp = \AEIC.aeic
112+
113+
expectEqual(kp, kp)
114+
}
115+
#endif
116+
105117
runAllTests()

0 commit comments

Comments
 (0)