Skip to content

Commit 09c57d3

Browse files
committed
AST: Fix some nested generics issues exposed by generic initializer inheritance
BoundGenericType::getSubsitutions() would only look at the bound generic arguments of the innermost type, ignoring parent types. However, it would then proceed to walk the AllArchetypes list of all outer generic parameter lists when forming the final result. The gatherAllSubstitutions() would also walk through parent types. As a result, outer generic parameters would appear multiple times. Simplify gatherAllSubstitutions() to just skip to the innermost BoundGenericType, and delegate to getSubsitutions() for the rest. Most calls to gatherAllSubstitutions() are from SILGen it seems, and fix only fixes one compiler_crasher. However an upcoming patch adds a new call to gatherAllSubstitutions() which caused some crashers to regress, so I'm going to fix it properly here.
1 parent 3e0ddba commit 09c57d3

File tree

5 files changed

+42
-64
lines changed

5 files changed

+42
-64
lines changed

include/swift/AST/Types.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,6 @@ class alignas(1 << TypeAlignInBits) TypeBase {
571571
/// stitched together from multiple lists of generic arguments.
572572
ArrayRef<Type> getAllGenericArgs(SmallVectorImpl<Type> &scratch);
573573

574-
/// Gather all of the substitutions used to produce the given specialized type
575-
/// from its unspecialized type.
576-
///
577-
/// \param scratchSpace The substitutions will be written into this scratch
578-
/// space if a single substitutions array cannot be returned.
579-
ArrayRef<Substitution> gatherAllSubstitutions(
580-
ModuleDecl *module,
581-
SmallVectorImpl<Substitution> &scratchSpace,
582-
LazyResolver *resolver,
583-
DeclContext *gpContext = nullptr);
584-
585574
/// Gather all of the substitutions used to produce the given specialized type
586575
/// from its unspecialized type.
587576
///

lib/AST/Module.cpp

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -696,15 +696,40 @@ ArrayRef<Substitution> BoundGenericType::getSubstitutions(
696696

697697
// Compute the set of substitutions.
698698
TypeSubstitutionMap substitutions;
699-
auto genericParams = gpContext->getGenericParamsOfContext();
700-
unsigned index = 0;
701-
for (Type arg : canon->getGenericArgs()) {
702-
auto gp = genericParams->getParams()[index++];
703-
auto archetype = gp->getArchetype();
704-
substitutions[archetype] = arg;
699+
700+
CanType parent(canon);
701+
auto *parentDC = gpContext;
702+
while (parent) {
703+
if (auto boundGeneric = dyn_cast<BoundGenericType>(parent)) {
704+
auto genericParams = parentDC->getGenericParamsOfContext();
705+
unsigned index = 0;
706+
707+
assert(boundGeneric->getGenericArgs().size() ==
708+
genericParams->getParams().size());
709+
710+
for (Type arg : boundGeneric->getGenericArgs()) {
711+
auto gp = genericParams->getParams()[index++];
712+
auto archetype = gp->getArchetype();
713+
substitutions[archetype] = arg;
714+
}
715+
716+
parent = CanType(boundGeneric->getParent());
717+
parentDC = parentDC->getParent();
718+
continue;
719+
}
720+
721+
if (auto nominal = dyn_cast<NominalType>(parent)) {
722+
parent = CanType(nominal->getParent());
723+
parentDC = parentDC->getParent();
724+
continue;
725+
}
726+
727+
llvm_unreachable("Not a nominal or bound generic type");
705728
}
706729

707730
// Collect all of the archetypes.
731+
auto *genericParams = gpContext->getGenericParamsOfContext();
732+
708733
SmallVector<ArchetypeType *, 2> allArchetypesList;
709734
ArrayRef<ArchetypeType *> allArchetypes = genericParams->getAllArchetypes();
710735
if (genericParams->getOuterParameters()) {
@@ -727,7 +752,7 @@ ArrayRef<Substitution> BoundGenericType::getSubstitutions(
727752
bool hasTypeVariables = canon->hasTypeVariable();
728753
SmallVector<Substitution, 4> resultSubstitutions;
729754
resultSubstitutions.resize(allArchetypes.size());
730-
index = 0;
755+
unsigned index = 0;
731756
for (auto archetype : allArchetypes) {
732757
// Substitute into the type.
733758
SubstOptions options;
@@ -913,9 +938,7 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol,
913938
if (!explicitConformanceType->isEqual(type)) {
914939
// Gather the substitutions we need to map the generic conformance to
915940
// the specialized conformance.
916-
SmallVector<Substitution, 4> substitutionsVec;
917-
auto substitutions = type->gatherAllSubstitutions(this, substitutionsVec,
918-
resolver,
941+
auto substitutions = type->gatherAllSubstitutions(this, resolver,
919942
explicitConformanceDC);
920943

921944
for (auto sub : substitutions) {

lib/AST/Type.cpp

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -331,25 +331,10 @@ ArrayRef<Type> TypeBase::getAllGenericArgs(SmallVectorImpl<Type> &scratch) {
331331

332332
ArrayRef<Substitution>
333333
TypeBase::gatherAllSubstitutions(Module *module,
334-
SmallVectorImpl<Substitution> &scratchSpace,
335334
LazyResolver *resolver,
336335
DeclContext *gpContext) {
337336
Type type(this);
338-
SmallVector<ArrayRef<Substitution>, 2> allSubstitutions;
339-
scratchSpace.clear();
340-
341337
while (type) {
342-
// Record the substitutions in a bound generic type.
343-
if (auto boundGeneric = type->getAs<BoundGenericType>()) {
344-
allSubstitutions.push_back(boundGeneric->getSubstitutions(module,
345-
resolver,
346-
gpContext));
347-
type = boundGeneric->getParent();
348-
if (gpContext)
349-
gpContext = gpContext->getParent();
350-
continue;
351-
}
352-
353338
// Skip to the parent of a nominal type.
354339
if (auto nominal = type->getAs<NominalType>()) {
355340
type = nominal->getParent();
@@ -358,36 +343,18 @@ TypeBase::gatherAllSubstitutions(Module *module,
358343
continue;
359344
}
360345

346+
// Return the substitutions in a bound generic type.
347+
// This walks any further parent types.
348+
if (auto boundGeneric = type->getAs<BoundGenericType>())
349+
return boundGeneric->getSubstitutions(module, resolver, gpContext);
350+
361351
llvm_unreachable("Not a nominal or bound generic type");
362352
}
363353

364-
// If there are no substitutions, return an empty array.
365-
if (allSubstitutions.empty())
366-
return { };
367-
368-
// If there is only one list of substitutions, return it. There's no
369-
// need to copy it.
370-
if (allSubstitutions.size() == 1)
371-
return allSubstitutions.front();
372-
373-
for (auto substitutions : allSubstitutions)
374-
scratchSpace.append(substitutions.begin(), substitutions.end());
375-
return scratchSpace;
354+
// Not a generic type.
355+
return { };
376356
}
377357

378-
ArrayRef<Substitution> TypeBase::gatherAllSubstitutions(Module *module,
379-
LazyResolver *resolver,
380-
DeclContext *gpContext){
381-
SmallVector<Substitution, 4> scratchSpace;
382-
auto subs = gatherAllSubstitutions(module, scratchSpace, resolver,
383-
gpContext);
384-
if (scratchSpace.empty())
385-
return subs;
386-
387-
return getASTContext().AllocateCopy(subs);
388-
}
389-
390-
391358
bool TypeBase::isUnspecializedGeneric() {
392359
CanType CT = getCanonicalType();
393360
if (CT.getPointer() != this)

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,11 @@ MetatypeInst *SILGenBuilder::createMetatype(SILLocation loc, SILType metatype) {
834834
case MetatypeRepresentation::Thick:
835835
case MetatypeRepresentation::ObjC: {
836836
// Walk the type recursively to look for substitutions we may need.
837-
SmallVector<Substitution, 2> subsBuf;
838837
theMetatype.getInstanceType().findIf([&](Type t) -> bool {
839838
if (!t->getAnyNominal())
840839
return false;
841840

842-
auto subs = t->gatherAllSubstitutions(SGM.SwiftModule, subsBuf, nullptr);
841+
auto subs = t->gatherAllSubstitutions(SGM.SwiftModule, nullptr);
843842
SGM.useConformancesFromSubstitutions(subs);
844843
return false;
845844
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See http://swift.org/LICENSE.txt for license information
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not --crash %target-swift-frontend %s -parse
8+
// RUN: not %target-swift-frontend %s -parse
99
// REQUIRES: asserts
1010
func<{struct c<T{enum S<T{struct A:a protocol a{associatedtype e}struct S<T:A.e

0 commit comments

Comments
 (0)