Skip to content

Commit 430c1d8

Browse files
committed
AST: Use PackElementType to model references to pack elements of outer expansions
1 parent dffc55e commit 430c1d8

12 files changed

+181
-54
lines changed

include/swift/AST/InFlightSubstitution.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,9 @@ class InFlightSubstitution {
4949
InFlightSubstitution(const InFlightSubstitution &) = delete;
5050
InFlightSubstitution &operator=(const InFlightSubstitution &) = delete;
5151

52-
// TODO: when we add PackElementType, we should recognize it during
53-
// substitution and either call different methods on this class or
54-
// pass an extra argument for the pack-expansion depth D. We should
55-
// be able to rely on that to mark a pack-element reference instead
56-
// of checking whether the original type was a pack. Substitution
57-
// should use the D'th entry from the end of ActivePackExpansions to
58-
// guide the element substitution:
59-
// - project the given index of the pack substitution
60-
// - wrap it in a PackElementType if it's a subst expansion
61-
// - the depth of that PackElementType is the number of subst
62-
// expansions between the depth entry and the end of
63-
// ActivePackExpansions
64-
6552
/// Perform primitive substitution on the given type. Returns Type()
6653
/// if the type should not be substituted as a whole.
67-
Type substType(SubstitutableType *origType);
54+
Type substType(SubstitutableType *origType, unsigned level);
6855

6956
/// Perform primitive conformance lookup on the given type.
7057
ProtocolConformanceRef lookupConformance(CanType dependentType,

include/swift/AST/Type.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ enum class SubstFlags {
151151
/// Map member types to their desugared witness type.
152152
DesugarMemberTypes = 0x02,
153153
/// Substitute types involving opaque type archetypes.
154-
SubstituteOpaqueArchetypes = 0x04
154+
SubstituteOpaqueArchetypes = 0x04,
155+
/// Don't increase pack expansion level for free pack references.
156+
/// Do not introduce new usages of this flag.
157+
/// FIXME: Remove this.
158+
PreservePackExpansionLevel = 0x08,
155159
};
156160

157161
/// Options for performing substitutions into a type.

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,8 @@ static Type getTypeForDWARFMangling(Type t) {
659659
return t;
660660
},
661661
MakeAbstractConformanceForGenericType(),
662-
SubstFlags::AllowLoweredTypes);
662+
SubstFlags::AllowLoweredTypes |
663+
SubstFlags::PreservePackExpansionLevel);
663664
}
664665

665666
std::string ASTMangler::mangleTypeForDebugger(Type Ty, GenericSignature sig) {

lib/AST/GenericEnvironment.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,8 @@ Type TypeBase::mapTypeOutOfContext() {
432432
assert(!hasTypeParameter() && "already have an interface type");
433433
return Type(this).subst(MapTypeOutOfContext(),
434434
MakeAbstractConformanceForGenericType(),
435-
SubstFlags::AllowLoweredTypes);
435+
SubstFlags::AllowLoweredTypes |
436+
SubstFlags::PreservePackExpansionLevel);
436437
}
437438

438439
class GenericEnvironment::NestedTypeStorage
@@ -637,7 +638,8 @@ Type GenericEnvironment::mapTypeIntoContext(
637638
type = maybeApplyOuterContextSubstitutions(type);
638639
Type result = type.subst(QueryInterfaceTypeSubstitutions(this),
639640
lookupConformance,
640-
SubstFlags::AllowLoweredTypes);
641+
SubstFlags::AllowLoweredTypes |
642+
SubstFlags::PreservePackExpansionLevel);
641643
assert((!result->hasTypeParameter() || result->hasError() ||
642644
getKind() == Kind::Opaque) &&
643645
"not fully substituted");
@@ -787,16 +789,19 @@ GenericEnvironment::mapElementTypeIntoPackContext(Type type) const {
787789
// Map element archetypes to the pack archetypes by converting
788790
// element types to interface types and adding the isParameterPack
789791
// bit. Then, map type parameters to archetypes.
790-
return type.subst([&](SubstitutableType *type) {
791-
auto *genericParam = type->getAs<GenericTypeParamType>();
792-
if (!genericParam)
793-
return Type();
794-
795-
if (auto *packParam = packParamForElement[{genericParam}])
796-
return substitutions(packParam);
797-
798-
return substitutions(genericParam);
799-
}, LookUpConformanceInSignature(sig.getPointer()));
792+
return type.subst(
793+
[&](SubstitutableType *type) {
794+
auto *genericParam = type->getAs<GenericTypeParamType>();
795+
if (!genericParam)
796+
return Type();
797+
798+
if (auto *packParam = packParamForElement[{genericParam}])
799+
return substitutions(packParam);
800+
801+
return substitutions(genericParam);
802+
},
803+
LookUpConformanceInSignature(sig.getPointer()),
804+
SubstFlags::PreservePackExpansionLevel);
800805
}
801806

