Skip to content

Commit d484e12

Browse files
authored
Merge pull request #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

lib/IRGen/GenReflection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ getRuntimeVersionThatSupportsDemanglingType(CanType type) {
200200
if (type->hasOpaqueArchetype()) {
201201
auto hasOpaqueAssocType = type.findIf([](CanType t) -> bool {
202202
if (auto a = dyn_cast<ArchetypeType>(t)) {
203-
return isa<OpaqueTypeArchetypeType>(a->getRoot()) &&
203+
return isa<OpaqueTypeArchetypeType>(a) &&
204204
a->getInterfaceType()->is<DependentMemberType>();
205205
}
206206
return false;

lib/IRGen/Outlining.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,10 @@ irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
117117
GenericEnvironment *env = nullptr;
118118
loweredType.findIf([&env](Type t) -> bool {
119119
if (auto arch = t->getAs<ArchetypeType>()) {
120-
auto root = arch->getRoot();
121-
if (!isa<PrimaryArchetypeType>(root) &&
122-
!isa<VariadicSequenceType>(root))
120+
if (!isa<PrimaryArchetypeType>(arch) &&
121+
!isa<VariadicSequenceType>(arch))
123122
return false;
124-
env = root->getGenericEnvironment();
123+
env = arch->getGenericEnvironment();
125124
return true;
126125
}
127126
return false;

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,17 @@ static llvm::cl::opt<bool> AllowCriticalEdges("allow-critical-edges",
8686
/// Returns true if A is an opened existential type or is equal to an
8787
/// archetype from F's generic context.
8888
static bool isArchetypeValidInFunction(ArchetypeType *A, const SILFunction *F) {
89-
auto root = A->getRoot();
90-
if (!isa<PrimaryArchetypeType>(root) && !isa<SequenceArchetypeType>(root))
89+
if (!isa<PrimaryArchetypeType>(A) && !isa<SequenceArchetypeType>(A))
9190
return true;
92-
if (isa<OpenedArchetypeType>(root))
91+
if (isa<OpenedArchetypeType>(A))
9392
return true;
94-
if (isa<OpaqueTypeArchetypeType>(root))
93+
if (isa<OpaqueTypeArchetypeType>(A))
9594
return true;
9695

9796
// Ok, we have a primary archetype, make sure it is in the nested generic
9897
// environment of our caller.
9998
if (auto *genericEnv = F->getGenericEnvironment())
100-
if (root->getGenericEnvironment() == genericEnv)
99+
if (A->getGenericEnvironment() == genericEnv)
101100
return true;
102101

103102
return false;

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,11 +1092,11 @@ shouldBePartiallySpecialized(Type Replacement,
10921092
llvm::SmallSetVector<ArchetypeType *, 2> UsedArchetypes;
10931093
Replacement.visit([&](Type Ty) {
10941094
if (auto Archetype = Ty->getAs<ArchetypeType>()) {
1095-
if (auto Primary = dyn_cast<PrimaryArchetypeType>(Archetype->getRoot())) {
1095+
if (auto Primary = dyn_cast<PrimaryArchetypeType>(Archetype)) {
10961096
UsedArchetypes.insert(Primary);
10971097
}
10981098

1099-
if (auto Seq = dyn_cast<SequenceArchetypeType>(Archetype->getRoot())) {
1099+
if (auto Seq = dyn_cast<SequenceArchetypeType>(Archetype)) {
11001100
UsedArchetypes.insert(Seq);
11011101
}
11021102
}
@@ -1322,11 +1322,11 @@ void FunctionSignaturePartialSpecializer::collectUsedCallerArchetypes(
13221322
// Add used generic parameters/archetypes.
13231323
Replacement.visit([&](Type Ty) {
13241324
if (auto Archetype = Ty->getAs<ArchetypeType>()) {
1325-
if (auto Primary = dyn_cast<PrimaryArchetypeType>(Archetype->getRoot())) {
1325+
if (auto Primary = dyn_cast<PrimaryArchetypeType>(Archetype)) {
13261326
UsedCallerArchetypes.insert(Primary);
13271327
}
13281328

1329-
if (auto Seq = dyn_cast<SequenceArchetypeType>(Archetype->getRoot())) {
1329+
if (auto Seq = dyn_cast<SequenceArchetypeType>(Archetype)) {
13301330
UsedCallerArchetypes.insert(Seq);
13311331
}
13321332
}

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,8 +2849,8 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
28492849
// Handle opaque archetypes.
28502850
if (auto arch1 = type1->getAs<ArchetypeType>()) {
28512851
auto arch2 = type2->castTo<ArchetypeType>();
2852-
auto opaque1 = cast<OpaqueTypeArchetypeType>(arch1->getRoot());
2853-
auto opaque2 = cast<OpaqueTypeArchetypeType>(arch2->getRoot());
2852+
auto opaque1 = cast<OpaqueTypeArchetypeType>(arch1);
2853+
auto opaque2 = cast<OpaqueTypeArchetypeType>(arch2);
28542854
assert(opaque1->getDecl() == opaque2->getDecl());
28552855
assert(opaque1->getCanonicalInterfaceType(arch1->getInterfaceType())->isEqual(
28562856
opaque2->getCanonicalInterfaceType(arch2->getInterfaceType())));

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,14 +692,15 @@ static Type replaceArchetypesWithTypeVariables(ConstraintSystem &cs,
692692
return found->second;
693693

694694
if (auto archetypeType = dyn_cast<ArchetypeType>(origType)) {
695-
auto root = archetypeType->getRoot();
696695
// We leave opaque types and their nested associated types alone here.
697696
// They're globally available.
698-
if (isa<OpaqueTypeArchetypeType>(root))
697+
if (isa<OpaqueTypeArchetypeType>(archetypeType))
699698
return origType;
699+
700+
auto root = archetypeType->getRoot();
700701
// For other nested types, fail here so the default logic in subst()
701702
// for nested types applies.
702-
else if (root != archetypeType)
703+
if (root != archetypeType)
703704
return Type();
704705

705706
auto locator = cs.getConstraintLocator({});

test/Interpreter/named_opaque_result_types.swift

Lines changed: 29 additions & 3 deletions
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
@@ -34,8 +34,7 @@ struct X<T, U: Hashable>: P {
3434
func f() -> <
3535
R1: Collection, R2: Collection where R1.Element == T, R2.Element == U
3636
> (R1, R2) {
37-
// FIXME: Use unzipCollection here
38-
return (Array(data.map { $0.0 }), Set(data.map { $0.1 }))
37+
return unzipCollection(data)
3938
}
4039
}
4140

@@ -62,6 +61,22 @@ if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) {
6261
// CHECK: {{["Hello", "World", "!"]|too old}}
6362
print(x3.1)
6463

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+
6580
// CHECK: {{(Array<Int>, Set<String>)|too old}}
6681
let paType = getP_A(X<Int, String>.self)
6782
print(paType)
@@ -71,6 +86,17 @@ if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) {
7186
print("too old")
7287
print("too old")
7388
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("!")
99+
74100
print("too old")
75101
print("too old")
76102
}

0 commit comments

Comments
 (0)