Skip to content

Commit 2b67b0c

Browse files
authored
Merge pull request swiftlang#19601 from slavapestov/fewer-gsbs-2
Create fewer GenericSignatureBuilders, part 2
2 parents 3268b9d + 3b203a5 commit 2b67b0c

31 files changed

+241
-197
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
190190
Optional<ProtocolConformanceRef>
191191
lookupConformance(CanType depTy, ProtocolDecl *proto) const;
192192

193-
/// Return a vector of all generic parameters that are not subject to
194-
/// a concrete same-type constraint.
195-
SmallVector<GenericTypeParamType *, 2> getSubstitutableParams() const;
193+
/// Iterate over all generic parameters, passing a flag to the callback
194+
/// indicating if the generic parameter is canonical or not.
195+
void forEachParam(
196+
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const;
196197

197198
/// Check if the generic signature makes all generic parameters
198199
/// concrete.

include/swift/AST/ProtocolConformance.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,6 @@ class NormalProtocolConformance : public ProtocolConformance,
415415
{
416416
assert(!conformingType->hasArchetype() &&
417417
"ProtocolConformances should store interface types");
418-
differenceAndStoreConditionalRequirements();
419418
}
420419

421420
NormalProtocolConformance(Type conformingType,
@@ -428,7 +427,6 @@ class NormalProtocolConformance : public ProtocolConformance,
428427
{
429428
assert(!conformingType->hasArchetype() &&
430429
"ProtocolConformances should store interface types");
431-
differenceAndStoreConditionalRequirements();
432430
}
433431

434432
void resolveLazyInfo() const;

include/swift/AST/Witness.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ class Witness {
117117
return Witness(requirement);
118118
}
119119

120+
/// Create a witness for the given requirement.
121+
///
122+
/// Deserialized witnesses do not have a synthetic environment.
123+
static Witness forDeserialized(ValueDecl *decl,
124+
SubstitutionMap substitutions) {
125+
// TODO: It's probably a good idea to have a separate 'deserialized' bit.
126+
return Witness(decl, substitutions, nullptr, SubstitutionMap());
127+
}
128+
120129
/// Create a witness that requires substitutions.
121130
///
122131
/// \param decl The declaration for the witness.

include/swift/SIL/TypeSubstCloner.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,15 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
297297
if (SubsMap.empty())
298298
return false;
299299

300-
for (auto ParamType : Sig->getSubstitutableParams()) {
300+
bool Result = false;
301+
Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
302+
if (!Canonical)
303+
return;
301304
if (!Type(ParamType).subst(SubsMap)->isEqual(ParamType))
302-
return true;
303-
}
305+
Result = true;
306+
});
304307

305-
return false;
308+
return Result;
306309
}
307310

308311
enum { ForInlining = true };

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
58+
const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment
5959

6060
using DeclIDField = BCFixed<31>;
6161

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4384,14 +4384,15 @@ void SubstitutionMap::Storage::Profile(
43844384
// Profile those replacement types that corresponding to canonical generic
43854385
// parameters within the generic signature.
43864386
id.AddInteger(replacementTypes.size());
4387-
auto genericParams = genericSig->getGenericParams();
4388-
for (unsigned i : indices(genericParams)) {
4389-
auto gp = genericParams[i];
4390-
if (genericSig->isCanonicalTypeInContext(gp->getCanonicalType()))
4387+
4388+
unsigned i = 0;
4389+
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
4390+
if (canonical)
43914391
id.AddPointer(replacementTypes[i].getPointer());
43924392
else
43934393
id.AddPointer(nullptr);
4394-
}
4394+
i++;
4395+
});
43954396

43964397
// Conformances.
43974398
id.AddInteger(conformances.size());

lib/AST/GenericSignature.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -97,45 +97,42 @@ GenericSignature::getInnermostGenericParams() const {
9797
return params;
9898
}
9999