802807
namespace {

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() cons
130130
return archetypeType->getInterfaceType();
131131
return type;
132132
},
133-
MakeAbstractConformanceForGenericType());
133+
MakeAbstractConformanceForGenericType(),
134+
SubstFlags::PreservePackExpansionLevel);
134135
return ProtocolConformanceRef(concrete);
135136
} else if (isPack()) {
136137
return getPack()->subst(
@@ -139,7 +140,8 @@ ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() cons
139140
return archetypeType->getInterfaceType();
140141
return type;
141142
},
142-
MakeAbstractConformanceForGenericType());
143+
MakeAbstractConformanceForGenericType(),
144+
SubstFlags::PreservePackExpansionLevel);
143145
}
144146

145147
return *this;

lib/AST/RequirementEnvironment.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ RequirementEnvironment::RequirementEnvironment(
6969
MakeAbstractConformanceForGenericType();
7070

7171
auto substConcreteType = concreteType.subst(
72-
conformanceToWitnessThunkTypeFn, conformanceToWitnessThunkConformanceFn);
72+
conformanceToWitnessThunkTypeFn,
73+
conformanceToWitnessThunkConformanceFn,
74+
SubstFlags::PreservePackExpansionLevel);
7375

7476
// Calculate the depth at which the requirement's generic parameters
7577
// appear in the witness thunk signature.

lib/AST/SubstitutionMap.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,9 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
440440
}
441441

442442
SubstitutionMap SubstitutionMap::mapReplacementTypesOutOfContext() const {
443-
return subst(MapTypeOutOfContext(), MakeAbstractConformanceForGenericType());
443+
return subst(MapTypeOutOfContext(),
444+
MakeAbstractConformanceForGenericType(),
445+
SubstFlags::PreservePackExpansionLevel);
444446
}
445447

446448
SubstitutionMap SubstitutionMap::subst(SubstitutionMap subMap,
@@ -829,5 +831,7 @@ SubstitutionMap SubstitutionMap::mapIntoTypeExpansionContext(
829831
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
830832
context.getContext(), context.getResilienceExpansion(),
831833
context.isWholeModuleContext());
832-
return this->subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
834+
return this->subst(replacer, replacer,
835+
SubstFlags::SubstituteOpaqueArchetypes |
836+
SubstFlags::PreservePackExpansionLevel);
833837
}

