[Type metadata] @objc protocol conformance requirements don't have arguments.

@objc protocols don't have witness tables. However, both type metadata
(in the nominal type descriptors) and the runtime code to demangle
type names into metadata weren't acknowledging this. Fix type metadata
emission to not count an "extra argument" for @objc protocol
conformance requirements, and teach the runtime code to properly look
for conformances to @objc protocols (through the Objective-C runtime)
and not record witness tables for them.
This commit is contained in:
Doug Gregor
2018-02-15 14:07:46 -08:00
parent 33996de39c
commit 800e3818b7
6 changed files with 45 additions and 18 deletions

View File

@@ -6237,11 +6237,13 @@ GenericRequirementsMetadata irgen::addGenericRequirements(
case RequirementKind::Conformance: {
// ABI TODO: We also need a *key* argument that uniquely identifies
// the conformance for conformance requirements as well.
auto flags = GenericRequirementFlags(GenericRequirementKind::Protocol,
/*TODO key argument*/ false,
/*extra argument*/ true);
auto protocol = requirement.getSecondType()->castTo<ProtocolType>()
->getDecl();
bool needsWitnessTable =
Lowering::TypeConverter::protocolRequiresWitnessTable(protocol);
auto flags = GenericRequirementFlags(GenericRequirementKind::Protocol,
/*TODO key argument*/ false,
needsWitnessTable);
auto descriptorRef =
IGM.getConstantReferenceForProtocolDescriptor(protocol);
addGenericRequirement(IGM, B, metadata, sig, flags,

View File

@@ -305,14 +305,7 @@ static bool _unknownClassConformsToObjCProtocol(const OpaqueValue *value,
}
#endif
/// Check whether a type conforms to a protocol.
///
/// \param value - can be null, in which case the question should
/// be answered abstractly if possible
/// \param conformance - if non-null, and the protocol requires a
/// witness table, and the type implements the protocol, the witness
/// table will be placed here
static bool _conformsToProtocol(const OpaqueValue *value,
bool swift::_conformsToProtocol(const OpaqueValue *value,
const Metadata *type,
const ProtocolDescriptor *protocol,
const WitnessTable **conformance) {

View File

@@ -313,6 +313,17 @@ public:
}
};
/// Check whether a type conforms to a protocol.
///
/// \param value - can be null, in which case the question should
/// be answered abstractly if possible
/// \param conformance - if non-null, and the protocol requires a
/// witness table, and the type implements the protocol, the witness
/// table will be placed here
bool _conformsToProtocol(const OpaqueValue *value,
const Metadata *type,
const ProtocolDescriptor *protocol,
const WitnessTable **conformance);
} // end namespace swift
#endif /* SWIFT_RUNTIME_PRIVATE_H */

View File

@@ -747,15 +747,16 @@ bool swift::_checkGenericRequirements(
// Check the requirement.
switch (req.getKind()) {
case GenericRequirementKind::Protocol: {
// Look for a witness table to satisfy this conformance.
auto witnessTable =
swift_conformsToProtocol(subjectType, req.getProtocol());
if (!witnessTable) return true;
const WitnessTable *witnessTable = nullptr;
if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(),
&witnessTable))
return true;
// If this requirement provides an extra argument, add the witness table
// as that argument.
if (req.getFlags().hasExtraArgument())
// If we need a witness table, add it.
if (req.getProtocol()->Flags.needsWitnessTable()) {
assert(witnessTable);
extraArguments.push_back(witnessTable);
}
continue;
}

View File

@@ -64,3 +64,11 @@ sil @$S20generic_classes_objc20GenericInheritsObjC2C7bellsOnACyxGSgSi_tcfcTo : $
bb0(%0 : $Int, %1 : $GenericInheritsObjC<T>):
unreachable
}
@objc protocol P1 { }
protocol P2 { }
// CHECK: @"$S20generic_classes_objc16Generic3WithReqsCMn" = hidden constant
// CHECK-SAME: i32 3, i32 3, i32 3, i32 2
class Generic3WithReqs<T: P1, U: P2, V: P2> { }
sil_vtable Generic3WithReqs { }

View File

@@ -62,5 +62,17 @@ DemangleToMetadataTests.test("Imported enum types") {
_typeByMangledName("So21NSURLSessionTaskStateV")!)
}
class CG4<T: P1, U: P2> { }
extension C : P1 { }
extension C : P2 { }
class D: P2 { }
DemangleToMetadataTests.test("@objc protocol conformances") {
expectEqual(CG4<C, C>.self,
_typeByMangledName("4main3CG4CyAA1CCAA1CCG")!)
expectNil(_typeByMangledName("4main3CG4CyAA1DCAA1DCG"))
}
runAllTests()