Skip to content

Commit c8659ca

Browse files
committed
Runtime: Handle Protocol objects through universal bridging too.
1 parent 6e7a281 commit c8659ca

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,15 +2738,27 @@ static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
27382738
return result;
27392739
}
27402740

2741-
// Handle metatypes. Class metatypes bridge to their class object.
2741+
// Handle metatypes.
27422742
if (isa<ExistentialMetatypeMetadata>(srcType)
27432743
|| isa<MetatypeMetadata>(srcType)) {
27442744
const Metadata *srcMetatypeValue;
27452745
memcpy(&srcMetatypeValue, src, sizeof(srcMetatypeValue));
27462746

2747+
// Class metatypes bridge to their class object.
27472748
if (isa<ClassMetadata>(srcMetatypeValue)
2748-
|| isa<ObjCClassWrapperMetadata>(srcMetatypeValue))
2749+
|| isa<ObjCClassWrapperMetadata>(srcMetatypeValue)) {
27492750
return (id)srcMetatypeValue->getClassObject();
2751+
2752+
// ObjC protocols bridge to their Protocol object.
2753+
} else if (auto existential
2754+
= dyn_cast<ExistentialTypeMetadata>(srcMetatypeValue)) {
2755+
if (existential->isObjC() && existential->Protocols.NumProtocols == 1) {
2756+
// Though they're statically-allocated globals, Protocol inherits
2757+
// NSObject's default refcounting behavior so must be retained.
2758+
auto protocolObj = (id)existential->Protocols[0];
2759+
return objc_retain(protocolObj);
2760+
}
2761+
}
27502762
} else if (auto srcBridgeWitness = findBridgeWitness(srcType)) {
27512763
// Bridge the source value to an object.
27522764
auto srcBridgedObject =

test/1_stdlib/BridgeIdAsAny.swift.gyb

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,24 +138,36 @@ func classMetatypePreservesIdentityGenerically<T>(original: T.Type,
138138
expectTrue(original as Any.Type as AnyObject === bridged)
139139
}
140140

141+
func protocolObjectPreservesIdentity(original: NSCopying.Protocol,
142+
bridged: AnyObject) {
143+
let proto: Protocol = original
144+
expectTrue(proto === bridged)
145+
}
146+
147+
protocol P {}
148+
141149
// We want to exhaustively check all paths through the bridging and dynamic
142150
// casting infrastructure, so expand out test cases that wrap the different
143151
// interesting bridging cases in different kinds of existential container.
144152
%{
145153
testCases = [
146-
("classes", "LifetimeTracked(0)", "bridgedObjectPreservesIdentity", True),
147-
("strings", '"vitameatavegamin"', "stringBridgesToEqualNSString", True),
148-
("unbridged type", "KnownUnbridged()", "boxedTypeRoundTripsThroughDynamicCasting", True),
149-
("tuple", '(1, "2")', "tupleCanBeDynamicallyCast", False),
150-
("metatype", 'Int.self', "metatypeCanBeDynamicallyCast", False),
151-
("generic metatype", 'Int.self', "metatypeCanBeDynamicallyCastGenerically", False),
152-
("CF metatype", 'CFString.self', "metatypeCanBeDynamicallyCast", False),
153-
("generic CF metatype", 'CFString.self', "metatypeCanBeDynamicallyCastGenerically", False),
154-
("class metatype", 'LifetimeTracked.self', "classMetatypePreservesIdentity", False),
155-
("objc metatype", 'NSObject.self', "classMetatypePreservesIdentity", False),
156-
("generic class metatype", 'LifetimeTracked.self', "classMetatypePreservesIdentityGenerically", False),
157-
("generic objc metatype", 'NSObject.self', "classMetatypePreservesIdentityGenerically", False),
158-
("function", 'guineaPigFunction', "functionCanBeDynamicallyCast", False),
154+
("classes", "LifetimeTracked(0)", "bridgedObjectPreservesIdentity", True),
155+
("strings", '"vitameatavegamin"', "stringBridgesToEqualNSString", True),
156+
("unbridged type", "KnownUnbridged()", "boxedTypeRoundTripsThroughDynamicCasting", True),
157+
("tuple", '(1, "2")', "tupleCanBeDynamicallyCast", False),
158+
("metatype", 'Int.self', "metatypeCanBeDynamicallyCast", False),
159+
("generic metatype", 'Int.self', "metatypeCanBeDynamicallyCastGenerically", False),
160+
("CF metatype", 'CFString.self', "metatypeCanBeDynamicallyCast", False),
161+
("generic CF metatype", 'CFString.self', "metatypeCanBeDynamicallyCastGenerically", False),
162+
("class metatype", 'LifetimeTracked.self', "classMetatypePreservesIdentity", False),
163+
("objc metatype", 'NSObject.self', "classMetatypePreservesIdentity", False),
164+
("protocol", 'P.self', "metatypeCanBeDynamicallyCastGenerically", False),
165+
("objc protocol", 'NSCopying.self', "protocolObjectPreservesIdentity", False),
166+
("objc protocol composition", '(NSCopying & NSCoding).self', "metatypeCanBeDynamicallyCastGenerically", False),
167+
("mixed protocol composition", '(NSCopying & P).self', "metatypeCanBeDynamicallyCastGenerically", False),
168+
("generic class metatype", 'LifetimeTracked.self', "classMetatypePreservesIdentityGenerically", False),
169+
("generic objc metatype", 'NSObject.self', "classMetatypePreservesIdentityGenerically", False),
170+
("function", 'guineaPigFunction', "functionCanBeDynamicallyCast", False),
159171
]
160172
}%
161173

0 commit comments

Comments
 (0)