Skip to content

Commit 25eb9ef

Browse files
authored
Merge pull request #61678 from hborla/pack-expansion-expression-checking
[Sema] Implement basic type checking for pack expansion expressions.
2 parents 361f5b4 + e80ee92 commit 25eb9ef

26 files changed

+520
-54
lines changed

include/swift/AST/Expr.h

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
350350
IsObjC : 1
351351
);
352352

353+
SWIFT_INLINE_BITFIELD_FULL(PackExpansionExpr, Expr, 32,
354+
: NumPadBits,
355+
NumBindings : 32
356+
);
357+
353358
SWIFT_INLINE_BITFIELD_FULL(SequenceExpr, Expr, 32,
354359
: NumPadBits,
355360
NumElements : 32
@@ -3519,20 +3524,54 @@ class VarargExpansionExpr : public Expr {
35193524
/// that naturally accept a comma-separated list of values, including
35203525
/// call argument lists, the elements of a tuple value, and the source
35213526
/// of a for-in loop.
3522-
class PackExpansionExpr: public Expr {
3527+
class PackExpansionExpr final : public Expr,
3528+
private llvm::TrailingObjects<PackExpansionExpr,
3529+
OpaqueValueExpr *, Expr *> {
3530+
friend TrailingObjects;
3531+
35233532
Expr *PatternExpr;
35243533
SourceLoc DotsLoc;
3534+
GenericEnvironment *Environment;
35253535

35263536
PackExpansionExpr(Expr *patternExpr,
3537+
ArrayRef<OpaqueValueExpr *> opaqueValues,
3538+
ArrayRef<Expr *> bindings,
35273539
SourceLoc dotsLoc,
3540+
GenericEnvironment *environment,
35283541
bool implicit, Type type)
35293542
: Expr(ExprKind::PackExpansion, implicit, type),
3530-
PatternExpr(patternExpr), DotsLoc(dotsLoc) {}
3543+
PatternExpr(patternExpr), DotsLoc(dotsLoc), Environment(environment) {
3544+
assert(opaqueValues.size() == bindings.size());
3545+
Bits.PackExpansionExpr.NumBindings = opaqueValues.size();
3546+
3547+
assert(Bits.PackExpansionExpr.NumBindings > 0 &&
3548+
"PackExpansionExpr must have pack references");
3549+
3550+
std::uninitialized_copy(opaqueValues.begin(), opaqueValues.end(),
3551+
getTrailingObjects<OpaqueValueExpr *>());
3552+
std::uninitialized_copy(bindings.begin(), bindings.end(),
3553+
getTrailingObjects<Expr *>());
3554+
}
3555+
3556+
size_t numTrailingObjects(OverloadToken<OpaqueValueExpr *>) const {
3557+
return getNumBindings();
3558+
}
3559+
3560+
size_t numTrailingObjects(OverloadToken<Expr *>) const {
3561+
return getNumBindings();
3562+
}
3563+
3564+
MutableArrayRef<Expr *> getMutableBindings() {
3565+
return {getTrailingObjects<Expr *>(), getNumBindings()};
3566+
}
35313567

35323568
public:
35333569
static PackExpansionExpr *create(ASTContext &ctx,
35343570
Expr *patternExpr,
3571+
ArrayRef<OpaqueValueExpr *> opaqueValues,
3572+
ArrayRef<Expr *> bindings,
35353573
SourceLoc dotsLoc,
3574+
GenericEnvironment *environment,
35363575
bool implicit = false,
35373576
Type type = Type());
35383577

@@ -3542,6 +3581,26 @@ class PackExpansionExpr: public Expr {
35423581
PatternExpr = patternExpr;
35433582
}
35443583

3584+
unsigned getNumBindings() const {
3585+
return Bits.PackExpansionExpr.NumBindings;
3586+
}
3587+
3588+
ArrayRef<OpaqueValueExpr *> getOpaqueValues() {
3589+
return {getTrailingObjects<OpaqueValueExpr *>(), getNumBindings()};
3590+
}
3591+
3592+
ArrayRef<Expr *> getBindings() {
3593+
return {getTrailingObjects<Expr *>(), getNumBindings()};
3594+
}
3595+
3596+
void setBinding(unsigned i, Expr *e) {
3597+
getMutableBindings()[i] = e;
3598+
}
3599+
3600+
GenericEnvironment *getGenericEnvironment() {
3601+
return Environment;
3602+
}
3603+
35453604
SourceLoc getStartLoc() const {
35463605
return PatternExpr->getStartLoc();
35473606
}

include/swift/AST/GenericSignature.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ class GenericSignature {
179179

180180
RequiredProtocols protos;
181181
LayoutConstraint layout;
182+
183+
Type packShape;
182184
};
183185

184186
private:

include/swift/AST/Identifier.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ class Identifier {
128128
return is("??");
129129
}
130130

131+
bool isExpansionOperator() const {
132+
return is("...");
133+
}
134+
131135
/// isOperatorStartCodePoint - Return true if the specified code point is a
132136
/// valid start of an operator.
133137
static bool isOperatorStartCodePoint(uint32_t C) {

include/swift/AST/Types.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6009,11 +6009,17 @@ BEGIN_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)
60096009
}
60106010
END_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)
60116011

6012+
/// A wrapper around a shape type to use in ArchetypeTrailingObjects
6013+
/// for PackArchetypeType.
6014+
struct PackShape {
6015+
Type shapeType;
6016+
};
6017+
60126018
/// An archetype that represents an opaque element of a type
60136019
/// parameter pack in context.
60146020
class PackArchetypeType final
60156021
: public ArchetypeType,
6016-
private ArchetypeTrailingObjects<PackArchetypeType> {
6022+
private ArchetypeTrailingObjects<PackArchetypeType, PackShape> {
60176023
friend TrailingObjects;
60186024
friend ArchetypeType;
60196025

@@ -6024,18 +6030,21 @@ class PackArchetypeType final
60246030
/// by this routine.
60256031
static CanTypeWrapper<PackArchetypeType>
60266032
get(const ASTContext &Ctx, GenericEnvironment *GenericEnv,
6027-
Type InterfaceType,
6033+
Type InterfaceType, Type ShapeType,
60286034
SmallVectorImpl<ProtocolDecl *> &ConformsTo, Type Superclass,
60296035
LayoutConstraint Layout);
60306036

6037+
// Returns the reduced shape type for this pack archetype.
6038+
Type getShape() const;
6039+
60316040
static bool classof(const TypeBase *T) {
60326041
return T->getKind() == TypeKind::PackArchetype;
60336042
}
60346043

60356044
private:
60366045
PackArchetypeType(const ASTContext &Ctx, GenericEnvironment *GenericEnv,
60376046
Type InterfaceType, ArrayRef<ProtocolDecl *> ConformsTo,
6038-
Type Superclass, LayoutConstraint Layout);
6047+
Type Superclass, LayoutConstraint Layout, PackShape Shape);
60396048
};
60406049
BEGIN_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)
60416050
END_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ enum class ConstraintKind : char {
215215
/// Represents an AST node contained in a body of a function/closure.
216216
/// It only has an AST node to generate constraints and infer the type for.
217217
SyntacticElement,
218+
/// The first type is the opened pack element type of the second type, which
219+
/// is the pattern of a pack expansion type.
220+
PackElementOf,
218221
/// Do not add new uses of this, it only exists to retain compatibility for
219222
/// rdar://85263844.
220223
///
@@ -686,6 +689,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
686689
case ConstraintKind::OneWayBindParam:
687690
case ConstraintKind::DefaultClosureType:
688691
case ConstraintKind::UnresolvedMemberChainBase:
692+
case ConstraintKind::PackElementOf:
689693
return ConstraintClassification::Relational;
690694

691695
case ConstraintKind::ValueMember:

include/swift/Sema/ConstraintSystem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5501,6 +5501,18 @@ class ConstraintSystem {
55015501
TypeMatchOptions flags,
55025502
ConstraintLocatorBuilder locator);
55035503

5504+
/// Attempt to simplify a PackElementOf constraint.
5505+
///
5506+
/// Solving this constraint is delayed until the element type is fully
5507+
/// resolved with no type variables. The element type is then mapped out
5508+
/// of the opened element context and into the context of the surrounding
5509+
/// function, effecively substituting opened element archetypes with their
5510+
/// corresponding pack archetypes, and bound to the second type.
5511+
SolutionKind
5512+
simplifyPackElementOfConstraint(Type first, Type second,
5513+
TypeMatchOptions flags,
5514+
ConstraintLocatorBuilder locator);
5515+
55045516
/// Attempt to simplify the ApplicableFunction constraint.
55055517
SolutionKind simplifyApplicableFnConstraint(
55065518
Type type1, Type type2,

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,15 +3136,6 @@ TupleType *TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
31363136
properties |= eltTy->getRecursiveProperties();
31373137
}
31383138

3139-
// Enforce an invariant.
3140-
for (unsigned i = 0, e = Fields.size(); i < e; ++i) {
3141-
if (Fields[i].getType()->is<PackExpansionType>()) {
3142-
assert(i == e - 1 || Fields[i + 1].hasName() &&
3143-
"Tuple element with pack expansion type cannot be followed "
3144-
"by an unlabeled element");
3145-
}
3146-
}
3147-
31483139
auto arena = getArena(properties);
31493140

31503141
void *InsertPos = nullptr;
@@ -5611,8 +5602,8 @@ ASTContext::getOpenedElementSignature(CanGenericSignature baseGenericSig) {
56115602

56125603
auto eraseParameterPack = [&](GenericTypeParamType *paramType) {
56135604
return GenericTypeParamType::get(
5614-
paramType->getDepth(), paramType->getIndex(),
5615-
/*isParameterPack=*/false, *this);
5605+
/*isParameterPack=*/false, paramType->getDepth(),
5606+
paramType->getIndex(), *this);
56165607
};
56175608

56185609
for (auto paramType : baseGenericSig.getGenericParams()) {

lib/AST/ASTVerifier.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,36 @@ class Verifier : public ASTWalker {
820820
OpenedExistentialArchetypes.erase(expr->getOpenedArchetype());
821821
}
822822

823+
bool shouldVerify(PackExpansionExpr *expr) {
824+
if (!shouldVerify(cast<Expr>(expr)))
825+
return false;
826+
827+
Generics.push_back(expr->getGenericEnvironment()->getGenericSignature());
828+
829+
for (auto *placeholder : expr->getOpaqueValues()) {
830+
assert(!OpaqueValues.count(placeholder));
831+
OpaqueValues[placeholder] = 0;
832+
}
833+
834+
return true;
835+
}
836+
837+
void verifyCheckedAlways(PackExpansionExpr *E) {
838+
// Remove the element generic environment before verifying
839+
// the pack expansion type, which contains pack archetypes.
840+
assert(Generics.back().get<GenericSignature>().getPointer() ==
841+
E->getGenericEnvironment()->getGenericSignature().getPointer());
842+
Generics.pop_back();
843+
verifyCheckedAlwaysBase(E);
844+
}
845+
846+
void cleanup(PackExpansionExpr *expr) {
847+
for (auto *placeholder : expr->getOpaqueValues()) {
848+
assert(OpaqueValues.count(placeholder));
849+
OpaqueValues.erase(placeholder);
850+
}
851+
}
852+
823853
bool shouldVerify(MakeTemporarilyEscapableExpr *expr) {
824854
if (!shouldVerify(cast<Expr>(expr)))
825855
return false;

lib/AST/Expr.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,10 +1239,17 @@ VarargExpansionExpr *VarargExpansionExpr::createArrayExpansion(ASTContext &ctx,
12391239

12401240
PackExpansionExpr *
12411241
PackExpansionExpr::create(ASTContext &ctx, Expr *patternExpr,
1242-
SourceLoc dotsLoc, bool implicit,
1243-
Type type) {
1244-
return new (ctx) PackExpansionExpr(patternExpr, dotsLoc,
1245-
implicit, type);
1242+
ArrayRef<OpaqueValueExpr *> opaqueValues,
1243+
ArrayRef<Expr *> bindings, SourceLoc dotsLoc,
1244+
GenericEnvironment *environment,
1245+
bool implicit, Type type) {
1246+
size_t size =
1247+
totalSizeToAlloc<OpaqueValueExpr *, Expr *>(opaqueValues.size(),
1248+
bindings.size());
1249+
void *mem = ctx.Allocate(size, alignof(PackExpansionExpr));
1250+
return ::new (mem) PackExpansionExpr(patternExpr, opaqueValues,
1251+
bindings, dotsLoc, environment,
1252+
implicit, type);
12461253
}
12471254

12481255
SequenceExpr *SequenceExpr::create(ASTContext &ctx, ArrayRef<Expr*> elements) {

lib/AST/GenericEnvironment.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
365365
if (rootGP->isParameterPack()) {
366366
assert(getKind() == Kind::Primary);
367367
result = PackArchetypeType::get(ctx, this, requirements.anchor,
368+
requirements.packShape,
368369
requirements.protos, superclass,
369370
requirements.layout);
370371
} else {

lib/AST/PackExpansionMatcher.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,23 @@
2424

2525
using namespace swift;
2626

27-
static PackType *gatherTupleElements(ArrayRef<TupleTypeElt> &elts,
28-
Identifier name,
29-
ASTContext &ctx) {
27+
static Type createPackBinding(ASTContext &ctx, ArrayRef<Type> types) {
28+
// If there is only one element and it's a pack expansion type,
29+
// return the pattern type directly. Because PackType can only appear
30+
// inside a PackExpansion, PackType(PackExpansionType()) will always
31+
// simplify to the pattern type.
32+
if (types.size() == 1) {
33+
if (auto *expansion = types.front()->getAs<PackExpansionType>()) {
34+
return expansion->getPatternType();
35+
}
36+
}
37+
38+
return PackType::get(ctx, types);
39+
}
40+
41+
static Type gatherTupleElements(ArrayRef<TupleTypeElt> &elts,
42+
Identifier name,
43+
ASTContext &ctx) {
3044
SmallVector<Type, 2> types;
3145

3246
if (!elts.empty() && elts.front().getName() == name) {
@@ -36,7 +50,7 @@ static PackType *gatherTupleElements(ArrayRef<TupleTypeElt> &elts,
3650
} while (!elts.empty() && !elts.front().hasName());
3751
}
3852

39-
return PackType::get(ctx, types);
53+
return createPackBinding(ctx, types);
4054
}
4155

4256
TuplePackMatcher::TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple)
@@ -69,7 +83,7 @@ bool TuplePackMatcher::match() {
6983
"Tuple element with pack expansion type cannot be followed "
7084
"by an unlabeled element");
7185

72-
auto *rhs = gatherTupleElements(rhsElts, lhsElt.getName(), ctx);
86+
auto rhs = gatherTupleElements(rhsElts, lhsElt.getName(), ctx);
7387
pairs.emplace_back(lhsExpansionType->getPatternType(), rhs, idx++);
7488
continue;
7589
}
@@ -89,7 +103,7 @@ bool TuplePackMatcher::match() {
89103
"Tuple element with pack expansion type cannot be followed "
90104
"by an unlabeled element");
91105

92-
auto *lhs = gatherTupleElements(lhsElts, rhsElt.getName(), ctx);
106+
auto lhs = gatherTupleElements(lhsElts, rhsElt.getName(), ctx);
93107
pairs.emplace_back(lhs, rhsExpansionType->getPatternType(), idx++);
94108
continue;
95109
}
@@ -299,4 +313,4 @@ bool PackMatcher::match() {
299313
// - The prefix and suffix are mismatched, so we're left with something
300314
// like {T..., Int} vs {Float, U...}.
301315
return true;
302-
}
316+
}

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,12 @@ ConcreteContraction::substRequirement(const Requirement &req) const {
371371
auto firstType = req.getFirstType();
372372

373373
switch (req.getKind()) {
374-
case RequirementKind::SameShape:
375-
llvm_unreachable("Same-shape requirement not supported here");
374+
case RequirementKind::SameShape: {
375+
auto substFirstType = substType(firstType);
376+
auto substSecondType = substType(req.getSecondType());
377+
378+
return Requirement(req.getKind(), substFirstType, substSecondType);
379+
}
376380

377381
case RequirementKind::Superclass:
378382
case RequirementKind::SameType: {

lib/AST/RequirementMachine/GenericSignatureQueries.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ RequirementMachine::getLocalRequirements(
5757

5858
GenericSignature::LocalRequirements result;
5959
result.anchor = Map.getTypeForTerm(term, genericParams);
60+
result.packShape = getReducedShape(depType);
6061

6162
auto *props = Map.lookUpProperties(term);
6263
if (!props)
@@ -789,13 +790,16 @@ void RequirementMachine::verify(const MutableTerm &term) const {
789790
erased.add(Symbol::forName(symbol.getName(), Context));
790791
break;
791792

793+
case Symbol::Kind::Shape:
794+
erased.add(symbol);
795+
break;
796+
792797
case Symbol::Kind::Protocol:
793798
case Symbol::Kind::GenericParam:
794799
case Symbol::Kind::Layout:
795800
case Symbol::Kind::Superclass:
796801
case Symbol::Kind::ConcreteType:
797802
case Symbol::Kind::ConcreteConformance:
798-
case Symbol::Kind::Shape:
799803
llvm::errs() << "Bad interior symbol " << symbol << " in " << term << "\n";
800804
abort();
801805
break;

0 commit comments

Comments
 (0)