100-
101-
SmallVector<GenericTypeParamType *, 2>
102-
GenericSignature::getSubstitutableParams() const {
100+
void GenericSignature::forEachParam(
101+
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const {
103102
// Figure out which generic parameters are concrete or same-typed to another
104-
// generic parameter.
103+
// type parameter.
105104
auto genericParams = getGenericParams();
106-
auto genericParamsAreNotSubstitutable =
107-
SmallVector<bool, 4>(genericParams.size(), false);
105+
auto genericParamsAreCanonical =
106+
SmallVector<bool, 4>(genericParams.size(), true);
107+
108108
for (auto req : getRequirements()) {
109109
if (req.getKind() != RequirementKind::SameType) continue;
110110

111111
GenericTypeParamType *gp;
112112
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
113-
// If two generic parameters are same-typed, then the left-hand one
114-
// is canonical.
113+
// If two generic parameters are same-typed, then the right-hand one
114+
// is non-canonical.
115+
assert(req.getFirstType()->is<GenericTypeParamType>());
115116
gp = secondGP;
116117
} else {
117-
// If an associated type is same-typed, it doesn't constrain the generic
118-
// parameter itself.
119-
if (req.getSecondType()->isTypeParameter()) continue;
120-
121-
// Otherwise, the generic parameter is concrete.
118+
// Otherwise, the right-hand side is an associated type or concrete type,
119+
// and the left-hand one is non-canonical.
122120
gp = req.getFirstType()->getAs<GenericTypeParamType>();
123121
if (!gp) continue;
122+
123+
// If an associated type is same-typed, it doesn't constrain the generic
124+
// parameter itself. That is, if T == U.Foo, then T is canonical, whereas
125+
// U.Foo is not.
126+
if (req.getSecondType()->isTypeParameter()) continue;
124127
}
125128

126129
unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
127-
genericParamsAreNotSubstitutable[index] = true;
130+
genericParamsAreCanonical[index] = false;
128131
}
129132

130-
// Collect the generic parameters that are substitutable.
131-
SmallVector<GenericTypeParamType *, 2> result;
132-
for (auto index : indices(genericParams)) {
133-
auto gp = genericParams[index];
134-
if (!genericParamsAreNotSubstitutable[index])
135-
result.push_back(gp);
136-
}
137-
138-
return result;
133+
// Call the callback with each parameter and the result of the above analysis.
134+
for (auto index : indices(genericParams))
135+
callback(genericParams[index], genericParamsAreCanonical[index]);
139136
}
140137

141138
bool GenericSignature::areAllParamsConcrete() const {

lib/AST/ProtocolConformance.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,6 @@ SpecializedProtocolConformance::SpecializedProtocolConformance(
886886
GenericSubstitutions(substitutions)
887887
{
888888
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
889-
computeConditionalRequirements();
890889
}
891890

892891
void SpecializedProtocolConformance::computeConditionalRequirements() const {

lib/AST/SubstitutionMap.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,19 @@ SubstitutionMap SubstitutionMap::get(GenericSignature *genericSig,
200200
// Form the replacement types.
201201
SmallVector<Type, 4> replacementTypes;
202202
replacementTypes.reserve(genericSig->getGenericParams().size());
203-
for (auto gp : genericSig->getGenericParams()) {
203+
204+
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
204205
// Don't eagerly form replacements for non-canonical generic parameters.
205-
if (!genericSig->isCanonicalTypeInContext(gp->getCanonicalType())) {
206+
if (!canonical) {
206207
replacementTypes.push_back(Type());
207-
continue;
208+
return;
208209
}
209210

210211
// Record the replacement.
211212
Type replacement = Type(gp).subst(subs, lookupConformance,
212213
SubstFlags::UseErrorType);
213214
replacementTypes.push_back(replacement);
214-
}
215+
});
215216

216217
// Form the stored conformances.
217218
SmallVector<ProtocolConformanceRef, 4> conformances;
@@ -318,6 +319,20 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
318319
if (!type->isTypeParameter())
319320
return None;
320321

322+
auto genericSig = getGenericSignature();
323+
324+
// Fast path
325+
unsigned index = 0;
326+
for (auto reqt : genericSig->getRequirements()) {
327+
if (reqt.getKind() == RequirementKind::Conformance) {
328+
if (reqt.getFirstType()->isEqual(type) &&
329+
reqt.getSecondType()->isEqual(proto->getDeclaredType()))
330+
return getConformances()[index];
331+
332+
index++;
333+
}
334+
}
335+
321336
// Retrieve the starting conformance from the conformance map.
322337
auto getInitialConformance =
323338
[&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
@@ -338,8 +353,6 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
338353
return None;
339354
};
340355

341-
auto genericSig = getGenericSignature();
342-
343356
// If the type doesn't conform to this protocol, the result isn't formed
344357
// from these requirements.
345358
if (!genericSig->conformsToProtocol(type, proto)) {

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,15 @@ namespace {
313313
GenericSignature *sig = asImpl().getGenericSignature();
314314
assert(sig);
315315
auto canSig = sig->getCanonicalSignature();
316-
317-
for (auto param : canSig->getGenericParams()) {
316+
317+
canSig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
318318
// Currently, there are only type parameters. The parameter is a key
319319
// argument if it's canonical in its generic context.
320320
asImpl().addGenericParameter(GenericParamKind::Type,
321-
/*key argument*/ canSig->isCanonicalTypeInContext(param),
322-
/*extra argument*/ false);
323-
}
324-
321+
/*key argument*/ canonical,
322+
/*extra argument*/ false);
323+
});
324+
325325
// Pad the structure up to four bytes for the following requirements.
326326
unsigned padding = (unsigned) -canSig->getGenericParams().size() & 3;
327327
for (unsigned i = 0; i < padding; ++i)

0 commit comments

Comments
 (0)