Skip to content

Commit dc3a221

Browse files
committed
[WIP] Always use PackTypes as the substitutions for type parameter packs
This simplifies the representation and allows clients to handle fewer cases. It also removes an ambiguity in the representation which could lead us to have two canonical types for the same type. This is definitely not working yet, but I'm not making progress on it quickly enough to unblock what we need to unblock; it'll have to be fixed in parallel.
1 parent d103bf7 commit dc3a221

File tree

11 files changed

+117
-15
lines changed

11 files changed

+117
-15
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6699,6 +6699,10 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
66996699
TypeArrayView<GenericTypeParamType> params,
67006700
ArrayRef<Type> args);
67016701

6702+
/// Given a pack parameter or pack archetype `T`, produce the
6703+
/// pack type `Pack{repeat each T}`.
6704+
static PackType *getSingletonPackExpansion(Type packParam);
6705+
67026706
public:
67036707
/// Retrieves the number of elements in this pack.
67046708
unsigned getNumElements() const { return Bits.PackType.Count; }

lib/AST/ASTContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3302,6 +3302,13 @@ PackType *PackType::getEmpty(const ASTContext &C) {
33023302
return cast<PackType>(CanType(C.TheEmptyPackType));
33033303
}
33043304

3305+
PackType *PackType::getSingletonPackExpansion(Type param) {
3306+
assert((param->is<GenericTypeParamType>() &&
3307+
param->castTo<GenericTypeParamType>()->isParameterPack()) ||
3308+
(param->is<PackArchetypeType>()));
3309+
return get(param->getASTContext(), {PackExpansionType::get(param, param)});
3310+
}
3311+
33053312
CanPackType CanPackType::get(const ASTContext &C, ArrayRef<CanType> elements) {
33063313
SmallVector<Type, 8> ncElements(elements.begin(), elements.end());
33073314
return CanPackType(PackType::get(C, ncElements));

lib/AST/Decl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4623,8 +4623,12 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) {
46234623
// the generic parameter list directly instead of looking
46244624
// at the signature.
46254625
SmallVector<Type, 4> args;
4626-
for (auto param : decl->getGenericParams()->getParams())
4627-
args.push_back(param->getDeclaredInterfaceType());
4626+
for (auto param : decl->getGenericParams()->getParams()) {
4627+
auto argTy = param->getDeclaredInterfaceType();
4628+
if (param->isParameterPack())
4629+
argTy = PackType::getSingletonPackExpansion(argTy);
4630+
args.push_back(argTy);
4631+
}
46284632

46294633
return BoundGenericType::get(decl, ParentTy, args);
46304634
}

lib/AST/GenericEnvironment.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,10 +681,37 @@ GenericEnvironment::mapElementTypeIntoPackContext(Type type) const {
681681
}, LookUpConformanceInSignature(sig.getPointer()));
682682
}
683683

684+
namespace {
685+
/// A function suitable for use as a \c TypeSubstitutionFn that produces
686+
/// correct forwarding substitutions for a generic environment.
687+
///
688+
/// This differs from QueryInterfaceTypeSubstitutions only in that it
689+
/// always produces PackTypes for pack parameters.
690+
class BuildForwardingSubstitutions {
691+
QueryInterfaceTypeSubstitutions Query;
692+
693+
public:
694+
BuildForwardingSubstitutions(const GenericEnvironment *self)
695+
: Query(self) { }
696+
697+
Type operator()(SubstitutableType *type) const;
698+
};
699+
} // end anonymous namespace
700+
701+
Type BuildForwardingSubstitutions::operator()(SubstitutableType *type) const {
702+
if (auto resultType = Query(type)) {
703+
auto param = type->castTo<GenericTypeParamType>();
704+
if (!param->isParameterPack())
705+
return resultType;
706+
return PackType::getSingletonPackExpansion(resultType);
707+
}
708+
return Type();
709+
}
710+
684711
SubstitutionMap GenericEnvironment::getForwardingSubstitutionMap() const {
685712
auto genericSig = getGenericSignature();
686713
return SubstitutionMap::get(genericSig,
687-
QueryInterfaceTypeSubstitutions(this),
714+
BuildForwardingSubstitutions(this),
688715
MakeAbstractConformanceForGenericType());
689716
}
690717

