Skip to content

Commit c30f7dc

Browse files
authored
Merge pull request #66096 from slavapestov/pack-element-type
Preliminary support for substitution with nested pack expansions
2 parents 1adcf99 + f432270 commit c30f7dc

34 files changed

+551
-189
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,8 @@ Types
675675
type ::= assoc-type-list 'QZ' // shortcut for 'QYz'
676676
type ::= opaque-type-decl-name bound-generic-args 'Qo' INDEX // opaque type
677677
678+
type ::= pack-type 'Qe' INDEX // pack element type
679+
678680
type ::= pattern-type count-type 'Qp' // pack expansion type
679681
type ::= pack-element-list 'QP' // pack type
680682
type ::= pack-element-list 'QS' DIRECTNESS // SIL pack type

include/swift/AST/InFlightSubstitution.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,15 @@ 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,
7158
Type conformingReplacementType,
72-
ProtocolDecl *conformedProtocol);
59+
ProtocolDecl *conformedProtocol,
60+
unsigned level);
7361

7462
/// Given the shape type of a pack expansion, invoke the given callback
7563
/// for each expanded component of it. If the substituted component

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.

include/swift/AST/Types.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
724724
SmallVectorImpl<OpenedArchetypeType *> &rootOpenedArchetypes) const;
725725

726726
/// Retrieve the set of type parameter packs that occur within this type.
727-
void getTypeParameterPacks(
728-
SmallVectorImpl<Type> &rootParameterPacks);
727+
void getTypeParameterPacks(SmallVectorImpl<Type> &rootParameterPacks);
728+
729+
/// Retrieve the set of type parameter packs that occur within this type.
730+
void walkPackReferences(llvm::function_ref<bool (Type)> fn);
729731

730732
/// Replace opened archetypes with the given root with their most
731733
/// specific non-dependent upper bounds throughout this type.
@@ -792,6 +794,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
792794
/// this function will wrap into a pack containing a singleton expansion.
793795
PackType *getPackSubstitutionAsPackType();
794796