lib/AST/TypeSubstitution.cpp

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ CanGenericFunctionType::substGenericArgs(SubstitutionMap subs) const {
9292
return cast<FunctionType>(
9393
getPointer()->substGenericArgs(subs)->getCanonicalType());
9494
}
95+
9596
static Type getMemberForBaseType(InFlightSubstitution &IFS,
9697
Type origBase,
9798
Type substBase,
@@ -386,16 +387,35 @@ void InFlightSubstitution::expandPackExpansionShape(Type origShape,
386387
ActivePackExpansions.pop_back();
387388
}
388389

389-
Type InFlightSubstitution::substType(SubstitutableType *origType) {
390+
Type InFlightSubstitution::substType(SubstitutableType *origType,
391+
unsigned level) {
390392
auto substType = BaselineSubstType(origType);
391393
if (!substType || ActivePackExpansions.empty())
392394
return substType;
393395

396+
auto outerExpansions = ArrayRef(ActivePackExpansions).drop_back(level);
397+
auto innerExpansions = ArrayRef(ActivePackExpansions).take_back(level);
398+
399+
unsigned outerLevel = 0;
400+
if (!getOptions().contains(SubstFlags::PreservePackExpansionLevel)) {
401+
for (const auto &activeExpansion : outerExpansions) {
402+
if (activeExpansion.isSubstExpansion)
403+
++outerLevel;
404+
}
405+
}
406+
407+
unsigned innerLevel = 0;
408+
for (const auto &activeExpansion : innerExpansions) {
409+
if (activeExpansion.isSubstExpansion)
410+
++innerLevel;
411+
}
412+
394413
auto substPackType = substType->getAs<PackType>();
395414
if (!substPackType)
396-
return substType;
415+
return substType->increasePackElementLevel(outerLevel);
416+
417+
auto &activeExpansion = outerExpansions.back();
397418

398-
auto &activeExpansion = ActivePackExpansions.back();
399419
auto index = activeExpansion.expansionIndex;
400420
assert(index < substPackType->getNumElements() &&
401421
"replacement for pack parameter did not have the right "
@@ -404,12 +424,14 @@ Type InFlightSubstitution::substType(SubstitutableType *origType) {
404424
if (activeExpansion.isSubstExpansion) {
405425
assert(substEltType->is<PackExpansionType>() &&
406426
"substituted shape mismatch: expected an expansion component");
407-
substEltType = substEltType->castTo<PackExpansionType>()->getPatternType();
427+
return substEltType->increasePackElementLevel(outerLevel)
428+
->castTo<PackExpansionType>()->getPatternType()
429+
->increasePackElementLevel(innerLevel);
408430
} else {
409431
assert(!substEltType->is<PackExpansionType>() &&
410432
"substituted shape mismatch: expected a scalar component");
433+
return substEltType->increasePackElementLevel(outerLevel);
411434
}
412-
return substEltType;
413435
}
414436

415437
ProtocolConformanceRef
@@ -440,7 +462,8 @@ bool InFlightSubstitution::isInvariant(Type derivedType) const {
440462
|| !derivedType->hasOpaqueArchetype());
441463
}
442464

443-
static Type substType(Type derivedType, InFlightSubstitution &IFS) {
465+
static Type substType(Type derivedType, unsigned level,
466+
InFlightSubstitution &IFS) {
444467
// Handle substitutions into generic function types.
445468
if (auto genericFnType = derivedType->getAs<GenericFunctionType>()) {
446469
return substGenericFunctionType(genericFnType, IFS);
@@ -493,21 +516,28 @@ static Type substType(Type derivedType, InFlightSubstitution &IFS) {
493516
if (auto aliasTy = dyn_cast<TypeAliasType>(type)) {
494517
Type parentTy;
495518
if (auto origParentTy = aliasTy->getParent())
496-
parentTy = substType(origParentTy, IFS);
497-
auto underlyingTy = substType(aliasTy->getSinglyDesugaredType(), IFS);
519+
parentTy = substType(origParentTy, level, IFS);
520+
auto underlyingTy = substType(aliasTy->getSinglyDesugaredType(),
521+
level, IFS);
498522
if (parentTy && parentTy->isExistentialType())
499523
return underlyingTy;
500524
auto subMap = aliasTy->getSubstitutionMap().subst(IFS);
501525
return Type(TypeAliasType::get(aliasTy->getDecl(), parentTy,
502526
subMap, underlyingTy));
503527
}
504528

529+
unsigned currentLevel = level;
530+
if (auto elementTy = dyn_cast<PackElementType>(type)) {
531+
type = elementTy->getPackType().getPointer();
532+
currentLevel += elementTy->getLevel();
533+
}
534+
505535
// We only substitute for substitutable types and dependent member types.
506536

507537
// For dependent member types, we may need to look up the member if the
508538
// base is resolved to a non-dependent type.
509539
if (auto depMemTy = dyn_cast<DependentMemberType>(type)) {
510-
auto newBase = substType(depMemTy->getBase(), IFS);
540+
auto newBase = substType(depMemTy->getBase(), currentLevel, IFS);
511541
return getMemberForBaseType(IFS,
512542
depMemTy->getBase(), newBase,
513543
depMemTy->getAssocType(),
@@ -525,7 +555,7 @@ static Type substType(Type derivedType, InFlightSubstitution &IFS) {
525555
return None;
526556

527557
// If we have a substitution for this type, use it.
528-
if (auto known = IFS.substType(substOrig)) {
558+
if (auto known = IFS.substType(substOrig, currentLevel)) {
529559
if (IFS.shouldSubstituteOpaqueArchetypes() &&
530560
isa<OpaqueTypeArchetypeType>(substOrig) &&
531561
known->getCanonicalType() == substOrig->getCanonicalType())
@@ -550,40 +580,40 @@ static Type substType(Type derivedType, InFlightSubstitution &IFS) {
550580
}
551581

552582
// For nested archetypes, we can substitute the parent.
553-
auto parent = origArchetype->getParent();
554-
assert(parent && "Not a nested archetype");
583+
Type origParent = origArchetype->getParent();
584+
assert(origParent && "Not a nested archetype");
555585

556586
// Substitute into the parent type.
557-
Type substParent = substType(parent, IFS);
587+
Type substParent = substType(origParent, currentLevel, IFS);
558588

559589
// If the parent didn't change, we won't change.
560-
if (substParent.getPointer() == parent)
590+
if (substParent.getPointer() == origArchetype->getParent())
561591
return Type(type);
562592

563593
// Get the associated type reference from a child archetype.
564594
AssociatedTypeDecl *assocType = origArchetype->getInterfaceType()
565595
->castTo<DependentMemberType>()->getAssocType();
566596

567-
return getMemberForBaseType(IFS, parent, substParent,
597+
return getMemberForBaseType(IFS, origArchetype->getParent(), substParent,
568598
assocType, assocType->getName());
569599
});
570600
}
571601

572602
Type Type::subst(SubstitutionMap substitutions,
573603
SubstOptions options) const {
574604
InFlightSubstitutionViaSubMap IFS(substitutions, options);
575-
return substType(*this, IFS);
605+
return substType(*this, /*level=*/0, IFS);
576606
}
577607

578608
Type Type::subst(TypeSubstitutionFn substitutions,
579609
LookupConformanceFn conformances,
580610
SubstOptions options) const {
581611
InFlightSubstitution IFS(substitutions, conformances, options);
582-
return substType(*this, IFS);
612+
return substType(*this, /*level=*/0, IFS);
583613
}
584614

585615
Type Type::subst(InFlightSubstitution &IFS) const {
586-
return substType(*this, IFS);
616+
return substType(*this, /*level=*/0, IFS);
587617
}
588618

589619
//===----------------------------------------------------------------------===//

lib/IRGen/GenType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2010,7 +2010,8 @@ CanType TypeConverter::getExemplarType(CanType contextTy) {
20102010
return type;
20112011
},
20122012
MakeAbstractConformanceForGenericType(),
2013-
SubstFlags::AllowLoweredTypes);
2013+
SubstFlags::AllowLoweredTypes |
2014+
SubstFlags::PreservePackExpansionLevel);
20142015
return CanType(exemplified);
20152016
}
20162017
}

lib/SIL/IR/SILFunction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,8 @@ SILType GenericEnvironment::mapTypeIntoContext(SILModule &M,
451451
return type.subst(M,
452452
QueryInterfaceTypeSubstitutions(this),
453453
LookUpConformanceInSignature(genericSig.getPointer()),
454-
genericSig);
454+
genericSig,
455+
SubstFlags::PreservePackExpansionLevel);
455456
}
456457

457458
bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {

lib/SIL/IR/SILTypeSubstitution.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,8 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC,
577577
context.isWholeModuleContext());
578578

579579
InFlightSubstitution IFS(replacer, replacer,
580-
SubstFlags::SubstituteOpaqueArchetypes);
580+
SubstFlags::SubstituteOpaqueArchetypes |
581+
SubstFlags::PreservePackExpansionLevel);
581582

582583
SILTypeSubstituter substituter(TC, context, IFS, getSubstGenericSignature());
583584
auto resTy =

0 commit comments

Comments
 (0)