Runtime checking for associated types conforming to invertible protocols

Emit metadata for runtime checks of conformances of associated types to
invertible protocols, e.g., `T.Assoc: Copyable`. This allows us to
correctly handle, e.g., dynamic casting involving conditional
conformances that have such constraints.

The model we use here is to emit an invertible-protocol constraint
that leaves only the specific bit clear in the invertible protocol
set.
This commit is contained in:
Doug Gregor
2024-04-02 16:42:16 -07:00
parent 72492aa75d
commit ae01d20428
6 changed files with 83 additions and 12 deletions

View File

@@ -1349,6 +1349,10 @@ bool swift::_swift_class_isSubclass(const Metadata *subclass,
return isSubclass(subclass, superclass);
}
static std::optional<TypeLookupError>
checkInvertibleRequirements(const Metadata *type,
InvertibleProtocolSet ignored);
static std::optional<TypeLookupError>
checkGenericRequirement(
const GenericRequirementDescriptor &req,
@@ -1445,8 +1449,10 @@ checkGenericRequirement(
}
case GenericRequirementKind::InvertedProtocols: {
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
if (index == 0xFFFF)
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
if (index == 0xFFFF) {
return checkInvertibleRequirements(subjectType,
req.getInvertedProtocols());
}
// Expand the suppression set so we can record these protocols.
if (index >= suppressed.size()) {
@@ -1613,8 +1619,18 @@ checkGenericPackRequirement(
case GenericRequirementKind::InvertedProtocols: {
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
if (index == 0xFFFF)
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
if (index == 0xFFFF) {
// Check that each pack element meets the invertible requirements.
for (size_t i = 0, e = subjectType.getNumElements(); i < e; ++i) {
const Metadata *elt = subjectType.getElements()[i];
if (auto error = checkInvertibleRequirements(
elt, req.getInvertedProtocols()))
return error;
}
return std::nullopt;
}
// Expand the suppression set so we can record these protocols.
if (index >= suppressed.size()) {
@@ -1632,10 +1648,6 @@ checkGenericPackRequirement(
(unsigned)req.getKind());
}
static std::optional<TypeLookupError>
checkInvertibleRequirements(const Metadata *type,
InvertibleProtocolSet ignored);
static std::optional<TypeLookupError>
checkInvertibleRequirementsStructural(const Metadata *type,
InvertibleProtocolSet ignored) {