Skip to content

Commit 48ea933

Browse files
committed
Parse an ellipsis T... for type parameter packs
In a generic parameter list, parse an ellipsis to produce a type parameter pack. This replaces the previous `@_typeSequence` attribute.
1 parent b645e63 commit 48ea933

15 files changed

+198
-89
lines changed

include/swift/AST/Decl.h

+35-14
Original file line numberDiff line numberDiff line change
@@ -3166,15 +3166,20 @@ class AbstractTypeParamDecl : public TypeDecl {
31663166
/// \code
31673167
/// func min<T : Comparable>(x : T, y : T) -> T { ... }
31683168
/// \endcode
3169-
class GenericTypeParamDecl final :
3170-
public AbstractTypeParamDecl,
3171-
private llvm::TrailingObjects<GenericTypeParamDecl, TypeRepr *>{
3169+
class GenericTypeParamDecl final
3170+
: public AbstractTypeParamDecl,
3171+
private llvm::TrailingObjects<GenericTypeParamDecl, TypeRepr *,
3172+
SourceLoc> {
31723173
friend TrailingObjects;
31733174

3174-
size_t numTrailingObjects(OverloadToken<OpaqueReturnTypeRepr *>) const {
3175+
size_t numTrailingObjects(OverloadToken<TypeRepr *>) const {
31753176
return isOpaqueType() ? 1 : 0;
31763177
}
31773178

3179+
size_t numTrailingObjects(OverloadToken<SourceLoc>) const {
3180+
return isParameterPack() ? 1 : 0;
3181+
}
3182+
31783183
/// Construct a new generic type parameter.
31793184
///
31803185
/// \param dc The DeclContext in which the generic type parameter's owner
@@ -3183,6 +3188,7 @@ class GenericTypeParamDecl final :
31833188
///
31843189
/// \param name The name of the generic parameter.
31853190
/// \param nameLoc The location of the name.
3191+
/// \param ellipsisLoc The location of the ellipsis for a type parameter pack.
31863192
/// \param depth The generic signature depth.
31873193
/// \param index The index of the parameter in the generic signature.
31883194
/// \param isParameterPack Whether the generic parameter is for a type
@@ -3192,8 +3198,9 @@ class GenericTypeParamDecl final :
31923198
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
31933199
///
31943200
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3195-
unsigned depth, unsigned index, bool isParameterPack,
3196-
bool isOpaqueType, TypeRepr *opaqueTypeRepr);
3201+
SourceLoc ellipsisLoc, unsigned depth, unsigned index,
3202+
bool isParameterPack, bool isOpaqueType,
3203+
TypeRepr *opaqueTypeRepr);
31973204

31983205
/// Construct a new generic type parameter.
31993206
///
@@ -3203,6 +3210,7 @@ class GenericTypeParamDecl final :
32033210
///
32043211
/// \param name The name of the generic parameter.
32053212
/// \param nameLoc The location of the name.
3213+
/// \param ellipsisLoc The location of the ellipsis for a type parameter pack.
32063214
/// \param depth The generic signature depth.
32073215
/// \param index The index of the parameter in the generic signature.
32083216
/// \param isParameterPack Whether the generic parameter is for a type
@@ -3212,9 +3220,9 @@ class GenericTypeParamDecl final :
32123220
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
32133221
///
32143222
static GenericTypeParamDecl *create(DeclContext *dc, Identifier name,
3215-
SourceLoc nameLoc, unsigned depth,
3216-
unsigned index, bool isParameterPack,
3217-
bool isOpaqueType,
3223+
SourceLoc nameLoc, SourceLoc ellipsisLoc,
3224+
unsigned depth, unsigned index,
3225+
bool isParameterPack, bool isOpaqueType,
32183226
TypeRepr *opaqueTypeRepr);
32193227

32203228
public:
@@ -3223,9 +3231,11 @@ class GenericTypeParamDecl final :
32233231
/// Construct a new generic type parameter. This should only be used by the
32243232
/// ClangImporter, use \c GenericTypeParamDecl::create[...] instead.
32253233
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3226-
unsigned depth, unsigned index, bool isParameterPack)
3227-
: GenericTypeParamDecl(dc, name, nameLoc, depth, index, isParameterPack,
3228-
/*isOpaqueType*/ false, nullptr) {}
3234+
SourceLoc ellipsisLoc, unsigned depth, unsigned index,
3235+
bool isParameterPack)
3236+
: GenericTypeParamDecl(dc, name, nameLoc, ellipsisLoc, depth, index,
3237+
isParameterPack, /*isOpaqueType*/ false, nullptr) {
3238+
}
32293239

