mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
IRGen/Runtime: AnyObject never has a witness table, even if it isn't @objc.
@objc protocols aren't supported with an ObjC runtime, but we still want values of AnyObject type to be word-sized. Handle this by turning the binary "needsWitnessTable" condition into a "dispatch strategy" enum, so we can recognize the condition "has no methods, so neither swift nor objc dispatch" as distinct from either swift or ObjC protocol representations. Assign this dispatch strategy when we lower AnyObject. Should be NFC for the ObjC-enabled build. (It would also be beneficial for the ObjC-runtime-enabled version of Swift if AnyObject weren't an @objc protocol; that would mean we could give it a canonical protocol descriptor in the standard library, among other things. There are fairly deep assumptions in Sema that AnyObject is @objc, though, and it's not worth disturbing those assumptions right now.) Swift SVN r27338
This commit is contained in:
@@ -481,6 +481,7 @@ static bool _conformsToProtocol(const OpaqueValue *value,
|
||||
case MetadataKind::Existential: {
|
||||
auto sourceExistential = cast<ExistentialTypeMetadata>(type);
|
||||
// The existential conforms to AnyObject if it's class-constrained.
|
||||
// FIXME: It also must not carry witness tables.
|
||||
return sourceExistential->isClassBounded();
|
||||
}
|
||||
|
||||
@@ -972,21 +973,29 @@ _dynamicCastUnknownClassToExistential(const void *object,
|
||||
const ExistentialTypeMetadata *targetType) {
|
||||
for (unsigned i = 0, e = targetType->Protocols.NumProtocols; i < e; ++i) {
|
||||
const ProtocolDescriptor *protocol = targetType->Protocols[i];
|
||||
// If the target existential requires witness tables, we can't do this cast.
|
||||
// The result type would not have a single-refcounted-pointer rep.
|
||||
if (protocol->Flags.needsWitnessTable())
|
||||
return nullptr;
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (!_swift_objectConformsToObjCProtocol(object, protocol))
|
||||
return nullptr;
|
||||
#else
|
||||
// The only non-@objc, non-witness-table-requiring protocol should be
|
||||
// AnyObject (in no-ObjC-interop mode).
|
||||
assert(protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject
|
||||
&& "swift protocols besides AnyObject should always require a "
|
||||
"witness table");
|
||||
#endif
|
||||
|
||||
switch (protocol->Flags.getDispatchStrategy()) {
|
||||
case ProtocolDispatchStrategy::Swift:
|
||||
// If the target existential requires witness tables, we can't do this cast.
|
||||
// The result type would not have a single-refcounted-pointer rep.
|
||||
return nullptr;
|
||||
case ProtocolDispatchStrategy::ObjC:
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (!_swift_objectConformsToObjCProtocol(object, protocol))
|
||||
return nullptr;
|
||||
break;
|
||||
#else
|
||||
assert(false && "ObjC interop disabled?!");
|
||||
return nullptr;
|
||||
#endif
|
||||
case ProtocolDispatchStrategy::Empty:
|
||||
// The only non-@objc, non-witness-table-requiring protocol should be
|
||||
// AnyObject for now.
|
||||
assert(protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject
|
||||
&& "swift protocols besides AnyObject should always require a "
|
||||
"witness table");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
|
||||
Reference in New Issue
Block a user