Skip to content

Commit 7c3a63b

Browse files
authored
Merge pull request #61465 from slavapestov/variadic-generics-constraints
Preliminary constraint solver support for variadic generics
2 parents 89c8b9c + b9d7201 commit 7c3a63b

26 files changed

+1219
-566
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8399,6 +8399,10 @@ ParameterList *getParameterList(ValueDecl *source);
83998399
/// there is none.
84008400
ParameterList *getParameterList(DeclContext *source);
84018401

8402+
/// Retrieve parameter declaration from the given source at given index, or
8403+
/// nullptr if the source does not have a parameter list.
8404+
const ParamDecl *getParameterAt(ConcreteDeclRef declRef, unsigned index);
8405+
84028406
/// Retrieve parameter declaration from the given source at given index, or
84038407
/// nullptr if the source does not have a parameter list.
84048408
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);

include/swift/AST/Expr.h

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,6 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
359359
IsPlaceholder : 1
360360
);
361361

362-
SWIFT_INLINE_BITFIELD_FULL(PackExpr, Expr, 32,
363-
: NumPadBits,
364-
NumElements : 32
365-
);
366-
367362
SWIFT_INLINE_BITFIELD_FULL(TypeJoinExpr, Expr, 32,
368363
: NumPadBits,
369364
NumElements : 32
@@ -5908,55 +5903,6 @@ class OneWayExpr : public Expr {
59085903
}
59095904
};
59105905

