Skip to content

Commit 5b02006

Browse files
committed
Extend runtime checking for suppressible protocols
Add more runtime support for checking suppressible protocol requirements: * Parameter packs now check all of the arguments appropriately * Most structural types now implement checking (these are hard to test).
1 parent b167eec commit 5b02006

File tree

3 files changed

+167
-21
lines changed

3 files changed

+167
-21
lines changed

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3238,7 +3238,14 @@ SubstGenericParametersFromMetadata::getMetadata(
32383238

32393239
MetadataOrPack
32403240
SubstGenericParametersFromMetadata::getMetadataOrdinal(unsigned ordinal) const {
3241-
return MetadataOrPack(genericArgs[ordinal]);
3241+
// Don't attempt anything if we have no generic parameters.
3242+
if (genericArgs == nullptr)
3243+
return MetadataOrPack();
3244+
3245+
// On first access, compute the descriptor path.
3246+
setup();
3247+
3248+
return MetadataOrPack(genericArgs[numShapeClasses + ordinal]);
32423249
}
32433250

32443251
const WitnessTable *

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 115 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,16 +1632,96 @@ checkGenericPackRequirement(
16321632
(unsigned)req.getKind());
16331633
}
16341634

1635+
static std::optional<TypeLookupError>
1636+
checkSuppressibleRequirements(const Metadata *type,
1637+
SuppressibleProtocolSet ignored);
1638+
16351639
static std::optional<TypeLookupError>
16361640
checkSuppressibleRequirementsStructural(const Metadata *type,
16371641
SuppressibleProtocolSet ignored) {
1638-
// FIXME: Implement me!
1642+
switch (type->getKind()) {
1643+
case MetadataKind::Class:
1644+
case MetadataKind::Struct:
1645+
case MetadataKind::Enum:
1646+
case MetadataKind::Optional:
1647+
case MetadataKind::ForeignClass:
1648+
case MetadataKind::ForeignReferenceType:
1649+
case MetadataKind::ObjCClassWrapper:
1650+
// All handled via context descriptor in the caller.
1651+
return std::nullopt;
1652+
1653+
case MetadataKind::HeapLocalVariable:
1654+
case MetadataKind::Opaque:
1655+
case MetadataKind::HeapGenericLocalVariable:
1656+
case MetadataKind::ErrorObject:
1657+
case MetadataKind::Task:
1658+
case MetadataKind::Job:
1659+
// Not part of the user-visible type system; assumed to handle all
1660+
// suppressible requirements.
1661+
return std::nullopt;
1662+
1663+
case MetadataKind::Tuple: {
1664+
// Check every element type in the tuple.
1665+
auto tupleMetadata = cast<TupleTypeMetadata>(type);
1666+
for (unsigned i = 0, n = tupleMetadata->NumElements; i != n; ++i) {
1667+
if (auto error =
1668+
checkSuppressibleRequirements(&*tupleMetadata->getElement(i).Type,
1669+
ignored))
1670+
return error;
1671+
}
1672+
return std::nullopt;
1673+
}
1674+
1675+
case MetadataKind::Function: {
1676+
// FIXME: Implement me
1677+
return std::nullopt;
1678+
}
1679+
1680+
case MetadataKind::ExtendedExistential: {
1681+
auto existential = cast<ExtendedExistentialTypeMetadata>(type);
1682+
auto &shape = *existential->Shape;
1683+
llvm::ArrayRef<GenericRequirementDescriptor> reqs(
1684+
shape.getReqSigRequirements(), shape.getNumReqSigRequirements());
1685+
// Look for any suppressed protocol requirements. If the existential
1686+
// has suppressed a protocol that is not ignored, then the existential
1687+
// does not meet the specified requirements.
1688+
for (const auto& req : reqs) {
1689+
if (req.getKind() != GenericRequirementKind::SuppressedProtocols)
1690+
continue;
1691+
1692+
auto suppressed = req.getSuppressedProtocols();
1693+
auto missing = suppressed - ignored;
1694+
if (!missing.empty()) {
1695+
return TYPE_LOOKUP_ERROR_FMT(
1696+
"existential type missing suppresible protocols %x",
1697+
missing.rawBits());
1698+
}
1699+
}
1700+
1701+
return std::nullopt;
1702+
}
1703+
1704+
case MetadataKind::Metatype:
1705+
case MetadataKind::ExistentialMetatype:
1706+
// Metatypes themselves can't have suppressible protocols.
1707+
return std::nullopt;
1708+
1709+
case MetadataKind::Existential:
1710+
// The existential representation has no room for specifying any
1711+
// suppressed requirements, so it always succeeds.
1712+
return std::nullopt;
1713+
1714+
case MetadataKind::LastEnumerated:
1715+
break;
1716+
}
1717+
1718+
// Just accept any unknown types.
16391719
return std::nullopt;
16401720
}
16411721