32303240
/// Construct a deserialized generic type parameter.
32313241
///
@@ -3253,13 +3263,14 @@ class GenericTypeParamDecl final :
32533263
///
32543264
/// \param name The name of the generic parameter.
32553265
/// \param nameLoc The location of the name.
3266+
/// \param ellipsisLoc The location of the ellipsis for a type parameter pack.
32563267
/// \param index The index of the parameter in the generic signature.
32573268
/// \param isParameterPack Whether the generic parameter is for a type
32583269
/// parameter pack, denoted by \c <T...>.
32593270
///
32603271
static GenericTypeParamDecl *
32613272
createParsed(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3262-
unsigned index, bool isParameterPack);
3273+
SourceLoc ellipsisLoc, unsigned index, bool isParameterPack);
32633274

32643275
/// Construct a new implicit generic type parameter.
32653276
///
@@ -3276,12 +3287,14 @@ class GenericTypeParamDecl final :
32763287
/// parameter e.g 'some Collection'.
32773288
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
32783289
/// \param nameLoc The location of the name.
3290+
/// \param ellipsisLoc The location of the ellipsis for a type parameter pack.
32793291
///
32803292
static GenericTypeParamDecl *
32813293
createImplicit(DeclContext *dc, Identifier name, unsigned depth,
32823294
unsigned index, bool isParameterPack = false,
32833295
bool isOpaqueType = false, TypeRepr *opaqueTypeRepr = nullptr,
3284-
SourceLoc nameLoc = SourceLoc());
3296+
SourceLoc nameLoc = SourceLoc(),
3297+
SourceLoc ellipsisLoc = SourceLoc());
32853298

32863299
/// The depth of this generic type parameter, i.e., the number of outer
32873300
/// levels of generic parameter lists that enclose this type parameter.
@@ -3348,6 +3361,14 @@ class GenericTypeParamDecl final :
33483361
/// Here 'T' and 'U' have indexes 0 and 1, respectively. 'V' has index 0.
33493362
unsigned getIndex() const { return Bits.GenericTypeParamDecl.Index; }
33503363

3364+
/// Retrieve the ellipsis location for a type parameter pack \c T...
3365+
SourceLoc getEllipsisLoc() const {
3366+
if (!isParameterPack())
3367+
return SourceLoc();
3368+
3369+
return *getTrailingObjects<SourceLoc>();
3370+
}
3371+
33513372
SourceLoc getStartLoc() const { return getNameLoc(); }
33523373
SourceRange getSourceRange() const;
33533374

include/swift/AST/DiagnosticsParse.def

+7
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,13 @@ ERROR(attr_requires_concurrency, none,
19641964
"concurrency is enabled",
19651965
(StringRef, bool))
19661966

1967+
//------------------------------------------------------------------------------
1968+
// MARK: Variadics
1969+
//------------------------------------------------------------------------------
1970+
1971+
ERROR(associatedtype_cannot_be_variadic,none,
1972+
"associated types cannot be variadic", ())
1973+
19671974
//------------------------------------------------------------------------------
19681975
// MARK: Consistency diagnostics
19691976
//------------------------------------------------------------------------------

include/swift/Parse/Parser.h