5911-
/// An expression node that aggregates a set of heterogeneous arguments into a
5912-
/// parameter pack suitable for passing off to a variadic generic function
5913-
/// argument.
5914-
///
5915-
/// There is no user-visible way to spell a pack expression, they are always
5916-
/// implicitly created at applies. As such, any appearance of pack types outside
5917-
/// of applies are illegal.
5918-
class PackExpr final : public Expr,
5919-
private llvm::TrailingObjects<PackExpr, Expr *> {
5920-
friend TrailingObjects;
5921-
5922-
size_t numTrailingObjects() const {
5923-
return getNumElements();
5924-
}
5925-
5926-
PackExpr(ArrayRef<Expr *> SubExprs, Type Ty);
5927-
5928-
public:
5929-
/// Create a pack.
5930-
static PackExpr *create(ASTContext &ctx, ArrayRef<Expr *> SubExprs, Type Ty);
5931-
5932-
/// Create an empty pack.
5933-
static PackExpr *createEmpty(ASTContext &ctx);
5934-
5935-
SourceLoc getLoc() const { return SourceLoc(); }
5936-
SourceRange getSourceRange() const { return SourceRange(); }
5937-
5938-
/// Retrieve the elements of this pack.
5939-
MutableArrayRef<Expr *> getElements() {
5940-
return { getTrailingObjects<Expr *>(), getNumElements() };
5941-
}
5942-
5943-
/// Retrieve the elements of this pack.
5944-
ArrayRef<Expr *> getElements() const {
5945-
return { getTrailingObjects<Expr *>(), getNumElements() };
5946-
}
5947-
5948-
unsigned getNumElements() const { return Bits.PackExpr.NumElements; }
5949-
5950-
Expr *getElement(unsigned i) const {
5951-
return getElements()[i];
5952-
}
5953-
void setElement(unsigned i, Expr *e) {
5954-
getElements()[i] = e;
5955-
}
5956-
5957-
static bool classof(const Expr *E) { return E->getKind() == ExprKind::Pack; }
5958-
};
5959-
59605906
class TypeJoinExpr final : public Expr,
59615907
private llvm::TrailingObjects<TypeJoinExpr, Expr *> {
59625908
friend TrailingObjects;

include/swift/AST/ExprNodes.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ EXPR(KeyPath, Expr)
206206
UNCHECKED_EXPR(KeyPathDot, Expr)
207207
UNCHECKED_EXPR(OneWay, Expr)
208208
EXPR(Tap, Expr)
209-
EXPR(Pack, Expr)
210209
UNCHECKED_EXPR(TypeJoin, Expr)
211210
LAST_EXPR(TypeJoin)
212211

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===--- PackExpansionMatcher.h - Matching pack expansions ------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utilities for structural matching of sequences of types containing pack
14+
// expansions.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_AST_PACK_EXPANSION_MATCHER_H
19+
#define SWIFT_AST_PACK_EXPANSION_MATCHER_H
20+
21+
#include "swift/AST/Type.h"
22+
#include "swift/AST/Types.h"
23+
#include "llvm/ADT/ArrayRef.h"
24+
#include "llvm/ADT/SmallVector.h"
25+
26+
namespace swift {
27+
28+
class ASTContext;
29+
30+
/// The result of a match. If one of lhs or rhs is a pack expansion type,
31+
/// the other one is a pack type.
32+
struct MatchedPair {
33+
Type lhs;
34+
Type rhs;
35+
36+
// An index into the original left-hand side.
37+
unsigned idx;
38+
39+
MatchedPair(Type lhs, Type rhs, unsigned idx)
40+
: lhs(lhs), rhs(rhs), idx(idx) {}
41+
};
42+
43+
/// Performs a structural match of two lists of tuple elements. The invariant
44+
/// is that a pack expansion type must not be followed by an unlabeled
45+
/// element, that is, it is either the last element or the next element has
46+
/// a label.
47+
///
48+
/// In this manner, an element with a pack expansion type "absorbs" all
49+
/// unlabeled elements up to the next label. An element with any other type
50+
/// matches exactly one element on the other side.
51+
class TuplePackMatcher {
52+
ArrayRef<TupleTypeElt> lhsElts;
53+
ArrayRef<TupleTypeElt> rhsElts;
54+
55+
ASTContext &ctx;
56+
57+
public:
58+
SmallVector<MatchedPair, 4> pairs;
59+
60+
TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple);
61+
62+
bool match();
63+
};
64+
65+
/// Performs a structural match of two lists of (unlabeled) function
66+
/// parameters.
67+
///
68+
/// The invariant is that each list must only contain at most one pack
69+
/// expansion type. After collecting a common prefix and suffix, the
70+
/// pack expansion on either side asborbs the remaining elements on the
71+
/// other side.
72+
class ParamPackMatcher {
73+
ArrayRef<AnyFunctionType::Param> lhsParams;
74+
ArrayRef<AnyFunctionType::Param> rhsParams;
75+
76+
ASTContext &ctx;
77+
78+
public:
79+
SmallVector<MatchedPair, 4> pairs;
80+
81+
ParamPackMatcher(ArrayRef<AnyFunctionType::Param> lhsParams,
82+
ArrayRef<AnyFunctionType::Param> rhsParams,
83+
ASTContext &ctx);
84+
85+
bool match();
86+
};
87+
88+
} // end namespace swift
89+
90+
#endif // SWIFT_AST_TYPE_MATCHER_H

include/swift/AST/ParameterList.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
namespace swift {
2626

27+
class SubstitutionMap;
28+
2729
/// This describes a list of parameters. Each parameter descriptor is tail
2830
/// allocated onto this list.
2931
class alignas(ParamDecl *) ParameterList final :
@@ -134,6 +136,8 @@ class alignas(ParamDecl *) ParameterList final :
134136
/// based on the interface types of the parameters in this list.
135137
void getParams(SmallVectorImpl<AnyFunctionType::Param> &params) const;
136138

139+
unsigned getOrigParamIndex(SubstitutionMap subMap, unsigned substIndex) const;
140+
137141
/// Return the full source range of this parameter.
138142
SourceRange getSourceRange() const;
139143
SourceLoc getStartLoc() const { return getSourceRange().Start; }

include/swift/AST/Types.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
384384
NumProtocols : 16
385385
);
386386