16421722
/// Check that the given `type` meets all suppressible protocol requirements
16431723
/// that haven't been explicitly suppressed by `ignored`.
1644-
static std::optional<TypeLookupError>
1724+
std::optional<TypeLookupError>
16451725
checkSuppressibleRequirements(const Metadata *type,
16461726
SuppressibleProtocolSet ignored) {
16471727
auto contextDescriptor = type->getTypeContextDescriptor();
@@ -1763,32 +1843,47 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(
17631843
if (index < allSuppressed.size())
17641844
suppressed = allSuppressed[index];
17651845

1846+
MetadataOrPack metadataOrPack(substGenericParamOrdinal(index));
17661847
switch (genericParams[index].getKind()) {
1767-
case GenericParamKind::Type:
1768-
break;
1848+
case GenericParamKind::Type: {
1849+
if (!metadataOrPack || metadataOrPack.isMetadataPack()) {
1850+
return TYPE_LOOKUP_ERROR_FMT(
1851+
"unexpected pack for generic parameter %u", index);
1852+
}
17691853

1770-
case GenericParamKind::TypePack:
1771-
// FIXME: variadic generics
1772-
continue;
1854+
auto metadata = metadataOrPack.getMetadata();
1855+
if (auto error = checkSuppressibleRequirements(metadata, suppressed))
1856+
return error;
17731857

1774-
default:
1775-
return TYPE_LOOKUP_ERROR_FMT("unknown generic parameter kind %u",
1776-
index);
1858+
break;
17771859
}
17781860

1779-
MetadataOrPack metadataOrPack(substGenericParamOrdinal(index));
1780-
if (!metadataOrPack)
1781-
return TYPE_LOOKUP_ERROR_FMT("unable to find generic argument %u",
1782-
index);
1861+
case GenericParamKind::TypePack: {
1862+
// NULL can be used to indicate an empty pack.
1863+
if (!metadataOrPack)
1864+
break;
17831865

1784-
if (metadataOrPack.isMetadataPack()) {
1785-
// FIXME: variadic generics
1786-
continue;
1866+
if (metadataOrPack.isMetadata()) {
1867+
return TYPE_LOOKUP_ERROR_FMT(
1868+
"unexpected metadata for generic pack parameter %u", index);
1869+
}
1870+
1871+
auto pack = metadataOrPack.getMetadataPack();
1872+
if (pack.getElements() != 0) {
1873+
llvm::ArrayRef<const Metadata *> elements(
1874+
pack.getElements(), pack.getNumElements());
1875+
for (auto element : elements) {
1876+
if (auto error = checkSuppressibleRequirements(element, suppressed))
1877+
return error;
1878+
}
1879+
}
1880+
break;
17871881
}
17881882

1789-
auto metadata = metadataOrPack.getMetadata();
1790-
if (auto error = checkSuppressibleRequirements(metadata, suppressed))
1791-
return error;
1883+
default:
1884+
return TYPE_LOOKUP_ERROR_FMT("unknown generic parameter kind %u",
1885+
index);
1886+
}
17921887
}
17931888

17941889
// Success!

test/Interpreter/moveonly_generics_casting.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct ConditionallyCopyable<T: ~Copyable>: ~Copyable {
2828
}
2929
extension ConditionallyCopyable: Copyable where T: Copyable { }
3030

31+
// FIXME: Not yet supported
32+
// struct VariadicCopyable<each T: ~Copyable>: Copyable { }
33+
// extension VariadicCopyable: P where repeat each T: Copyable { }
34+
3135
func attemptCall(_ a: Any) {
3236
if let value = a as? P {
3337
value.speak()
@@ -56,6 +60,46 @@ func main() {
5660
// CHECK: failed to cast (attemptCall)
5761
attemptCall(Cat<Noncopyable, ConditionallyCopyable<Ordinary>>())
5862

63+
// CHECK-FIXME: hello
64+
// attemptCall(VariadicCopyable<Ordinary, ConditionallyCopyable<Ordinary>>())
65+
66+
// CHECK-FIXME: failed to cast (attemptCall)
67+
// attemptCall(VariadicCopyable<Ordinary, ConditionallyCopyable<Noncopyable>>())
68+
69+
// CHECK: tuple types
70+
print("tuple types")
71+
72+
// CHECK: hello
73+
attemptCall(Dog<(Ordinary, Ordinary)>())
74+
75+
// CHECK-FIXME: failed to cast (attemptCall)
76+
// FIXME: Requires the ability to create such tuple types
77+
// attemptCall(Dog<(Ordinary, Noncopyable)>())
78+
79+
// CHECK: metatype types
80+
print("metatype types")
81+
82+
// CHECK: hello
83+
attemptCall(Dog<Ordinary.Type>())
84+
85+
// CHECK: hello
86+
attemptCall(Dog<Noncopyable.Type>())
87+
88+
// CHECK: function types
89+
print("function types")
90+
91+
attemptCall(Dog<(Ordinary) -> Noncopyable>())
92+
93+
// CHECK: existential types
94+
print("existential types")
95+
96+
// CHECK: hello
97+
attemptCall(Dog<Any>())
98+
99+
// CHECK-FIXME: failed to cast (attemptCall)
100+
typealias NoncopyableAny = ~Copyable
101+
// FIXME crashes: attemptCall(Dog<any NoncopyableAny>())
102+
59103
// CHECK: cast succeeded
60104
test_radar124171788(.nothing)
61105
}

0 commit comments

Comments
 (0)