Skip to content

Commit 2dd49a8

Browse files
committed
Rework the relationship between generic environments and opaque archetypes.
Teach `GenericEnvironment` how to lazily create opaque type archetypes, performing the contextual substitutions as required but without building the "bound" generic signature until required. To get here, augment `GenericEnvironment` with knowledge of the purpose of the environment, whether it is for normal cases (any signature), an opened existential type, or an opaque type. For opaque types, store the opaque type declaration and substitution map, which we also use to uniquely find the generic environment. Among other things, this ensures that different opaque type archetypes within the same opaque type declaration are properly sharing a generic environment, which wasn't happening before.
1 parent f5e40fe commit 2dd49a8

File tree

6 files changed

+426
-276
lines changed

6 files changed

+426
-276
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ namespace swift {
3333
class ArchetypeType;
3434
class ASTContext;
3535
class GenericTypeParamType;
36+
class OpaqueTypeDecl;
37+
class OpenedArchetypeType;
3638
class SILModule;
3739
class SILType;
3840

@@ -57,11 +59,28 @@ class QueryInterfaceTypeSubstitutions {
5759
/// TypeBase::mapTypeOutOfContext().
5860
///
5961
class alignas(1 << DeclAlignInBits) GenericEnvironment final
60-
: private llvm::TrailingObjects<GenericEnvironment, Type> {
61-
GenericSignature Signature = GenericSignature();
62+
: private llvm::TrailingObjects<
63+
GenericEnvironment, OpaqueTypeDecl *, SubstitutionMap, Type> {
64+
public:
65+
enum class Kind {
66+
/// A normal generic environment, determined only by its generic
67+
/// signature.
68+
Normal,
69+
/// A generic environment describing an opened existential archetype.
70+
OpenedExistential,
71+
/// A generic environment describing an opaque type archetype.
72+
Opaque,
73+
};
74+
75+
private:
76+
mutable llvm::PointerIntPair<GenericSignature, 2, Kind> SignatureAndKind{
77+
GenericSignature(), Kind::Normal};
6278

6379
friend TrailingObjects;
80+
friend OpaqueTypeArchetypeType;
6481

82+
size_t numTrailingObjects(OverloadToken<OpaqueTypeDecl *>) const;
83+
size_t numTrailingObjects(OverloadToken<SubstitutionMap>) const;
6584
size_t numTrailingObjects(OverloadToken<Type>) const;
6685

6786
/// Retrieve the array containing the context types associated with the
@@ -74,7 +93,9 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
7493
/// generic signature.
7594
ArrayRef<Type> getContextTypes() const;
7695

77-
explicit GenericEnvironment(GenericSignature signature);
96+
explicit GenericEnvironment(GenericSignature signature, Kind kind);
97+
explicit GenericEnvironment(
98+
GenericSignature signature, OpaqueTypeDecl *opaque, SubstitutionMap subs);
7899

79100
friend ArchetypeType;
80101
friend QueryInterfaceTypeSubstitutions;
@@ -86,18 +107,39 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
86107
/// This is only useful when lazily populating a generic environment.
87108
Optional<Type> getMappingIfPresent(GenericParamKey key) const;
88109

110+
/// Get the "raw" generic signature, without substituting into opaque
111+
/// type's signature.
112+
GenericSignature getRawGenericSignature() const;
113+
89114
public:
90-
GenericSignature getGenericSignature() const {
91-
return Signature;
92-
}
115+
GenericSignature getGenericSignature() const;
116+
117+
Kind getKind() const { return SignatureAndKind.getInt(); }
93118

94119
TypeArrayView<GenericTypeParamType> getGenericParams() const;
95120

121+
/// Retrieve the opaque type declaration for a generic environment describing
122+
/// opaque types.
123+
OpaqueTypeDecl *getOpaqueTypeDecl() const;
124+
125+
/// Retrieve the substitutions applied to an opaque type declaration to
126+
/// create a generic environment.
127+
SubstitutionMap getOpaqueSubstitutions() const;
128+
96129
/// Create a new, "incomplete" generic environment that will be populated
97130
/// by calls to \c addMapping().
98131
static
99132
GenericEnvironment *getIncomplete(GenericSignature signature);
100133

134+
/// Create a new generic environment for an opened existential.
135+
static GenericEnvironment *forOpenedExistential(
136+
GenericSignature signature, const OpenedArchetypeType *type);
137+
138+
/// Create a new generic environment for an opaque type with the given set of
139+
/// outer substitutions.
140+
static GenericEnvironment *forOpaqueType(
141+
OpaqueTypeDecl *opaque, SubstitutionMap subs, AllocationArena arena);
142+
101143
/// Add a mapping of a generic parameter to a specific type (which may be
102144
/// an archetype)
103145
void addMapping(GenericParamKey key, Type contextType);
@@ -112,6 +154,12 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
112154
return Mem;
113155
}
114156

157+
/// For an opaque archetype environment, apply the substitutions.
158+
Type maybeApplyOpaqueTypeSubstitutions(Type type) const;
159+
160+
/// Compute the canonical interface type within this environment.
161+
Type getCanonicalInterfaceType(Type interfaceType);
162+
115163
/// Map an interface type to a contextual type.
116164
static Type mapTypeIntoContext(GenericEnvironment *genericEnv,
117165
Type type);

include/swift/AST/Types.h

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5548,37 +5548,36 @@ END_CAN_TYPE_WRAPPER(PrimaryArchetypeType, ArchetypeType)
55485548

55495549
/// An archetype that represents an opaque type.
55505550
class OpaqueTypeArchetypeType final : public ArchetypeType,
5551-
public llvm::FoldingSetNode,
55525551
private ArchetypeTrailingObjects<OpaqueTypeArchetypeType>
55535552
{
55545553
friend TrailingObjects;
55555554
friend ArchetypeType;
55565555
friend GenericSignatureBuilder;
55575556

5558-
/// The declaration that defines the opaque type.
5559-
OpaqueTypeDecl *OpaqueDecl;
5560-
/// The substitutions into the interface signature of the opaque type.
5561-
SubstitutionMap Substitutions;
5562-
55635557
/// A GenericEnvironment with this opaque archetype bound to the interface
55645558
/// type of the output type from the OpaqueDecl.
5565-
mutable GenericEnvironment *Environment = nullptr;
5566-
5559+
GenericEnvironment *Environment = nullptr;
5560+
5561+
friend class GenericEnvironment;
5562+
5563+
static OpaqueTypeArchetypeType *getNew(
5564+
GenericEnvironment *environment, Type interfaceType,
5565+
ArrayRef<ProtocolDecl*> conformsTo, Type superclass,
5566+
LayoutConstraint layout);
5567+
55675568
public:
55685569
/// Get an opaque archetype representing the underlying type of the given
55695570
/// opaque type decl's opaque param with ordinal `ordinal`. For example, in
55705571
/// `(some P, some Q)`, `some P`'s type param would have ordinal 0 and `some
55715572
/// Q`'s type param would have ordinal 1.
5572-
static OpaqueTypeArchetypeType *get(OpaqueTypeDecl *Decl, unsigned ordinal,
5573-
SubstitutionMap Substitutions);
5573+
static Type get(OpaqueTypeDecl *decl, unsigned ordinal, SubstitutionMap subs);
5574+
5575+
/// Retrieve the opaque type declaration.
5576+
OpaqueTypeDecl *getDecl() const;
5577+
5578+
/// Retrieve the set of substitutions applied to the opaque type.
5579+
SubstitutionMap getSubstitutions() const;
55745580

5575-
OpaqueTypeDecl *getDecl() const {
5576-
return OpaqueDecl;
5577-
}
5578-
SubstitutionMap getSubstitutions() const {
5579-
return Substitutions;
5580-
}
5581-
55825581
/// Get the generic signature used to build out this archetype. This is
55835582
/// equivalent to the OpaqueTypeDecl's interface generic signature, with
55845583
/// all of the generic parameters aside from the opaque type's interface
@@ -5605,22 +5604,12 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
56055604
/// then the underlying type of `some P` would be ordinal 0, and `some Q` would be ordinal 1.
56065605
unsigned getOrdinal() const;
56075606

5608-
static void Profile(llvm::FoldingSetNodeID &ID,
5609-
OpaqueTypeDecl *OpaqueDecl,
5610-
unsigned ordinal,
5611-
SubstitutionMap Substitutions);
5612-
5613-
void Profile(llvm::FoldingSetNodeID &ID) {
5614-
Profile(ID, getDecl(), getOrdinal(), getSubstitutions());
5615-
};
5616-
56175607
private:
5618-
OpaqueTypeArchetypeType(OpaqueTypeDecl *OpaqueDecl,
5619-
SubstitutionMap Substitutions,
5620-
RecursiveTypeProperties Props,
5621-
Type InterfaceType,
5622-
ArrayRef<ProtocolDecl*> ConformsTo,
5623-
Type Superclass, LayoutConstraint Layout);
5608+
OpaqueTypeArchetypeType(GenericEnvironment *environment,
5609+
RecursiveTypeProperties properties,
5610+
Type interfaceType,
5611+
ArrayRef<ProtocolDecl*> conformsTo,
5612+
Type superclass, LayoutConstraint layout);
56245613
};
56255614
BEGIN_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType)
56265615
END_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType)

lib/AST/ASTContext.cpp

Lines changed: 82 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,8 @@ struct ASTContext::Implementation {
414414
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
415415
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
416416
llvm::FoldingSet<LayoutConstraintInfo> LayoutConstraints;
417-
llvm::FoldingSet<OpaqueTypeArchetypeType> OpaqueArchetypes;
417+
llvm::DenseMap<std::pair<OpaqueTypeDecl *, SubstitutionMap>,
418+
GenericEnvironment *> OpaqueArchetypeEnvironments;
418419

419420
/// The set of function types.
420421
llvm::FoldingSet<FunctionType> FunctionTypes;
@@ -4280,77 +4281,62 @@ DependentMemberType *DependentMemberType::get(Type base,
42804281
return known;
42814282
}
42824283

4283-
OpaqueTypeArchetypeType *
4284-
OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl, unsigned ordinal,
4285-
SubstitutionMap Substitutions) {
4286-
auto opaqueParamType = Decl->getOpaqueGenericParams()[ordinal];
4287-
4288-
// TODO: We could attempt to preserve type sugar in the substitution map.
4289-
// Currently archetypes are assumed to be always canonical in many places,
4290-
// though, so doing so would require fixing those places.
4291-
Substitutions = Substitutions.getCanonical();
4292-
4293-
llvm::FoldingSetNodeID id;
4294-
Profile(id, Decl, ordinal, Substitutions);
4295-
4296-
auto &ctx = Decl->getASTContext();
4297-
4284+
/// Compute the recursive type properties of an opaque type archetype.
4285+
static RecursiveTypeProperties getOpaqueTypeArchetypeProperties(
4286+
SubstitutionMap subs) {
42984287
// An opaque type isn't contextually dependent like other archetypes, so
42994288
// by itself, it doesn't impose the "Has Archetype" recursive property,
43004289
// but the substituted types might. A disjoint "Has Opaque Archetype" tracks
43014290
// the presence of opaque archetypes.
43024291
RecursiveTypeProperties properties =
43034292
RecursiveTypeProperties::HasOpaqueArchetype;
4304-
for (auto type : Substitutions.getReplacementTypes()) {
4293+
for (auto type : subs.getReplacementTypes()) {
43054294
properties |= type->getRecursiveProperties();
43064295
}
4307-
4296+
return properties;
4297+
}
4298+
4299+
OpaqueTypeArchetypeType *OpaqueTypeArchetypeType::getNew(
4300+
GenericEnvironment *environment, Type interfaceType,
4301+
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
4302+
LayoutConstraint layout) {
4303+
auto properties = getOpaqueTypeArchetypeProperties(
4304+
environment->getOpaqueSubstitutions());
43084305
auto arena = getArena(properties);
4309-
4310-
llvm::FoldingSet<OpaqueTypeArchetypeType> &set
4311-
= ctx.getImpl().getArena(arena).OpaqueArchetypes;
4312-
4313-
{
4314-
void *insertPos; // Discarded because the work below may invalidate the
4315-
// insertion point inside the folding set
4316-
if (auto existing = set.FindNodeOrInsertPos(id, insertPos)) {
4317-
return existing;
4318-
}
4319-
}
4320-
4321-
auto reqs = Decl->getOpaqueInterfaceGenericSignature()
4322-
->getLocalRequirements(opaqueParamType);
4323-
auto superclass = reqs.superclass;
4324-
#if !DO_IT_CORRECTLY
4325-
// Ad-hoc substitute the generic parameters of the superclass.
4326-
// If we correctly applied the substitutions to the generic signature
4327-
// constraints above, this would be unnecessary.
4328-
if (superclass && superclass->hasTypeParameter()) {
4329-
superclass = superclass.subst(Substitutions);
4330-
}
4331-
#endif
4306+
auto size = OpaqueTypeArchetypeType::totalSizeToAlloc<
4307+
ProtocolDecl *, Type, LayoutConstraint>(
4308+
conformsTo.size(), superclass ? 1 : 0, layout ? 1 : 0);
4309+
ASTContext &ctx = interfaceType->getASTContext();
4310+
auto mem = ctx.Allocate(size, alignof(OpaqueTypeArchetypeType), arena);
4311+
return ::new (mem)
4312+
OpaqueTypeArchetypeType(environment, properties, interfaceType,
4313+
conformsTo, superclass, layout);
4314+
}
4315+
4316+
Type OpaqueTypeArchetypeType::get(
4317+
OpaqueTypeDecl *Decl, unsigned ordinal, SubstitutionMap Substitutions) {
4318+
// TODO: We could attempt to preserve type sugar in the substitution map.
4319+
// Currently archetypes are assumed to be always canonical in many places,
4320+
// though, so doing so would require fixing those places.
4321+
Substitutions = Substitutions.getCanonical();
43324322

4333-
auto mem = ctx.Allocate(
4334-
OpaqueTypeArchetypeType::totalSizeToAlloc<ProtocolDecl *, Type, LayoutConstraint>(
4335-
reqs.protos.size(), superclass ? 1 : 0, reqs.layout ? 1 : 0),
4336-
alignof(OpaqueTypeArchetypeType),
4337-
arena);
4323+
auto &ctx = Decl->getASTContext();
43384324

4339-
auto newOpaque = ::new (mem)
4340-
OpaqueTypeArchetypeType(Decl, Substitutions, properties, opaqueParamType,
4341-
reqs.protos, superclass, reqs.layout);
4325+
// Look for an opaque archetype environment in the appropriate arena.
4326+
auto properties = getOpaqueTypeArchetypeProperties(Substitutions);
4327+
auto arena = getArena(properties);
4328+
auto &environments
4329+
= ctx.getImpl().getArena(arena).OpaqueArchetypeEnvironments;
4330+
GenericEnvironment *env = environments[{Decl, Substitutions}];
43424331

4343-
// Look up the insertion point in the folding set again in case something
4344-
// invalidated it above.
4345-
{
4346-
void *insertPos;
4347-
auto existing = set.FindNodeOrInsertPos(id, insertPos);
4348-
(void)existing;
4349-
assert(!existing && "race to create opaque archetype?!");
4350-
set.InsertNode(newOpaque, insertPos);
4332+
// Create the environment if it's missing.
4333+
if (!env) {
4334+
env = GenericEnvironment::forOpaqueType(Decl, Substitutions, arena);
4335+
environments[{Decl, Substitutions}] = env;
43514336
}
43524337

4353-
return newOpaque;
4338+
auto opaqueParamType = Decl->getOpaqueGenericParams()[ordinal];
4339+
return env->getOrCreateArchetypeFromInterfaceType(opaqueParamType);
43544340
}
43554341

43564342
CanOpenedArchetypeType OpenedArchetypeType::get(Type existential,
@@ -4411,15 +4397,11 @@ GenericEnvironment *OpenedArchetypeType::getGenericEnvironment() const {
44114397
if (Environment)
44124398
return Environment;
44134399

4414-
auto thisType = Type(const_cast<OpenedArchetypeType*>(this));
4400+
auto thisType = const_cast<OpenedArchetypeType*>(this);
44154401
auto &ctx = thisType->getASTContext();
44164402
// Create a generic environment to represent the opened type.
44174403
auto signature = ctx.getOpenedArchetypeSignature(Opened);
4418-
auto *env = GenericEnvironment::getIncomplete(signature);
4419-
env->addMapping(signature.getGenericParams().front().getPointer(), thisType);
4420-
Environment = env;
4421-
4422-
return env;
4404+
return GenericEnvironment::forOpenedExistential(signature, thisType);
44234405
}
44244406

44254407
CanType OpenedArchetypeType::getAny(Type existential) {
@@ -4575,9 +4557,43 @@ GenericEnvironment *GenericEnvironment::getIncomplete(
45754557

45764558
// Allocate and construct the new environment.
45774559
unsigned numGenericParams = signature.getGenericParams().size();
4578-
size_t bytes = totalSizeToAlloc<Type>(numGenericParams);
4560+
size_t bytes = totalSizeToAlloc<OpaqueTypeDecl *, SubstitutionMap, Type>(
4561+
0, 0, numGenericParams);
4562+
void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment));
4563+
return new (mem) GenericEnvironment(signature, Kind::Normal);
4564+
}
4565+
4566+
/// Create a new generic environment for an opened archetype.
4567+
GenericEnvironment *GenericEnvironment::forOpenedExistential(
4568+
GenericSignature signature, const OpenedArchetypeType *type) {
4569+
auto &ctx = signature->getASTContext();
4570+
4571+
// Allocate and construct the new environment.
4572+
unsigned numGenericParams = signature.getGenericParams().size();
4573+
size_t bytes = totalSizeToAlloc<OpaqueTypeDecl *, SubstitutionMap, Type>(
4574+
0, 0, numGenericParams);
45794575
void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment));
4580-
return new (mem) GenericEnvironment(signature);
4576+
auto env = new (mem) GenericEnvironment(signature, Kind::OpenedExistential);
4577+
env->addMapping(
4578+
signature.getGenericParams().front(),
4579+
Type(const_cast<OpenedArchetypeType *>(type)));
4580+
return env;
4581+
}
4582+
4583+
/// Create a new generic environment for an opaque type with the given set of
4584+
/// outer substitutions.
4585+
GenericEnvironment *GenericEnvironment::forOpaqueType(
4586+
OpaqueTypeDecl *opaque, SubstitutionMap subs, AllocationArena arena) {
4587+
auto &ctx = opaque->getASTContext();
4588+
4589+
// Allocate and construct the new environment.
4590+
auto signature = opaque->getOpaqueInterfaceGenericSignature();
4591+
unsigned numGenericParams = signature.getGenericParams().size();
4592+
size_t bytes = totalSizeToAlloc<OpaqueTypeDecl *, SubstitutionMap, Type>(
4593+
1, 1, numGenericParams);
4594+
void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment), arena);
4595+
auto env = new (mem) GenericEnvironment(GenericSignature(), opaque, subs);
4596+
return env;
45814597
}
45824598

45834599
void DeclName::CompoundDeclName::Profile(llvm::FoldingSetNodeID &id,

0 commit comments

Comments
 (0)