+8
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,9 @@ class Parser {
807807
/// Check whether the current token starts with '>'.
808808
bool startsWithGreater(Token Tok) { return startsWithSymbol(Tok, '>'); }
809809

810+
/// Check whether the current token starts with '...'.
811+
bool startsWithEllipsis(Token Tok);
812+
810813
/// Returns true if token is an identifier with the given value.
811814
bool isIdentifier(Token Tok, StringRef value) {
812815
return Tok.is(tok::identifier) && Tok.getText() == value;
@@ -822,6 +825,11 @@ class Parser {
822825
/// e.g., '>>'.
823826
SourceLoc consumeStartingGreater();
824827

828+
/// Consume the starting '...' of the current token, which may either be a
829+
/// complete '...' token or some kind of operator token starting with '...',
830+
/// e.g '...>'.
831+
SourceLoc consumeStartingEllipsis();
832+
825833
/// Consume the starting character of the current token, and split the
826834
/// remainder of the token into a new token (or tokens).
827835
SourceLoc

lib/AST/ASTPrinter.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -1684,9 +1684,6 @@ void PrintAST::printSingleDepthOfGenericSignature(
16841684
llvm::interleave(
16851685
genericParams,
16861686
[&](GenericTypeParamType *param) {
1687-
if (param->isParameterPack())
1688-
Printer.printAttrName("@_typeSequence ");
1689-
16901687
if (!subMap.empty()) {
16911688
printType(substParam(param));
16921689
} else if (auto *GP = param->getDecl()) {
@@ -1699,6 +1696,8 @@ void PrintAST::printSingleDepthOfGenericSignature(
16991696
} else {
17001697
printType(param);
17011698
}
1699+
if (param->isParameterPack())
1700+
Printer << "...";
17021701
},
17031702
[&] { Printer << ", "; });
17041703
}
@@ -3502,9 +3501,9 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
35023501

35033502
void PrintAST::visitGenericTypeParamDecl(GenericTypeParamDecl *decl) {
35043503
recordDeclLoc(decl, [&] {
3505-
if (decl->isParameterPack())
3506-
Printer.printAttrName("@_typeSequence ");
35073504
Printer.printName(decl->getName(), PrintNameContext::GenericParameter);
3505+
if (decl->isParameterPack())
3506+
Printer << "...";
35083507
});
35093508

35103509
printInherited(decl);

lib/AST/Decl.cpp

+24-15
Original file line numberDiff line numberDiff line change
@@ -4595,10 +4595,13 @@ AbstractTypeParamDecl::getConformingProtocols() const {
45954595
}
45964596

45974597
GenericTypeParamDecl::GenericTypeParamDecl(
4598-
DeclContext *dc, Identifier name, SourceLoc nameLoc, unsigned depth,
4599-
unsigned index, bool isParameterPack, bool isOpaqueType,
4598+
DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc ellipsisLoc,
4599+
unsigned depth, unsigned index, bool isParameterPack, bool isOpaqueType,
46004600
TypeRepr *opaqueTypeRepr)
46014601
: AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc) {
4602+
assert(!(ellipsisLoc && !isParameterPack) &&
4603+
"Ellipsis always means type parameter pack");
4604+
46024605
Bits.GenericTypeParamDecl.Depth = depth;
46034606
assert(Bits.GenericTypeParamDecl.Depth == depth && "Truncation");
46044607
Bits.GenericTypeParamDecl.Index = index;
@@ -4608,6 +4611,8 @@ GenericTypeParamDecl::GenericTypeParamDecl(
46084611
assert(isOpaqueType || !opaqueTypeRepr);
46094612
if (isOpaqueType)
46104613
*getTrailingObjects<TypeRepr *>() = opaqueTypeRepr;
4614+
if (isParameterPack)
4615+
*getTrailingObjects<SourceLoc>() = ellipsisLoc;
46114616

46124617
auto &ctx = dc->getASTContext();
46134618
RecursiveTypeProperties props = RecursiveTypeProperties::HasTypeParameter;
@@ -4618,51 +4623,55 @@ GenericTypeParamDecl::GenericTypeParamDecl(
46184623
}
46194624

46204625
GenericTypeParamDecl *GenericTypeParamDecl::create(
4621-
DeclContext *dc, Identifier name, SourceLoc nameLoc, unsigned depth,
4622-
unsigned index, bool isParameterPack, bool isOpaqueType,
4626+
DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc ellipsisLoc,
4627+
unsigned depth, unsigned index, bool isParameterPack, bool isOpaqueType,
46234628
TypeRepr *opaqueTypeRepr) {
46244629
auto &ctx = dc->getASTContext();
4625-
auto allocSize = totalSizeToAlloc<TypeRepr *>(isOpaqueType ? 1 : 0);
4630+
auto allocSize = totalSizeToAlloc<TypeRepr *, SourceLoc>(
4631+
isOpaqueType ? 1 : 0, isParameterPack ? 1 : 0);
46264632
auto mem = ctx.Allocate(allocSize, alignof(GenericTypeParamDecl));
46274633
return new (mem)
4628-
GenericTypeParamDecl(dc, name, nameLoc, depth, index,
4634+
GenericTypeParamDecl(dc, name, nameLoc, ellipsisLoc, depth, index,
46294635
isParameterPack, isOpaqueType, opaqueTypeRepr);
46304636
}
46314637

46324638
GenericTypeParamDecl *GenericTypeParamDecl::createDeserialized(
46334639
DeclContext *dc, Identifier name, unsigned depth, unsigned index,
46344640
bool isParameterPack, bool isOpaqueType) {
4635-
return GenericTypeParamDecl::create(dc, name, SourceLoc(), depth, index,
4636-
isParameterPack, isOpaqueType,
4641+
return GenericTypeParamDecl::create(dc, name, SourceLoc(), SourceLoc(), depth,
4642+
index, isParameterPack, isOpaqueType,
46374643
/*opaqueRepr*/ nullptr);
46384644
}
46394645

46404646
GenericTypeParamDecl *
46414647
GenericTypeParamDecl::createParsed(DeclContext *dc, Identifier name,
4642-
SourceLoc nameLoc, unsigned index,
4643-
bool isParameterPack) {
4648+
SourceLoc nameLoc, SourceLoc ellipsisLoc,
4649+
unsigned index, bool isParameterPack) {
46444650
// We always create generic type parameters with an invalid depth.
46454651
// Semantic analysis fills in the depth when it processes the generic
46464652
// parameter list.
46474653
return GenericTypeParamDecl::create(
4648-
dc, name, nameLoc, GenericTypeParamDecl::InvalidDepth, index,
4654+
dc, name, nameLoc, ellipsisLoc, GenericTypeParamDecl::InvalidDepth, index,
46494655
isParameterPack, /*isOpaqueType*/ false, /*opaqueTypeRepr*/ nullptr);
46504656
}
46514657

46524658
GenericTypeParamDecl *GenericTypeParamDecl::createImplicit(
46534659
DeclContext *dc, Identifier name, unsigned depth, unsigned index,
46544660
bool isParameterPack, bool isOpaqueType, TypeRepr *opaqueTypeRepr,
4655-
SourceLoc nameLoc) {
4656-
auto *param = GenericTypeParamDecl::create(dc, name, nameLoc, depth, index,
4657-
isParameterPack, isOpaqueType,
4658-
opaqueTypeRepr);
4661+
SourceLoc nameLoc, SourceLoc ellipsisLoc) {
4662+
auto *param = GenericTypeParamDecl::create(dc, name, nameLoc, ellipsisLoc,
4663+
depth, index, isParameterPack,
4664+
isOpaqueType, opaqueTypeRepr);
46594665
param->setImplicit();
46604666
return param;
46614667
}
46624668

46634669
SourceRange GenericTypeParamDecl::getSourceRange() const {
46644670
SourceLoc endLoc = getNameLoc();
46654671

4672+
if (auto ellipsisLoc = getEllipsisLoc())
4673+
endLoc = ellipsisLoc;
4674+
46664675
if (!getInherited().empty())
46674676
endLoc = getInherited().back().getSourceRange().End;
46684677

lib/ClangImporter/ImportDecl.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -3029,6 +3029,7 @@ namespace {
30293029
param, AccessLevel::Public, dc,
30303030
Impl.SwiftContext.getIdentifier(param->getName()),
30313031
/*nameLoc*/ SourceLoc(),
3032+
/*ellipsisLoc*/ SourceLoc(),
30323033
/*depth*/ 0, /*index*/ i, /*isParameterPack*/ false);
30333034
templateParams.push_back(typeParam);
30343035
(void)++i;
@@ -3478,8 +3479,8 @@ namespace {
34783479
param, AccessLevel::Public, dc,
34793480
Impl.SwiftContext.getIdentifier(param->getName()),
34803481
Impl.importSourceLoc(param->getLocation()),
3481-
/*depth*/ 0, /*index*/ genericParams.size(),
3482-
/*isParameterPack*/ false);
3482+
/*ellipsisLoc*/ SourceLoc(), /*depth*/ 0,
3483+
/*index*/ genericParams.size(), /*isParameterPack*/ false);
34833484
genericParams.push_back(genericParamDecl);
34843485
}
34853486
auto genericParamList = GenericParamList::create(
@@ -6591,6 +6592,7 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
65916592
objcGenericParam, AccessLevel::Public, dc,
65926593
Impl.SwiftContext.getIdentifier(objcGenericParam->getName()),
65936594
Impl.importSourceLoc(objcGenericParam->getLocation()),
6595+
/*ellipsisLoc*/ SourceLoc(),
65946596
/*depth*/ 0, /*index*/ genericParams.size(), /*isParameterPack*/ false);
65956597
// NOTE: depth is always 0 for ObjC generic type arguments, since only
65966598
// classes may have generic types in ObjC, and ObjC classes cannot be

lib/Parse/ParseDecl.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -6146,7 +6146,15 @@ ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions
61466146
.fixItRemove(genericParams->getSourceRange());
61476147
}
61486148
}
6149-
6149+
6150+
// Reject variadic associated types with a specific error.
6151+
if (Context.LangOpts.hasFeature(Feature::VariadicGenerics) &&
6152+
startsWithEllipsis(Tok)) {
6153+
auto Ellipsis = consumeStartingEllipsis();
6154+
diagnose(Ellipsis, diag::associatedtype_cannot_be_variadic)
6155+
.fixItRemoveChars(Ellipsis, Tok.getLoc());
6156+
}
6157+
61506158
// Parse optional inheritance clause.
61516159
// FIXME: Allow class requirements here.
61526160
SmallVector<InheritedEntry, 2> Inherited;

lib/Parse/ParseGeneric.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc,
7373
break;
7474
}
7575

76+
// Parse the ellipsis for a type parameter pack 'T...'.
77+
SourceLoc EllipsisLoc;
78+
if (Context.LangOpts.hasFeature(Feature::VariadicGenerics) &&
79+
startsWithEllipsis(Tok)) {
80+
EllipsisLoc = consumeStartingEllipsis();
81+
}
82+
7683
// Parse the ':' followed by a type.
7784
SmallVector<InheritedEntry, 1> Inherited;
7885
if (Tok.is(tok::colon)) {
@@ -101,10 +108,11 @@ Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc,
101108
}
102109

103110
const bool isParameterPack =
104-
attributes.getAttribute<TypeSequenceAttr>() != nullptr;
111+
attributes.getAttribute<TypeSequenceAttr>() != nullptr ||
112+
EllipsisLoc.isValid();
105113
auto *Param = GenericTypeParamDecl::createParsed(
106-
CurDeclContext, Name, NameLoc, /*index*/ GenericParams.size(),
107-
isParameterPack);
114+
CurDeclContext, Name, NameLoc, EllipsisLoc,
115+
/*index*/ GenericParams.size(), isParameterPack);
108116
if (!Inherited.empty())
109117
Param->setInherited(Context.AllocateCopy(Inherited));
110118
GenericParams.push_back(Param);

lib/Parse/Parser.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,18 @@ SourceLoc Parser::consumeStartingGreater() {
659659
return consumeStartingCharacterOfCurrentToken(tok::r_angle);
660660
}
661661

662+
bool Parser::startsWithEllipsis(Token Tok) {
663+
if (!Tok.isAnyOperator() && !Tok.isPunctuation())
664+
return false;
665+
666+
return Tok.getText().startswith("...");
667+
}
668+
669+
SourceLoc Parser::consumeStartingEllipsis() {
670+
assert(startsWithEllipsis(Tok) && "Token does not start with '...'");
671+
return consumeStartingCharacterOfCurrentToken(tok::ellipsis, /*length*/ 3);
672+
}
673+
662674
ParserStatus Parser::skipSingle() {
663675
ParserStatus status;
664676
switch (Tok.getKind()) {

lib/Syntax/SyntaxFactory.cpp.gyb

+2
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ SyntaxFactory::makeGenericParameter(TokenSyntax Name,
313313
/*UnexpectedNodes=*/None,
314314
/*Name=*/Name,
315315
/*UnexpectedNodes=*/None,
316+
/*Ellipsis=*/None,
317+
/*UnexpectedNodes=*/None,
316318
/*Colon=*/None,
317319
/*UnexpectedNodes=*/None,
318320
/*InheritedType=*/None,

0 commit comments

Comments
 (0)