Skip to content

Commit ba82053

Browse files
authored
Merge pull request #38450 from slavapestov/generic-environment-cleanup-redux
Re-apply #38384
2 parents 7c24d19 + 5570ed5 commit ba82053

File tree

8 files changed

+171
-248
lines changed

8 files changed

+171
-248
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,22 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
7676
/// generic signature.
7777
ArrayRef<Type> getContextTypes() const;
7878

79-
GenericEnvironment(GenericSignature signature,
80-
GenericSignatureBuilder *builder);
79+
explicit GenericEnvironment(GenericSignature signature);
8180

8281
friend ArchetypeType;
8382
friend GenericSignatureBuilder;
8483

85-
GenericSignatureBuilder *getGenericSignatureBuilder() const { return Builder; }
84+
GenericSignatureBuilder *getGenericSignatureBuilder() const;
8685

8786
friend QueryInterfaceTypeSubstitutions;
8887

88+
Type getOrCreateArchetypeFromInterfaceType(Type depType);
89+
90+
/// Retrieve the mapping for the given generic parameter, if present.
91+
///
92+
/// This is only useful when lazily populating a generic environment.
93+
Optional<Type> getMappingIfPresent(GenericParamKey key) const;
94+
8995
public:
9096
GenericSignature getGenericSignature() const {
9197
return Signature;
@@ -96,18 +102,12 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
96102
/// Create a new, "incomplete" generic environment that will be populated
97103
/// by calls to \c addMapping().
98104
static
99-
GenericEnvironment *getIncomplete(GenericSignature signature,
100-
GenericSignatureBuilder *builder);
105+
GenericEnvironment *getIncomplete(GenericSignature signature);
101106

102107
/// Add a mapping of a generic parameter to a specific type (which may be
103108
/// an archetype)
104109
void addMapping(GenericParamKey key, Type contextType);
105110

106-
/// Retrieve the mapping for the given generic parameter, if present.
107-
///
108-
/// This is only useful when lazily populating a generic environment.
109-
Optional<Type> getMappingIfPresent(GenericParamKey key) const;
110-
111111
/// Make vanilla new/delete illegal.
112112
void *operator new(size_t Bytes) = delete;
113113
void operator delete(void *Data) = delete;
@@ -151,6 +151,8 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
151151
mapConformanceRefIntoContext(Type conformingType,
152152
ProtocolConformanceRef conformance) const;
153153

154+
/// Returns a substitution map that sends every generic parameter to its
155+
/// corresponding archetype in this generic environment.
154156
SubstitutionMap getForwardingSubstitutionMap() const;
155157

156158
void dump(raw_ostream &os) const;

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -228,24 +228,15 @@ class GenericSignatureBuilder {
228228

229229
/// Lookup a nested type with the given name within this equivalence
230230
/// class.
231-
///
232-
/// \param otherConcreteTypes If non-null, will be filled in the all of the
233-
/// concrete types we found (other than the result) with the same name.
234231
TypeDecl *lookupNestedType(
235232
GenericSignatureBuilder &builder,
236-
Identifier name,
237-
SmallVectorImpl<TypeDecl *> *otherConcreteTypes = nullptr);
233+
Identifier name);
238234

239235
/// Retrieve the "anchor" type that canonically describes this equivalence
240236
/// class, for use in the canonical type.
241237
Type getAnchor(GenericSignatureBuilder &builder,
242238
TypeArrayView<GenericTypeParamType> genericParams);
243239

244-
/// Retrieve (or build) the contextual type corresponding to
245-
/// this equivalence class within the given generic environment.
246-
Type getTypeInContext(GenericSignatureBuilder &builder,
247-
GenericEnvironment *genericEnv);
248-
249240
/// Dump a debugging representation of this equivalence class,
250241
void dump(llvm::raw_ostream &out,
251242
GenericSignatureBuilder *builder = nullptr) const;
@@ -268,7 +259,7 @@ class GenericSignatureBuilder {
268259
unsigned numConformancesPresent;
269260
CanType superclassPresent;
270261
CanType concreteTypePresent;
271-
llvm::TinyPtrVector<TypeDecl *> types;
262+
TypeDecl *type = nullptr;
272263
};
273264

274265
/// Cached nested-type information, which contains the best declaration

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4165,8 +4165,7 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
41654165

41664166
// Create a generic environment and bind the opaque archetype to the
41674167
// opaque interface type from the decl's signature.
4168-
auto *builder = signature->getGenericSignatureBuilder();
4169-
auto *env = GenericEnvironment::getIncomplete(signature, builder);
4168+
auto *env = GenericEnvironment::getIncomplete(signature);
41704169
env->addMapping(GenericParamKey(opaqueInterfaceTy), newOpaque);
41714170
newOpaque->Environment = env;
41724171

@@ -4243,8 +4242,7 @@ GenericEnvironment *OpenedArchetypeType::getGenericEnvironment() const {
42434242
auto &ctx = thisType->getASTContext();
42444243
// Create a generic environment to represent the opened type.
42454244
auto signature = ctx.getOpenedArchetypeSignature(Opened);
4246-
auto *builder = signature->getGenericSignatureBuilder();
4247-
auto *env = GenericEnvironment::getIncomplete(signature, builder);
4245+
auto *env = GenericEnvironment::getIncomplete(signature);
42484246
env->addMapping(signature->getGenericParams()[0], thisType);
42494247
Environment = env;
42504248

@@ -4399,15 +4397,14 @@ GenericSignature::get(TypeArrayView<GenericTypeParamType> params,
43994397
}
44004398

44014399
GenericEnvironment *GenericEnvironment::getIncomplete(
4402-
GenericSignature signature,
4403-
GenericSignatureBuilder *builder) {
4400+
GenericSignature signature) {
44044401
auto &ctx = signature->getASTContext();
44054402

44064403
// Allocate and construct the new environment.
44074404
unsigned numGenericParams = signature->getGenericParams().size();
44084405
size_t bytes = totalSizeToAlloc<Type>(numGenericParams);
44094406
void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment));
4410-
return new (mem) GenericEnvironment(signature, builder);
4407+
return new (mem) GenericEnvironment(signature);
44114408
}
44124409

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

