Skip to content

Commit 9609484

Browse files
committed
[IRGen] Fix logic for finding witness tables in an opaque result type.
Use the same logic as we do for forming the opaque type result descriptor, of course.
1 parent 2e0a8a3 commit 9609484

File tree

4 files changed

+88
-31
lines changed

4 files changed

+88
-31
lines changed

lib/IRGen/GenArchetype.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -537,16 +537,32 @@ llvm::Value *irgen::emitOpaqueTypeWitnessTableRef(IRGenFunction &IGF,
537537
ProtocolDecl *protocol) {
538538
auto accessorFn = IGF.IGM.getGetOpaqueTypeConformanceFn();
539539
auto opaqueDecl = archetype->getDecl();
540-
540+
assert(archetype->isRoot() && "Can only follow from the root");
541541

542542
llvm::Value *descriptor = getAddressOfOpaqueTypeDescriptor(IGF, opaqueDecl);
543543

544-
auto foundProtocol = std::find(archetype->getConformsTo().begin(),
545-
archetype->getConformsTo().end(),
546-
protocol);
547-
assert(foundProtocol != archetype->getConformsTo().end());
548-
549-
unsigned index = foundProtocol - archetype->getConformsTo().begin() + 1;
544+
// Compute the index at which this witness table resides.
545+
unsigned index = opaqueDecl->getOpaqueGenericParams().size();
546+
auto opaqueReqs =
547+
opaqueDecl->getOpaqueInterfaceGenericSignature().getRequirements();
548+
bool found = false;
549+
for (const auto &req : opaqueReqs) {
550+
auto reqProto = opaqueTypeRequiresWitnessTable(opaqueDecl, req);
551+
if (!reqProto)
552+
continue;
553+
554+
// Is this requirement the one we're looking for?
555+
if (reqProto == protocol &&
556+
req.getFirstType()->isEqual(archetype->getInterfaceType())) {
557+
found = true;
558+
break;
559+
}
560+
561+
++index;
562+
}
563+
564+
(void)found;
565+
assert(found && "Opaque type does not conform to protocol");
550566
auto indexValue = llvm::ConstantInt::get(IGF.IGM.SizeTy, index);
551567

552568
llvm::CallInst *result = nullptr;

lib/IRGen/GenMeta.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,29 +2007,7 @@ namespace {
20072007
///
20082008
/// When it does, returns the protocol.
20092009
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;
2010+
return opaqueTypeRequiresWitnessTable(O, req);
20332011
}
20342012

20352013
public:
@@ -2155,6 +2133,33 @@ namespace {
21552133
};
21562134
} // end anonymous namespace
21572135

2136+
ProtocolDecl *irgen::opaqueTypeRequiresWitnessTable(
2137+
OpaqueTypeDecl *opaque, const Requirement &req) {
2138+
// We only care about conformance requirements.
2139+
if (req.getKind() != RequirementKind::Conformance)
2140+
return nullptr;
2141+
2142+
// The protocol must require a witness table.
2143+
auto proto = req.getProtocolDecl();
2144+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
2145+
return nullptr;
2146+
2147+
// The type itself must be anchored on one of the generic parameters of
2148+
// the opaque type (not an outer context).
2149+
Type subject = req.getFirstType();
2150+
while (auto depMember = subject->getAs<DependentMemberType>()) {
2151+
subject = depMember->getBase();
2152+
}
2153+
2154+
if (auto genericParam = subject->getAs<GenericTypeParamType>()) {
2155+
unsigned opaqueDepth = opaque->getOpaqueGenericParams().front()->getDepth();
2156+
if (genericParam->getDepth() == opaqueDepth)
2157+
return proto;
2158+
}
2159+
2160+
return nullptr;
2161+
}
2162+
21582163
static void eraseExistingTypeContextDescriptor(IRGenModule &IGM,
21592164
NominalTypeDecl *type) {
21602165
// We may have emitted a partial type context descriptor with some empty

lib/IRGen/GenMeta.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ namespace irgen {
187187
llvm::Function *function,
188188
LinkEntity entity,
189189
Size size);
190+
191+
/// Determine whether the given opaque type requires a witness table for the
192+
/// given requirement.
193+
///
194+
/// \returns the protocol when a witness table is required, or \c nullptr
195+
/// if the requirement isn't a conformance requirement or doesn't require a
196+
/// witness table.
197+
ProtocolDecl *opaqueTypeRequiresWitnessTable(
198+
OpaqueTypeDecl *opaque, const Requirement &req);
199+
190200
} // end namespace irgen
191201
} // end namespace swift
192202

test/Interpreter/named_opaque_result_types.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift -swift-version 5 -Xfrontend -enable-experimental-named-opaque-types %s -o %t/a.out
2+
// RUN: %target-build-swift -g -swift-version 5 -Xfrontend -enable-experimental-named-opaque-types %s -o %t/a.out
33
// RUN: %target-run %t/a.out | %FileCheck %s
44

55
// REQUIRES: executable_test
@@ -61,6 +61,22 @@ if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) {
6161
// CHECK: {{["Hello", "World", "!"]|too old}}
6262
print(x3.1)
6363

64+
// CHECK: Integer loop
65+
// CHECK-NEXT: 1
66+
// CHECK-NEXT: 2
67+
// CHECK-NEXT: 3
68+
print("Integer loop")
69+
for i in x3.0 {
70+
print(i)
71+
}
72+
73+
// CHECK: Hello
74+
// CHECK-NEXT: World
75+
// CHECK-NEXT: !
76+
for index in x3.1.indices {
77+
print(x3.1[index])
78+
}
79+
6480
// CHECK: {{(Array<Int>, Set<String>)|too old}}
6581
let paType = getP_A(X<Int, String>.self)
6682
print(paType)
@@ -70,6 +86,16 @@ if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) {
7086
print("too old")
7187
print("too old")
7288
print("too old")
89+
print("too old")
90+
91+
print("Integer loop")
92+
print("1")
93+
print("2")
94+
print("3")
95+
96+
print("Hello")
97+
print("World")
98+
print("!")
7399

74100
print("too old")
75101
print("too old")

0 commit comments

Comments
 (0)