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:
Joe Groff
2015-04-15 23:53:25 +00:00
parent e89ff69ac7
commit 2b93411ba7
9 changed files with 118 additions and 31 deletions

View File

@@ -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;