lib/AST/GenericEnvironment.cpp

Lines changed: 139 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/GenericSignatureBuilder.h"
2020
#include "swift/AST/ProtocolConformance.h"
21+
#include "swift/Basic/Defer.h"
22+
#include "GenericSignatureBuilderImpl.h"
2123

2224
using namespace swift;
2325

@@ -46,15 +48,24 @@ GenericEnvironment::getGenericParams() const {
4648
return Signature->getGenericParams();
4749
}
4850

49-
GenericEnvironment::GenericEnvironment(GenericSignature signature,
50-
GenericSignatureBuilder *builder)
51-
: Signature(signature), Builder(builder)
51+
GenericEnvironment::GenericEnvironment(GenericSignature signature)
52+
: Signature(signature)
5253
{
5354
// Clear out the memory that holds the context types.
5455
std::uninitialized_fill(getContextTypes().begin(), getContextTypes().end(),
5556
Type());
5657
}
5758

59+
GenericSignatureBuilder *GenericEnvironment::getGenericSignatureBuilder() const {
60+
if (Builder)
61+
return Builder;
62+
63+
const_cast<GenericEnvironment *>(this)->Builder
64+
= Signature->getGenericSignatureBuilder();
65+
66+
return Builder;
67+
}
68+
5869
void GenericEnvironment::addMapping(GenericParamKey key,
5970
Type contextType) {
6071
// Find the index into the parallel arrays of generic parameters and
@@ -64,7 +75,9 @@ void GenericEnvironment::addMapping(GenericParamKey key,
6475
assert(genericParams[index] == key && "Bad generic parameter");
6576

6677
// Add the mapping from the generic parameter to the context type.
67-
assert(getContextTypes()[index].isNull() && "Already recoded this mapping");
78+
assert(getContextTypes()[index].isNull() ||
79+
getContextTypes()[index]->is<ErrorType>() &&
80+
"Already recoded this mapping");
6881
getContextTypes()[index] = contextType;
6982
}
7083

@@ -107,6 +120,116 @@ Type TypeBase::mapTypeOutOfContext() {
107120
SubstFlags::AllowLoweredTypes);
108121
}
109122