387-
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 5+32,
387+
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 6+32,
388388
/// Type variable options.
389-
Options : 5,
389+
Options : 6,
390390
: NumPadBits,
391391
/// The unique number assigned to this type variable.
392392
ID : 32
@@ -2323,6 +2323,10 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,
23232323
static void Profile(llvm::FoldingSetNodeID &ID,
23242324
ArrayRef<TupleTypeElt> Elements);
23252325

2326+
bool containsPackExpansionType() const;
2327+
2328+
TupleType *flattenPackTypes();
2329+
23262330
private:
23272331
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,
23282332
RecursiveTypeProperties properties)
@@ -3357,6 +3361,10 @@ class AnyFunctionType : public TypeBase {
33573361
/// replaced.
33583362
AnyFunctionType *withExtInfo(ExtInfo info) const;
33593363

3364+
static bool containsPackExpansionType(ArrayRef<Param> params);
3365+
3366+
AnyFunctionType *flattenPackTypes();
3367+
33603368
static void printParams(ArrayRef<Param> Params, raw_ostream &OS,
33613369
const PrintOptions &PO = PrintOptions());
33623370
static void printParams(ArrayRef<Param> Params, ASTPrinter &Printer,
@@ -6410,6 +6418,10 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
64106418
return getTrailingObjects<Type>()[index];
64116419
}
64126420

6421+
bool containsPackExpansionType() const;
6422+
6423+
PackType *flattenPackTypes();
6424+
64136425
public:
64146426
void Profile(llvm::FoldingSetNodeID &ID) const {
64156427
Profile(ID, getElementTypes());
@@ -6480,6 +6492,8 @@ class PackExpansionType : public TypeBase, public llvm::FoldingSetNode {
64806492
/// Retrieves the count type of this pack expansion.
64816493
Type getCountType() const { return countType; }
64826494

6495+
PackExpansionType *expand();
6496+
64836497
public:
64846498
void Profile(llvm::FoldingSetNodeID &ID) {
64856499
Profile(ID, getPatternType(), getCountType());

include/swift/Sema/ConstraintSystem.h

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ enum TypeVariableOptions {
330330
/// Whether a more specific deduction for this type variable implies a
331331
/// better solution to the constraint system.
332332
TVO_PrefersSubtypeBinding = 0x10,
333+
334+
/// Whether the type variable can be bound to a pack type or not.
335+
TVO_CanBindToPack = 0x20,
333336
};
334337

335338
/// The implementation object for a type variable used within the
@@ -387,18 +390,21 @@ class TypeVariableType::Implementation {
387390
&& "Truncation");
388391
}
389392

390-
/// Whether this type variable can bind to an lvalue type.
393+
/// Whether this type variable can bind to an LValueType.
391394
bool canBindToLValue() const { return getRawOptions() & TVO_CanBindToLValue; }
392395

393-
/// Whether this type variable can bind to an inout type.
396+
/// Whether this type variable can bind to an InOutType.
394397
bool canBindToInOut() const { return getRawOptions() & TVO_CanBindToInOut; }
395398

396-
/// Whether this type variable can bind to an inout type.
399+
/// Whether this type variable can bind to a noescape FunctionType.
397400
bool canBindToNoEscape() const { return getRawOptions() & TVO_CanBindToNoEscape; }
398401

399-
/// Whether this type variable can bind to a hole.
402+
/// Whether this type variable can bind to a PlaceholderType.
400403
bool canBindToHole() const { return getRawOptions() & TVO_CanBindToHole; }
401404

405+
/// Whether this type variable can bind to a PackType.
406+
bool canBindToPack() const { return getRawOptions() & TVO_CanBindToPack; }
407+
402408
/// Whether this type variable prefers a subtype binding over a supertype
403409
/// binding.
404410
bool prefersSubtypeBinding() const {
@@ -638,6 +644,7 @@ class TypeVariableType::Implementation {
638644
ENTRY(TVO_CanBindToNoEscape, "noescape");
639645
ENTRY(TVO_CanBindToHole, "hole");
640646
ENTRY(TVO_PrefersSubtypeBinding, "");
647+
ENTRY(TVO_CanBindToPack, "pack");
641648
}
642649
#undef ENTRY
643650
}
@@ -5197,15 +5204,6 @@ class ConstraintSystem {
51975204
ConstraintKind kind, TypeMatchOptions flags,
51985205
ConstraintLocatorBuilder locator);
51995206

5200-
/// Subroutine of \c matchTypes(), which matches a scalar type to
5201-
/// a tuple type.
5202-
///
5203-
/// \returns the result of performing the scalar-to-tuple conversion.
5204-
TypeMatchResult matchScalarToTupleTypes(Type type1, TupleType *tuple2,
5205-
ConstraintKind kind,
5206-
TypeMatchOptions flags,
5207-
ConstraintLocatorBuilder locator);
5208-
52095207
/// Subroutine of \c matchTypes(), which matches up two function
52105208
/// types.
52115209
TypeMatchResult matchFunctionTypes(FunctionType *func1, FunctionType *func2,
@@ -6083,27 +6081,19 @@ class HandlePlaceholderType {
60836081
/// Compute the shuffle required to map from a given tuple type to
60846082
/// another tuple type.
60856083
///
6086-
/// \param fromTuple The tuple type we're converting from, as represented by its
6087-
/// TupleTypeElt members.
6084+
/// \param fromTuple The tuple type we're converting from.
60886085
///
6089-
/// \param toTuple The tuple type we're converting to, as represented by its
6090-
/// TupleTypeElt members.
6086+
/// \param toTuple The tuple type we're converting to.
60916087
///
60926088
/// \param sources Will be populated with information about the source of each
60936089
/// of the elements for the result tuple. The indices into this array are the
60946090
/// indices of the tuple type we're converting to, while the values are
60956091
/// an index into the source tuple.
60966092
///
60976093
/// \returns true if no tuple conversion is possible, false otherwise.
6098-
bool computeTupleShuffle(ArrayRef<TupleTypeElt> fromTuple,
6099-
ArrayRef<TupleTypeElt> toTuple,
6094+
bool computeTupleShuffle(TupleType *fromTuple,
6095+
TupleType *toTuple,
61006096
SmallVectorImpl<unsigned> &sources);
6101-
static inline bool computeTupleShuffle(TupleType *fromTuple,
6102-
TupleType *toTuple,
6103-
SmallVectorImpl<unsigned> &sources){
6104-
return computeTupleShuffle(fromTuple->getElements(), toTuple->getElements(),
6105-
sources);
6106-
}
61076097

61086098
/// Class used as the base for listeners to the \c matchCallArguments process.
61096099
///

lib/AST/ASTContext.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3135,6 +3135,15 @@ TupleType *TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
31353135
properties |= eltTy->getRecursiveProperties();
31363136
}
31373137

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

31403149
void *InsertPos = nullptr;
@@ -3173,8 +3182,14 @@ PackExpansionType::PackExpansionType(Type patternType, Type countType,
31733182
const ASTContext *canCtx)
31743183
: TypeBase(TypeKind::PackExpansion, canCtx, properties),
31753184
patternType(patternType), countType(countType) {
3176-
assert(countType->is<TypeVariableType>() ||
3185+
3186+
// TODO: it would be nice if the solver didn't stick PlaceholderTypes and
3187+
// UnresolvedTypes in here.
3188+
assert(countType->is<PackType>() ||
3189+
countType->is<TypeVariableType>() ||
31773190
countType->is<PackArchetypeType>() ||
3191+
countType->is<PlaceholderType>() ||
3192+
countType->is<UnresolvedType>() ||
31783193
countType->castTo<GenericTypeParamType>()->isParameterPack());
31793194
}
31803195

0 commit comments

Comments
 (0)