Skip to content

Commit 75c1b6e

Browse files
authored
Merge pull request #64166 from hborla/parameter-pack-substitution
2 parents c93a235 + 1845d0d commit 75c1b6e

26 files changed

+186
-48
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,6 +2733,9 @@ ERROR(requires_not_suitable_archetype,none,
27332733
ERROR(invalid_shape_requirement,none,
27342734
"invalid same-shape requirement between %0 and %1",
27352735
(Type, Type))
2736+
ERROR(unsupported_same_element,none,
2737+
"same-element requirements are not yet supported",
2738+
())
27362739

27372740
ERROR(requires_generic_params_made_equal,none,
27382741
"same-type requirement makes generic parameters %0 and %1 equivalent",

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,8 @@ class Solution {
14871487

14881488
/// The pack expansion environment that can open pack elements for
14891489
/// a given locator.
1490-
llvm::DenseMap<ConstraintLocator *, UUID> PackExpansionEnvironments;
1490+
llvm::DenseMap<ConstraintLocator *, std::pair<UUID, Type>>
1491+
PackExpansionEnvironments;
14911492

14921493
/// The locators of \c Defaultable constraints whose defaults were used.
14931494
llvm::SmallPtrSet<ConstraintLocator *, 2> DefaultedConstraints;
@@ -2228,7 +2229,8 @@ class ConstraintSystem {
22282229
llvm::SmallMapVector<ConstraintLocator *, OpenedArchetypeType *, 4>
22292230
OpenedExistentialTypes;
22302231

2231-
llvm::SmallMapVector<ConstraintLocator *, UUID, 4> PackExpansionEnvironments;
2232+
llvm::SmallMapVector<ConstraintLocator *, std::pair<UUID, Type>, 4>
2233+
PackExpansionEnvironments;
22322234

22332235
/// The set of functions that have been transformed by a result builder.
22342236
llvm::MapVector<AnyFunctionRef, AppliedBuilderTransform>
@@ -3191,9 +3193,6 @@ class ConstraintSystem {
31913193
std::pair<Type, OpenedArchetypeType *> openExistentialType(
31923194
Type type, ConstraintLocator *locator);
31933195

3194-
/// Add the given pack expansion as an opened pack element environment.
3195-
void addPackElementEnvironment(PackExpansionExpr *expr);
3196-
31973196
/// Get the opened element generic environment for the given locator.
31983197
GenericEnvironment *getPackElementEnvironment(ConstraintLocator *locator,
31993198
CanType shapeClass);

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5147,6 +5147,7 @@ GenericEnvironment::forOpenedElement(GenericSignature signature,
51475147
if (found != openedElementEnvironments.end()) {
51485148
auto *existingEnv = found->second;
51495149
assert(existingEnv->getGenericSignature().getPointer() == signature.getPointer());
5150+
assert(existingEnv->getOpenedElementShapeClass()->isEqual(shapeClass));
51505151
assert(existingEnv->getOpenedElementUUID() == uuid);
51515152

51525153
return existingEnv;

lib/AST/Decl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4670,8 +4670,12 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) {
46704670
// the generic parameter list directly instead of looking
46714671
// at the signature.
46724672
SmallVector<Type, 4> args;
4673-
for (auto param : decl->getGenericParams()->getParams())
4674-
args.push_back(param->getDeclaredInterfaceType());
4673+
for (auto param : decl->getGenericParams()->getParams()) {
4674+
auto argTy = param->getDeclaredInterfaceType();
4675+
if (param->isParameterPack())
4676+
argTy = PackType::getSingletonPackExpansion(argTy);
4677+
args.push_back(argTy);
4678+
}
46754679

46764680
return BoundGenericType::get(decl, ParentTy, args);
46774681
}

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
@@ -579,10 +579,13 @@ unsigned GenericParamKey::findIndexIn(
579579

580580
SubstitutionMap GenericSignatureImpl::getIdentitySubstitutionMap() const {
581581
return SubstitutionMap::get(const_cast<GenericSignatureImpl *>(this),
582-
[](SubstitutableType *t) -> Type {
583-
return Type(cast<GenericTypeParamType>(t));
584-
},
585-
MakeAbstractConformanceForGenericType());
582+
[](SubstitutableType *t) -> Type {
583+
auto param = cast<GenericTypeParamType>(t);
584+
if (!param->isParameterPack())
585+
return param;
586+
return PackType::getSingletonPackExpansion(param);
587+
},
588+
MakeAbstractConformanceForGenericType());
586589
}
587590

588591
GenericTypeParamType *GenericSignatureImpl::getSugaredType(

lib/AST/RequirementMachine/Diagnostics.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ bool swift::rewriting::diagnoseRequirementErrors(
209209

210210
break;
211211
}
212+
213+
case RequirementError::Kind::UnsupportedSameElement: {
214+
if (error.requirement.hasError())
215+
break;
216+
217+
ctx.Diags.diagnose(loc, diag::unsupported_same_element);
218+
diagnosedError = true;
219+
break;
220+
}
212221
}
213222
}
214223

lib/AST/RequirementMachine/Diagnostics.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ struct RequirementError {
4242
RecursiveRequirement,
4343
/// A redundant requirement, e.g. T == T.
4444
RedundantRequirement,
45+
/// A not-yet-supported same-element requirement, e.g. each T == Int.
46+
UnsupportedSameElement,
4547
} kind;
4648

4749
/// The invalid requirement.
@@ -100,6 +102,10 @@ struct RequirementError {
100102
SourceLoc loc) {
101103
return {Kind::RecursiveRequirement, req, loc};
102104
}
105+
106+
static RequirementError forSameElement(Requirement req, SourceLoc loc) {
107+
return {Kind::UnsupportedSameElement, req, loc};
108+
}
103109
};
104110

105111
/// Policy for the fixit that transforms 'T : S' where 'S' is not a protocol

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ static void desugarSameTypeRequirement(Type lhs, Type rhs, SourceLoc loc,
194194

195195
bool mismatch(TypeBase *firstType, TypeBase *secondType,
196196
Type sugaredFirstType) {
197+
// If one side is a parameter pack, this is a same-element requirement, which
198+
// is not yet supported.
199+
if (firstType->isParameterPack() != secondType->isParameterPack()) {
200+
errors.push_back(RequirementError::forSameElement(
201+
{RequirementKind::SameType, sugaredFirstType, secondType}, loc));
202+
recordedErrors = true;
203+
return true;
204+
}
205+
197206
if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
198207
result.emplace_back(RequirementKind::SameType,
199208
sugaredFirstType, secondType);

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
@@ -4502,6 +4502,24 @@ operator()(CanType dependentType, Type conformingReplacementType,
45024502
ProtocolConformanceRef MakeAbstractConformanceForGenericType::
45034503
operator()(CanType dependentType, Type conformingReplacementType,
45044504
ProtocolDecl *conformedProtocol) const {
4505+
// The places that use this can also produce conformance packs, generally
4506+
// just for singleton pack expansions.
4507+
if (auto conformingPack = conformingReplacementType->getAs<PackType>()) {
4508+
SmallVector<ProtocolConformanceRef, 4> conformances;
4509+
for (auto conformingPackElt : conformingPack->getElementTypes()) {
4510+
// Look through pack expansions; there's no equivalent conformance
4511+
// expansion right now.
4512+
auto expansion = conformingPackElt->getAs<PackExpansionType>();
4513+
if (expansion) conformingPackElt = expansion->getPatternType();
4514+
4515+
auto conformance =
4516+
(*this)(dependentType, conformingPackElt, conformedProtocol);
4517+
conformances.push_back(conformance);
4518+
}
4519+
return ProtocolConformanceRef(
4520+
PackConformance::get(conformingPack, conformedProtocol, conformances));
4521+
}
4522+
45054523
assert((conformingReplacementType->is<ErrorType>() ||
45064524
conformingReplacementType->is<SubstitutableType>() ||
45074525
conformingReplacementType->is<DependentMemberType>() ||
@@ -4967,6 +4985,9 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
49674985
else if (genericEnv)
49684986
substTy = genericEnv->mapTypeIntoContext(gp);
49694987

4988+
if (gp->isParameterPack() && !substTy->hasError())
4989+
substTy = PackType::getSingletonPackExpansion(substTy);
4990+
49704991
auto result = substitutions.insert(
49714992
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
49724993
substTy});

lib/IRGen/GenPack.cpp

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

266+
/// Find the pack archetype for the given interface type in the given
267+
/// opened element context, which is known to be a forwarding context.
268+
static CanPackArchetypeType
269+
getMappedPackArchetypeType(const OpenedElementContext &context, CanType ty) {
270+
auto packType = cast<PackType>(
271+
context.environment->maybeApplyOuterContextSubstitutions(ty)
272+
->getCanonicalType());
273+
auto archetype = getForwardedPackArchetypeType(packType);
274+
assert(archetype);
275+
return archetype;
276+
}
277+
266278
static void bindElementSignatureRequirementsAtIndex(
267279
IRGenFunction &IGF, OpenedElementContext const &context, llvm::Value *index,
268280
DynamicMetadataRequest request) {
@@ -275,9 +287,7 @@ static void bindElementSignatureRequirementsAtIndex(
275287
break;
276288
case GenericRequirement::Kind::MetadataPack: {
277289
auto ty = requirement.getTypeParameter();
278-
auto patternPackArchetype = cast<PackArchetypeType>(
279-
context.environment->maybeApplyOuterContextSubstitutions(ty)
280-
->getCanonicalType());
290+
auto patternPackArchetype = getMappedPackArchetypeType(context, ty);
281291
auto response =
282292
IGF.emitTypeMetadataRef(patternPackArchetype, request);
283293
auto elementArchetype =
@@ -295,9 +305,7 @@ static void bindElementSignatureRequirementsAtIndex(
295305
case GenericRequirement::Kind::WitnessTablePack: {
296306
auto ty = requirement.getTypeParameter();
297307
auto proto = requirement.getProtocol();
298-
auto patternPackArchetype = cast<PackArchetypeType>(
299-
context.environment->maybeApplyOuterContextSubstitutions(ty)
300-
->getCanonicalType());
308+
auto patternPackArchetype = getMappedPackArchetypeType(context, ty);
301309
auto elementArchetype =
302310
context.environment
303311
->mapPackTypeIntoElementContext(

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,12 @@ class SubstFunctionTypePatternVisitor
17121712
auto gp = GenericTypeParamType::get(isParameterPack, 0, paramIndex,
17131713
TC.Context);
17141714
substGenericParams.push_back(gp);
1715-
substReplacementTypes.push_back(substTy);
1715+
if (isParameterPack) {
1716+
substReplacementTypes.push_back(
1717+
PackType::getSingletonPackExpansion(substTy));
1718+
} else {
1719+
substReplacementTypes.push_back(substTy);
1720+
}
17161721

17171722
if (auto layout = pattern.getLayoutConstraint()) {
17181723
// Look at the layout constraint on this position in the abstraction pattern

lib/SILGen/SILGenConstructor.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,13 @@ static SubstitutionMap getSubstitutionsForPropertyInitializer(
139139
// replacement types are the archetypes of the initializer itself.
140140
return SubstitutionMap::get(
141141
nominal->getGenericSignatureOfContext(),
142-
[&](SubstitutableType *type) {
142+
[&](SubstitutableType *type) -> Type {
143143
if (auto gp = type->getAs<GenericTypeParamType>()) {
144-
return genericEnv->mapTypeIntoContext(gp);
144+
auto archetype = genericEnv->mapTypeIntoContext(gp);
145+
if (!gp->isParameterPack())
146+
return archetype;
147+
148+
return PackType::getSingletonPackExpansion(archetype);
145149
}
146150

147151
return Type(type);

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
@@ -1501,6 +1501,7 @@ void PotentialBindings::infer(Constraint *constraint) {
15011501
break;
15021502

15031503
auto elementType = elementEnv->mapPackTypeIntoElementContext(packType);
1504+
assert(!elementType->is<PackType>());
15041505
addPotentialBinding({elementType, AllowedBindingKind::Exact, constraint});
15051506

15061507
break;

lib/Sema/CSGen.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,6 @@ namespace {
11011101
ConstraintSystem &getConstraintSystem() const { return CS; }
11021102

11031103
void addPackElementEnvironment(PackExpansionExpr *expr) {
1104-
CS.addPackElementEnvironment(expr);
11051104
PackElementEnvironments.push_back(expr);
11061105
}
11071106

lib/Sema/CSSimplify.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8843,6 +8843,19 @@ ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
88438843
return SolutionKind::Solved;
88448844
}
88458845

8846+
static Type lookThroughSingletonPackExpansion(Type ty) {
8847+
if (auto pack = ty->getAs<PackType>()) {
8848+
if (pack->getNumElements() == 1) {
8849+
if (auto expansion = pack->getElementType(0)->getAs<PackExpansionType>()) {
8850+
auto countType = expansion->getCountType();
8851+
if (countType->isEqual(expansion->getPatternType()))
8852+
return countType;
8853+
}
8854+
}
8855+
}
8856+
return ty;
8857+
}
8858+
88468859
ConstraintSystem::SolutionKind
88478860
ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
88488861
TypeMatchOptions flags,
@@ -8862,6 +8875,11 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
88628875
return SolutionKind::Solved;
88638876
}
88648877

8878+
// FIXME: I'm not sure this is actually necessary; I may only be seeing
8879+
// this because of something I've screwed up in element generic
8880+
// environments.
8881+
elementType = lookThroughSingletonPackExpansion(elementType);
8882+
88658883
// This constraint only exists to vend bindings.
88668884
auto *packEnv = DC->getGenericEnvironmentOfContext();
88678885

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -649,29 +649,31 @@ std::pair<Type, OpenedArchetypeType *> ConstraintSystem::openExistentialType(
649649
return {result, opened};
650650
}
651651

652-
void ConstraintSystem::addPackElementEnvironment(PackExpansionExpr *expr) {
653-
auto *locator = getConstraintLocator(expr);
654-
PackExpansionEnvironments[locator] = UUID::fromTime();
655-
}
656-
657652
GenericEnvironment *
658653
ConstraintSystem::getPackElementEnvironment(ConstraintLocator *locator,
659654
CanType shapeClass) {
655+
assert(locator->directlyAt<PackExpansionExpr>());
656+
657+
std::pair<UUID, Type> uuidAndShape;
660658
auto result = PackExpansionEnvironments.find(locator);
661-
if (result == PackExpansionEnvironments.end())
662-
return nullptr;
659+
if (result == PackExpansionEnvironments.end()) {
660+
uuidAndShape = std::make_pair(UUID::fromTime(), shapeClass);
661+
PackExpansionEnvironments[locator] = uuidAndShape;
662+
} else {
663+
uuidAndShape = result->second;
664+
}
663665

664-
if (!shapeClass->is<PackArchetypeType>())
666+
if (!shapeClass->is<PackArchetypeType>() ||
667+
!shapeClass->isEqual(uuidAndShape.second))
665668
return nullptr;
666669

667-
auto uuid = result->second;
668670
auto &ctx = getASTContext();
669671
auto elementSig = ctx.getOpenedElementSignature(
670672
DC->getGenericSignatureOfContext().getCanonicalSignature(), shapeClass);
671673
auto *contextEnv = DC->getGenericEnvironmentOfContext();
672674
auto contextSubs = contextEnv->getForwardingSubstitutionMap();
673-
return GenericEnvironment::forOpenedElement(elementSig, uuid, shapeClass,
674-
contextSubs);
675+
return GenericEnvironment::forOpenedElement(elementSig, uuidAndShape.first,
676+
shapeClass, contextSubs);
675677
}
676678

677679
/// Extend the given depth map by adding depths for all of the subexpressions

0 commit comments

Comments
 (0)