Skip to content

Commit 482421f

Browse files
committed
Generalize emission of opaque type descriptor to use generic signature.
Use the generic signature and substitution map of `OpaqueTypeDecl` to emit type metadata for each opaque generic parameter (rather than only the "underyling type") and each conformance requirement on an opaque generic parameter (or dependent member thereof) that needs a witness table. Fix a bug where opaque result type metadata would miscount the number of witness tables, because it counted conformance requirements without accounting for `@objc` and marker protocols that don't have witness tables.
1 parent b97ef02 commit 482421f

File tree

2 files changed

+76
-24
lines changed

2 files changed

+76
-24
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,37 @@ namespace {
20012001
using super = ContextDescriptorBuilderBase;
20022002

20032003
OpaqueTypeDecl *O;
2004+
2005+
/// Whether the given requirement is a conformance requirement that
2006+
/// requires a witness table in the opaque type descriptor.
2007+
///
2008+
/// When it does, returns the protocol.
2009+
ProtocolDecl *requiresWitnessTable(const Requirement &req) const {
2010+
// We only care about conformance requirements.
2011+
if (req.getKind() != RequirementKind::Conformance)
2012+
return nullptr;
2013+
2014+
// The protocol must require a witness table.
2015+
auto proto = req.getProtocolDecl();
2016+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
2017+
return nullptr;
2018+
2019+
// The type itself must be anchored on one of the generic parameters of
2020+
// the opaque type (not an outer context).
2021+
Type subject = req.getFirstType();
2022+
while (auto depMember = subject->getAs<DependentMemberType>()) {
2023+
subject = depMember->getBase();
2024+
}
2025+
2026+
if (auto genericParam = subject->getAs<GenericTypeParamType>()) {
2027+
unsigned opaqueDepth = O->getOpaqueGenericParams().front()->getDepth();
2028+
if (genericParam->getDepth() == opaqueDepth)
2029+
return proto;
2030+
}
2031+
2032+
return nullptr;
2033+
}
2034+
20042035
public:
20052036

20062037
OpaqueTypeDescriptorBuilder(IRGenModule &IGM, OpaqueTypeDecl *O)
@@ -2015,29 +2046,28 @@ namespace {
20152046

20162047
void addUnderlyingTypeAndConformances() {
20172048
auto sig = O->getOpaqueInterfaceGenericSignature();
2018-
auto underlyingType = Type(O->getUnderlyingInterfaceType())
2019-
.subst(*O->getUnderlyingTypeSubstitutions())
2020-
->getCanonicalType(sig);
2021-
20222049
auto contextSig = O->getGenericSignature().getCanonicalSignature();
2050+
auto subs = *O->getUnderlyingTypeSubstitutions();
20232051

2024-
B.addRelativeAddress(IGM.getTypeRef(underlyingType, contextSig,
2025-
MangledTypeRefRole::Metadata).first);
2026-
2027-
auto opaqueType = O->getDeclaredInterfaceType()
2028-
->castTo<OpaqueTypeArchetypeType>();
2029-
2030-
for (auto proto : opaqueType->getConformsTo()) {
2031-
auto conformance = ProtocolConformanceRef(proto);
2032-
auto underlyingConformance = conformance
2033-
.subst(O->getUnderlyingInterfaceType(),
2034-
*O->getUnderlyingTypeSubstitutions());
2035-
2036-
// Skip protocols without Witness tables, e.g. @objc protocols.
2037-
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(
2038-
underlyingConformance.getRequirement()))
2052+
// Add the underlying types for each generic parameter.
2053+
for (auto genericParam : O->getOpaqueGenericParams()) {
2054+
auto underlyingType = Type(genericParam).subst(subs)->getCanonicalType(sig);
2055+
B.addRelativeAddress(
2056+
IGM.getTypeRef(underlyingType, contextSig,
2057+
MangledTypeRefRole::Metadata).first);
2058+
}
2059+
2060+
// Add witness tables for each of the conformance requirements.
2061+
for (const auto &req : sig.getRequirements()) {
2062+
auto proto = requiresWitnessTable(req);
2063+
if (!proto)
20392064
continue;
20402065

2066+
auto underlyingDependentType = req.getFirstType()->getCanonicalType();
2067+
auto underlyingType = underlyingDependentType.subst(subs)
2068+
->getCanonicalType();
2069+
auto underlyingConformance =
2070+
subs.lookupConformance(underlyingDependentType, proto);
20412071
auto witnessTableRef = IGM.emitWitnessTableRefString(
20422072
underlyingType, underlyingConformance,
20432073
contextSig,
@@ -2113,11 +2143,14 @@ namespace {
21132143
}
21142144

21152145
uint16_t getKindSpecificFlags() {
2116-
// Store the size of the type and conformances vector in the flags.
2117-
auto opaqueType = O->getDeclaredInterfaceType()
2118-
->castTo<OpaqueTypeArchetypeType>();
2119-
2120-
return 1 + opaqueType->getConformsTo().size();
2146+
// Store the number of types and witness tables in the flags.
2147+
unsigned numWitnessTables = llvm::count_if(
2148+
O->getOpaqueInterfaceGenericSignature().getRequirements(),
2149+
[&](const Requirement &req) {
2150+
return requiresWitnessTable(req) != nullptr;
2151+
});
2152+
2153+
return O->getOpaqueGenericParams().size() + numWitnessTables;
21212154
}
21222155
};
21232156
} // end anonymous namespace

test/IRGen/opaque_result_type.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ extension Int: O, O2 {
2828
public func baz() {}
2929
}
3030

31+
@_marker protocol Marker { }
32+
extension Int: Marker { }
33+
3134
extension String: P {
3235
// CHECK-LABEL: @"$sSS18opaque_result_typeE3pooQryFQOMQ" = {{.*}}constant <{ {{.*}} }> <{
3336
// -- header: opaque type context (0x4), generic (0x80), unique (0x40), two entries (0x2_0000)
@@ -135,6 +138,22 @@ func baz<T: P & Q>(z: T) -> some P & Q {
135138
return z
136139
}
137140

141+
// CHECK-LABEL: @"$s18opaque_result_type4fizz1zQrx_tAA6MarkerRzAA1PRzAA1QRzlFQOMQ" = {{.*}} constant <{ {{.*}} }> <{
142+
// -- header: opaque type context (0x4), generic (0x80), unique (0x40), three entries (0x3_0000)
143+
// CHECK-SAME: <i32 0x3_00c4>
144+
// -- parent context: anon context for function
145+
// CHECK-SAME: @"$s18opaque_result_type4fizz1zQrx_tAA6MarkerRzAA1PRzAA1QRzlFMXX"
146+
// -- mangled underlying type
147+
// CHECK-SAME: @"symbolic x"
148+
// -- conformance to P
149+
// CHECK-SAME: @"get_witness_table 18opaque_result_type6MarkerRzAA1PRzAA1QRzlxAaCHD2_
150+
// -- conformance to Q
151+
// CHECK-SAME: @"get_witness_table 18opaque_result_type6MarkerRzAA1PRzAA1QRzlxAaDHD3_
152+
// CHECK-SAME: }>
153+
func fizz<T: P & Q & Marker>(z: T) -> some P & Q & Marker {
154+
return z
155+
}
156+
138157
// Ensure the local type's opaque descriptor gets emitted.
139158
// CHECK-LABEL: @"$s18opaque_result_type11localOpaqueQryF0D0L_QryFQOMQ" =
140159
func localOpaque() -> some P {

0 commit comments

Comments
 (0)