Skip to content

Commit d484e12

Browse files
authored
Merge pull request swiftlang#40938 from DougGregor/opaque-witness-table-fixes
Opaque type fixes for interesting generic environments
2 parents 972e3aa + 9609484 commit d484e12

17 files changed

+140
-59
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ class AbstractionPattern {
981981
return true;
982982
}
983983
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
984-
return !isa<OpaqueTypeArchetypeType>(archetype->getRoot());
984+
return !isa<OpaqueTypeArchetypeType>(archetype);
985985
}
986986
return false;
987987
}

lib/AST/ASTVerifier.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,19 @@ class Verifier : public ASTWalker {
28072807

28082808
unsigned currentDepth = DC->getGenericContextDepth();
28092809
if (currentDepth < GTPD->getDepth()) {
2810+
// If this is actually an opaque type's generic parameter, we're okay.
2811+
if (auto value = dyn_cast_or_null<ValueDecl>(DC->getAsDecl())) {
2812+
auto opaqueDecl = dyn_cast<OpaqueTypeDecl>(value);
2813+
if (!opaqueDecl)
2814+
opaqueDecl = value->getOpaqueResultTypeDecl();
2815+
if (opaqueDecl) {
2816+
if (GTPD->getDepth() ==
2817+
opaqueDecl->getOpaqueGenericParams().front()->getDepth()) {
2818+
return;
2819+
}
2820+
}
2821+
}
2822+
28102823
Out << "GenericTypeParamDecl has incorrect depth\n";
28112824
abort();
28122825
}

lib/AST/GenericEnvironment.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,24 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
362362
break;
363363
}
364364

365-
case Kind::Opaque:
365+
case Kind::Opaque: {
366+
// If the anchor type isn't rooted in a generic parameter that
367+
// represents an opaque declaration, then apply the outer substitutions.
368+
// It would be incorrect to build an opaque type archetype here.
369+
auto rootGP = requirements.anchor->getRootGenericParam();
370+
unsigned opaqueDepth =
371+
getOpaqueTypeDecl()->getOpaqueGenericParams().front()->getDepth();
372+
if (rootGP->getDepth() < opaqueDepth) {
373+
result = maybeApplyOpaqueTypeSubstitutions(requirements.anchor);
374+
break;
375+
}
376+
366377
result = OpaqueTypeArchetypeType::getNew(this, requirements.anchor,
367378
requirements.protos, superclass,
368379
requirements.layout);
369380
break;
370381
}
382+
}
371383
}
372384

373385
if (genericParam)

lib/AST/ProtocolConformance.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ ProtocolConformanceRef::subst(Type origType,
115115
// unless we're specifically substituting opaque types.
116116
if (auto origArchetype = origType->getAs<ArchetypeType>()) {
117117
if (!options.contains(SubstFlags::SubstituteOpaqueArchetypes)
118-
&& isa<OpaqueTypeArchetypeType>(origArchetype->getRoot())) {
118+
&& isa<OpaqueTypeArchetypeType>(origArchetype)) {
119119
return *this;
120120
}
121121
}

lib/AST/SubstitutionMap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
326326
// If we have an archetype, map out of the context so we can compute a
327327
// conformance access path.
328328
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
329-
if (!isa<OpaqueTypeArchetypeType>(archetype->getRoot())) {
329+
if (!isa<OpaqueTypeArchetypeType>(archetype)) {
330330
type = archetype->getInterfaceType()->getCanonicalType();
331331
}
332332
}

lib/AST/TypeWalker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ class Traversal : public TypeVisitor<Traversal, bool>
207207
bool visitArchetypeType(ArchetypeType *ty) {
208208
// If the root is an opaque archetype, visit its substitution replacement
209209
// types.
210-
if (auto opaqueRoot = dyn_cast<OpaqueTypeArchetypeType>(ty->getRoot())) {
211-
for (auto arg : opaqueRoot->getSubstitutions().getReplacementTypes()) {
210+
if (auto opaque = dyn_cast<OpaqueTypeArchetypeType>(ty)) {
211+
for (auto arg : opaque->getSubstitutions().getReplacementTypes()) {
212212
if (doIt(arg)) {
213213
return true;
214214
}

lib/IRGen/DebugTypeInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class DebugTypeInfo {
9393
bool isContextArchetype() const {
9494
if (auto archetype =
9595
Type->getWithoutSpecifierType()->getAs<ArchetypeType>()) {
96-
return !isa<OpaqueTypeArchetypeType>(archetype->getRoot());
96+
return !isa<OpaqueTypeArchetypeType>(archetype);
9797
}
9898
return false;
9999
}

lib/IRGen/GenArchetype.cpp

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

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

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

551567
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

0 commit comments

Comments
 (0)