123+
Type
124+
GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
125+
auto &builder = *getGenericSignatureBuilder();
126+
auto &ctx = builder.getASTContext();
127+
128+
auto resolved =
129+
builder.maybeResolveEquivalenceClass(
130+
depType,
131+
ArchetypeResolutionKind::CompleteWellFormed,
132+
/*wantExactPotentialArchetype=*/false);
133+
if (!resolved)
134+
return ErrorType::get(depType);
135+
136+
if (auto concrete = resolved.getAsConcreteType()) {
137+
return mapTypeIntoContext(concrete,
138+
builder.getLookupConformanceFn());
139+
}
140+
141+
auto *equivClass = resolved.getEquivalenceClass(builder);
142+
143+
auto genericParams = getGenericParams();
144+
Type anchor = equivClass->getAnchor(builder, genericParams);
145+
146+
// First, write an ErrorType to the location where this type is cached,
147+
// to catch re-entrant lookups that might arise from an invalid generic
148+
// signature (eg, <X where X == Array<X>>).
149+
ArchetypeType *parentArchetype = nullptr;
150+
GenericTypeParamType *genericParam = nullptr;
151+
if (auto depMemTy = anchor->getAs<DependentMemberType>()) {
152+
parentArchetype =
153+
getOrCreateArchetypeFromInterfaceType(depMemTy->getBase())
154+
->getAs<ArchetypeType>();
155+
if (!parentArchetype)
156+
return ErrorType::get(depMemTy);
157+
158+
auto name = depMemTy->getName();
159+
if (auto type = parentArchetype->getNestedTypeIfKnown(name))
160+
return *type;
161+
162+
parentArchetype->registerNestedType(name, ErrorType::get(ctx));
163+
} else {
164+
genericParam = anchor->castTo<GenericTypeParamType>();
165+
if (auto type = getMappingIfPresent(genericParam))
166+
return *type;
167+
addMapping(genericParam, ErrorType::get(ctx));
168+
}
169+
170+
Type result;
171+
172+
// If this equivalence class is mapped to a concrete type, produce that
173+
// type.
174+
if (equivClass->concreteType) {
175+
result = mapTypeIntoContext(equivClass->concreteType,
176+
builder.getLookupConformanceFn());
177+
} else {
178+
// Substitute into the superclass.
179+
Type superclass = equivClass->superclass;
180+
if (superclass && superclass->hasTypeParameter()) {
181+
superclass = mapTypeIntoContext(superclass,
182+
builder.getLookupConformanceFn());
183+
if (superclass->is<ErrorType>())
184+
superclass = Type();
185+
}
186+
187+
// Collect the protocol conformances for the archetype.
188+
SmallVector<ProtocolDecl *, 4> protos;
189+
for (const auto &conforms : equivClass->conformsTo) {
190+
auto proto = conforms.first;
191+
192+
if (!equivClass->isConformanceSatisfiedBySuperclass(proto))
193+
protos.push_back(proto);
194+
}
195+
196+
if (parentArchetype) {
197+
auto *depMemTy = anchor->castTo<DependentMemberType>();
198+
result = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy,
199+
protos, superclass,
200+
equivClass->layout);
201+
} else {
202+
result = PrimaryArchetypeType::getNew(ctx, this, genericParam,
203+
protos, superclass,
204+
equivClass->layout);
205+
}
206+
}
207+
208+
// Cache the new archetype for future lookups.
209+
if (auto depMemTy = anchor->getAs<DependentMemberType>()) {
210+
parentArchetype->registerNestedType(depMemTy->getName(), result);
211+
} else {
212+
addMapping(genericParam, result);
213+
}
214+
215+
return result;
216+
}
217+
218+
void ArchetypeType::resolveNestedType(
219+
std::pair<Identifier, Type> &nested) const {
220+
Type interfaceType = getInterfaceType();
221+
Type memberInterfaceType =
222+
DependentMemberType::get(interfaceType, nested.first);
223+
224+
Type result = getGenericEnvironment()->getOrCreateArchetypeFromInterfaceType(
225+
memberInterfaceType);
226+
227+
assert(!nested.second ||
228+
nested.second->isEqual(result) ||
229+
nested.second->is<ErrorType>());
230+
nested.second = result;
231+
}
232+
110233
Type QueryInterfaceTypeSubstitutions::operator()(SubstitutableType *type) const{
111234
if (auto gp = type->getAs<GenericTypeParamType>()) {
112235
// Find the index into the parallel arrays of generic parameters and
@@ -120,24 +243,18 @@ Type QueryInterfaceTypeSubstitutions::operator()(SubstitutableType *type) const{
120243
return Type();
121244

122245
// If the context type isn't already known, lazily create it.
123-
Type contextType = self->getContextTypes()[index];
124-
if (!contextType) {
125-
assert(self->Builder &&"Missing generic signature builder for lazy query");
126-
auto equivClass =
127-
self->Builder->resolveEquivalenceClass(
128-
type,
129-
ArchetypeResolutionKind::CompleteWellFormed);
130-
131-
auto mutableSelf = const_cast<GenericEnvironment *>(self);
132-
contextType = equivClass->getTypeInContext(*mutableSelf->Builder,
133-
mutableSelf);
134-
135-
// FIXME: Redundant mapping from key -> index.
136-
if (self->getContextTypes()[index].isNull())
137-
mutableSelf->addMapping(key, contextType);
138-
}
139-
140-
return contextType;
246+
auto mutableSelf = const_cast<GenericEnvironment *>(self);
247+
Type &contextType = mutableSelf->getContextTypes()[index];
248+
if (contextType)
249+
return contextType;
250+
251+
auto result = mutableSelf->getOrCreateArchetypeFromInterfaceType(type);
252+
253+
assert (!contextType ||
254+
contextType->isEqual(result) ||
255+
contextType->is<ErrorType>());
256+
contextType = result;
257+
return result;
141258
}
142259

143260
return Type();

lib/AST/GenericSignature.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,8 @@ CanGenericSignature GenericSignatureImpl::getCanonicalSignature() const {
247247

248248
GenericEnvironment *GenericSignatureImpl::getGenericEnvironment() const {
249249
if (GenericEnv == nullptr) {
250-
auto *builder = getGenericSignatureBuilder();
251250
const auto impl = const_cast<GenericSignatureImpl *>(this);
252-
impl->GenericEnv = GenericEnvironment::getIncomplete(this, builder);
251+
impl->GenericEnv = GenericEnvironment::getIncomplete(this);
253252
}
254253

255254
return GenericEnv;

0 commit comments

Comments
 (0)