797+
/// Increase the expansion level of each parameter pack appearing in this type.
798+
Type increasePackElementLevel(unsigned level);
799+
795800
/// Determines whether this type is an lvalue. This includes both straight
796801
/// lvalue types as well as tuples or optionals of lvalues.
797802
bool hasLValueType() {

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ NODE(SILPackDirect)
242242
NODE(SILPackIndirect)
243243
NODE(PackExpansion)
244244
NODE(PackElement)
245+
NODE(PackElementLevel)
245246
NODE(Type)
246247
CONTEXT_NODE(TypeSymbolicReference)
247248
CONTEXT_NODE(TypeAlias)

include/swift/SIL/AbstractionPattern.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -938,10 +938,9 @@ class AbstractionPattern {
938938
case Kind::Discard: {
939939
auto type = getType();
940940
if (isa<DependentMemberType>(type) ||
941-
isa<GenericTypeParamType>(type)) {
942-
return true;
943-
}
944-
if (isa<ArchetypeType>(type)) {
941+
isa<GenericTypeParamType>(type) ||
942+
isa<PackElementType>(type) ||
943+
isa<ArchetypeType>(type)) {
945944
return true;
946945
}
947946
return false;
@@ -960,7 +959,8 @@ class AbstractionPattern {
960959
case Kind::Discard: {
961960
auto type = getType();
962961
if (isa<DependentMemberType>(type) ||
963-
isa<GenericTypeParamType>(type)) {
962+
isa<GenericTypeParamType>(type) ||
963+
isa<PackElementType>(type)) {
964964
return true;
965965
}
966966
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
@@ -1448,6 +1448,10 @@ class AbstractionPattern {
14481448
/// the abstraction pattern for an element type.
14491449
AbstractionPattern getTupleElementType(unsigned index) const;
14501450

1451+
/// Given that the value being abstracted is a pack element type, return
1452+
/// the abstraction pattern for its pack type.
1453+
AbstractionPattern getPackElementPackType() const;
1454+
14511455
/// Given that the value being abstracted is a pack type, return
14521456
/// the abstraction pattern for an element type.
14531457
AbstractionPattern getPackElementType(unsigned index) const;

lib/AST/ASTMangler.cpp

Lines changed: 5 additions & 3 deletions
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) {
@@ -1288,8 +1289,9 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
12881289
case TypeKind::PackElement: {
12891290
auto elementType = cast<PackElementType>(tybase);
12901291
appendType(elementType->getPackType(), sig, forDecl);
1291-
1292-
// FIXME: append expansion depth
1292+
// If this ever changes, just mangle level 0 as a plain type parameter.
1293+
assert(elementType->getLevel() > 0);
1294+
appendOperator("Qe", Index(elementType->getLevel() - 1));
12931295

12941296
return;
12951297
}

lib/AST/ASTPrinter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6075,12 +6075,24 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
60756075
}
60766076

60776077
void visitPackExpansionType(PackExpansionType *T) {
6078+
SmallVector<Type, 2> rootParameterPacks;
6079+
T->getPatternType()->getTypeParameterPacks(rootParameterPacks);
6080+
6081+
if (rootParameterPacks.empty() &&
6082+
(T->getCountType()->isParameterPack() ||
6083+
T->getCountType()->is<PackArchetypeType>())) {
6084+
Printer << "/* shape: ";
6085+
visit(T->getCountType());
6086+
Printer << " */ ";
6087+
}
6088+
60786089
Printer << "repeat ";
6090+
60796091
visit(T->getPatternType());
60806092
}
60816093

60826094
void visitPackElementType(PackElementType *T) {
6083-
Printer << "@level(" << T->getLevel() << ") ";
6095+
Printer << "/* level: " << T->getLevel() << " */ ";
60846096
visit(T->getPackType());
60856097
}
60866098

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/ParameterPack.cpp

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ namespace {
2929

3030
/// Collects all unique pack type parameters referenced from the pattern type,
3131
/// skipping those captured by nested pack expansion types.
32-
struct PackTypeParameterCollector: TypeWalker {
33-
llvm::SetVector<Type> typeParams;
32+
struct PackReferenceCollector: TypeWalker {
33+
llvm::function_ref<bool (Type)> fn;
3434
unsigned expansionLevel;
3535
SmallVector<unsigned, 2> elementLevel;
3636

37-
PackTypeParameterCollector() : expansionLevel(0) {
37+
PackReferenceCollector(llvm::function_ref<bool (Type)> fn)
38+
: fn(fn), expansionLevel(0) {
3839
elementLevel.push_back(0);
3940
}
4041

@@ -72,12 +73,8 @@ struct PackTypeParameterCollector: TypeWalker {
7273
}
7374

7475
if (elementLevel.back() == expansionLevel) {
75-
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
76-
if (paramTy->isParameterPack())
77-
typeParams.insert(paramTy);
78-
} else if (auto *archetypeTy = t->getAs<PackArchetypeType>()) {
79-
typeParams.insert(archetypeTy->getRoot());
80-
}
76+
if (fn(t))
77+
return Action::Stop;
8178
}
8279

8380
return Action::Continue;
@@ -96,13 +93,28 @@ struct PackTypeParameterCollector: TypeWalker {
9693

9794
}
9895

96+
void TypeBase::walkPackReferences(
97+
llvm::function_ref<bool (Type)> fn) {
98+
Type(this).walk(PackReferenceCollector(fn));
99+
}
100+
99101
void TypeBase::getTypeParameterPacks(
100102
SmallVectorImpl<Type> &rootParameterPacks) {
101-
PackTypeParameterCollector collector;
102-
Type(this).walk(collector);
103+
llvm::SmallSetVector<Type, 2> rootParameterPackSet;
104+
105+
walkPackReferences([&](Type t) {
106+
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
107+
if (paramTy->isParameterPack())
108+
rootParameterPackSet.insert(paramTy);
109+
} else if (auto *archetypeTy = t->getAs<PackArchetypeType>()) {
110+
rootParameterPackSet.insert(archetypeTy->getRoot());
111+
}
112+
113+
return false;
114+
});
103115

104-
rootParameterPacks.append(collector.typeParams.begin(),
105-
collector.typeParams.end());
116+
rootParameterPacks.append(rootParameterPackSet.begin(),
117+
rootParameterPackSet.end());
106118
}
107119

108120
bool GenericTypeParamType::isParameterPack() const {
@@ -133,6 +145,45 @@ PackType *TypeBase::getPackSubstitutionAsPackType() {
133145
}
134146
}
135147

148+
static Type increasePackElementLevelImpl(
149+
Type type, unsigned level, unsigned outerLevel) {
150+
assert(level > 0);
151+
152+
return type.transformRec([&](TypeBase *t) -> Optional<Type> {
153+
if (auto *elementType = dyn_cast<PackElementType>(t)) {
154+
if (elementType->getLevel() >= outerLevel) {
155+
elementType = PackElementType::get(elementType->getPackType(),
156+
elementType->getLevel() + level);
157+
}
158+
159+
return Type(elementType);
160+
}
161+
162+
if (auto *expansionType = dyn_cast<PackExpansionType>(t)) {
163+
return Type(PackExpansionType::get(
164+
increasePackElementLevelImpl(expansionType->getPatternType(),
165+
level, outerLevel + 1),
166+
expansionType->getCountType()));
167+
}
168+
169+
if (t->isParameterPack() || isa<PackArchetypeType>(t)) {
170+
if (outerLevel == 0)
171+
return Type(PackElementType::get(t, level));
172+
173+
return Type(t);
174+
}
175+
176+
return None;
177+
});
178+
}
179+
180+
Type TypeBase::increasePackElementLevel(unsigned level) {
181+
if (level == 0)
182+
return Type(this);
183+
184+
return increasePackElementLevelImpl(Type(this), level, 0);
185+
}
186+
136187
CanType PackExpansionType::getReducedShape() {
137188
auto reducedShape = countType->getReducedShape();
138189
if (reducedShape == getASTContext().TheEmptyTupleType)

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ ProtocolConformanceRef::subst(Type origType, InFlightSubstitution &IFS) const {
119119
}
120120

121121
// Check the conformance map.
122-
return IFS.lookupConformance(origType->getCanonicalType(), substType, proto);
122+
// FIXME: Pack element level?
123+
return IFS.lookupConformance(origType->getCanonicalType(), substType, proto,
124+
/*level=*/0);
123125
}
124126

125127
ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const {
@@ -130,7 +132,8 @@ ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() cons
130132
return archetypeType->getInterfaceType();
131133
return type;
132134
},
133-
MakeAbstractConformanceForGenericType());
135+
MakeAbstractConformanceForGenericType(),
136+
SubstFlags::PreservePackExpansionLevel);
134137
return ProtocolConformanceRef(concrete);
135138
} else if (isPack()) {
136139
return getPack()->subst(
@@ -139,7 +142,8 @@ ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() cons
139142
return archetypeType->getInterfaceType();
140143
return type;
141144
},
142-
MakeAbstractConformanceForGenericType());
145+
MakeAbstractConformanceForGenericType(),
146+
SubstFlags::PreservePackExpansionLevel);
143147
}
144148

145149
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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ SubstitutionMap SubstitutionMap::get(GenericSignature genericSig,
247247
CanType depTy = req.getFirstType()->getCanonicalType();
248248
auto replacement = depTy.subst(IFS);
249249
auto *proto = req.getProtocolDecl();
250-
auto conformance = IFS.lookupConformance(depTy, replacement, proto);
250+
auto conformance = IFS.lookupConformance(depTy, replacement, proto,
251+
/*level=*/0);
251252
conformances.push_back(conformance);
252253
}
253254

@@ -440,7 +441,9 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
440441
}
441442

442443
SubstitutionMap SubstitutionMap::mapReplacementTypesOutOfContext() const {
443-
return subst(MapTypeOutOfContext(), MakeAbstractConformanceForGenericType());
444+
return subst(MapTypeOutOfContext(),
445+
MakeAbstractConformanceForGenericType(),
446+
SubstFlags::PreservePackExpansionLevel);
444447
}
445448

446449
SubstitutionMap SubstitutionMap::subst(SubstitutionMap subMap,
@@ -829,5 +832,7 @@ SubstitutionMap SubstitutionMap::mapIntoTypeExpansionContext(
829832
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
830833
context.getContext(), context.getResilienceExpansion(),
831834
context.isWholeModuleContext());
832-
return this->subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
835+
return this->subst(replacer, replacer,
836+
SubstFlags::SubstituteOpaqueArchetypes |
837+
SubstFlags::PreservePackExpansionLevel);
833838
}

0 commit comments

Comments
 (0)