lib/AST/GenericSignature.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,13 @@ unsigned GenericParamKey::findIndexIn(
566566

567567
SubstitutionMap GenericSignatureImpl::getIdentitySubstitutionMap() const {
568568
return SubstitutionMap::get(const_cast<GenericSignatureImpl *>(this),
569-
[](SubstitutableType *t) -> Type {
570-
return Type(cast<GenericTypeParamType>(t));
571-
},
572-
MakeAbstractConformanceForGenericType());
569+
[](SubstitutableType *t) -> Type {
570+
auto param = cast<GenericTypeParamType>(t);
571+
if (!param->isParameterPack())
572+
return param;
573+
return PackType::getSingletonPackExpansion(param);
574+
},
575+
MakeAbstractConformanceForGenericType());
573576
}
574577

575578
GenericTypeParamType *GenericSignatureImpl::getSugaredType(

lib/AST/SubstitutionMap.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ SubstitutionMap SubstitutionMap::get(GenericSignature genericSig,
226226

227227
// Record the replacement.
228228
Type replacement = Type(gp).subst(subs, lookupConformance);
229+
230+
assert((!replacement || replacement->hasError() ||
231+
gp->isParameterPack() == replacement->is<PackType>()) &&
232+
"replacement for pack parameter must be a pack type");
233+
229234
replacementTypes.push_back(replacement);
230235
});
231236

lib/AST/Type.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4489,6 +4489,24 @@ operator()(CanType dependentType, Type conformingReplacementType,
44894489
ProtocolConformanceRef MakeAbstractConformanceForGenericType::
44904490
operator()(CanType dependentType, Type conformingReplacementType,
44914491
ProtocolDecl *conformedProtocol) const {
4492+
// The places that use this can also produce conformance packs, generally
4493+
// just for singleton pack expansions.
4494+
if (auto conformingPack = conformingReplacementType->getAs<PackType>()) {
4495+
SmallVector<ProtocolConformanceRef, 4> conformances;
4496+
for (auto conformingPackElt : conformingPack->getElementTypes()) {
4497+
// Look through pack expansions; there's no equivalent conformance
4498+
// expansion right now.
4499+
auto expansion = conformingPackElt->getAs<PackExpansionType>();
4500+
if (expansion) conformingPackElt = expansion->getPatternType();
4501+
4502+
auto conformance =
4503+
(*this)(dependentType, conformingPackElt, conformedProtocol);
4504+
conformances.push_back(conformance);
4505+
}
4506+
return ProtocolConformanceRef(
4507+
PackConformance::get(conformingPack, conformedProtocol, conformances));
4508+
}
4509+
44924510
assert((conformingReplacementType->is<ErrorType>() ||
44934511
conformingReplacementType->is<SubstitutableType>() ||
44944512
conformingReplacementType->is<DependentMemberType>() ||
@@ -4954,6 +4972,9 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
49544972
else if (genericEnv)
49554973
substTy = genericEnv->mapTypeIntoContext(gp);
49564974

4975+
if (gp->isParameterPack() && !substTy->hasError())
4976+
substTy = PackType::getSingletonPackExpansion(substTy);
4977+
49574978
auto result = substitutions.insert(
49584979
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
49594980
substTy});

lib/IRGen/GenPack.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,18 @@ static llvm::Value *bindWitnessTableAtIndex(IRGenFunction &IGF,
261261
return wtable;
262262
}
263263

264+
/// Find the pack archetype for the given interface type in the given
265+
/// opened element context, which is known to be a forwarding context.
266+
static CanPackArchetypeType
267+
getMappedPackArchetypeType(const OpenedElementContext &context, CanType ty) {
268+
auto packType = cast<PackType>(
269+
context.environment->maybeApplyOuterContextSubstitutions(ty)
270+
->getCanonicalType());
271+
auto archetype = getForwardedPackArchetypeType(packType);
272+
assert(archetype);
273+
return archetype;
274+
}
275+
264276
static void bindElementSignatureRequirementsAtIndex(
265277
IRGenFunction &IGF, OpenedElementContext const &context, llvm::Value *index,
266278
DynamicMetadataRequest request) {
@@ -273,9 +285,7 @@ static void bindElementSignatureRequirementsAtIndex(
273285
break;
274286
case GenericRequirement::Kind::MetadataPack: {
275287
auto ty = requirement.getTypeParameter();
276-
auto patternPackArchetype = cast<PackArchetypeType>(
277-
context.environment->maybeApplyOuterContextSubstitutions(ty)
278-
->getCanonicalType());
288+
auto patternPackArchetype = getMappedPackArchetypeType(context, ty);
279289
auto response =
280290
IGF.emitTypeMetadataRef(patternPackArchetype, request);
281291
auto elementArchetype =
@@ -293,9 +303,7 @@ static void bindElementSignatureRequirementsAtIndex(
293303
case GenericRequirement::Kind::WitnessTablePack: {
294304
auto ty = requirement.getTypeParameter();
295305
auto proto = requirement.getProtocol();
296-
auto patternPackArchetype = cast<PackArchetypeType>(
297-
context.environment->maybeApplyOuterContextSubstitutions(ty)
298-
->getCanonicalType());
306+
auto patternPackArchetype = getMappedPackArchetypeType(context, ty);
299307
auto elementArchetype =
300308
context.environment
301309
->mapPackTypeIntoElementContext(

lib/Sema/CSApply.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,12 @@ Solution::computeSubstitutions(GenericSignature sig,
9595
return SubstitutionMap();
9696

9797
TypeSubstitutionMap subs;
98-
for (const auto &opened : openedTypes->second)
99-
subs[opened.first] = getFixedType(opened.second);
98+
for (const auto &opened : openedTypes->second) {
99+
auto type = getFixedType(opened.second);
100+
if (opened.first->isParameterPack() && !type->is<PackType>())
101+
type = PackType::getSingletonPackExpansion(type);
102+
subs[opened.first] = type;
103+
}
100104

101105
auto lookupConformanceFn =
102106
[&](CanType original, Type replacement,

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,7 @@ void PotentialBindings::infer(Constraint *constraint) {
14831483
auto *elementEnv = CS.getPackElementEnvironment(constraint->getLocator(),
14841484
shapeClass);
14851485
auto elementType = elementEnv->mapPackTypeIntoElementContext(packType);
1486+
assert(!elementType->is<PackType>());
14861487
addPotentialBinding({elementType, AllowedBindingKind::Exact, constraint});
14871488

14881489
break;

lib/Sema/CSSimplify.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8782,6 +8782,19 @@ ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
87828782
return SolutionKind::Solved;
87838783
}
87848784

8785+
static Type lookThroughSingletonPackExpansion(Type ty) {
8786+
if (auto pack = ty->getAs<PackType>()) {
8787+
if (pack->getNumElements() == 1) {
8788+
if (auto expansion = pack->getElementType(0)->getAs<PackExpansionType>()) {
8789+
auto countType = expansion->getCountType();
8790+
if (countType->isEqual(expansion->getPatternType()))
8791+
return countType;
8792+
}
8793+
}
8794+
}
8795+
return ty;
8796+
}
8797+
87858798
ConstraintSystem::SolutionKind
87868799
ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
87878800
TypeMatchOptions flags,
@@ -8801,6 +8814,11 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
88018814
return SolutionKind::Solved;
88028815
}
88038816

8817+
// FIXME: I'm not sure this is actually necessary; I may only be seeing
8818+
// this because of something I've screwed up in element generic
8819+
// environments.
8820+
elementType = lookThroughSingletonPackExpansion(elementType);
8821+
88048822
// This constraint only exists to vend bindings.
88058823
auto *packEnv = DC->getGenericEnvironmentOfContext();
88068824
if ((!elementType->hasElementArchetype() && packType->isEqual(elementType)) ||

0 commit comments

Comments
 (0)