Skip to content

Commit 05443c4

Browse files
authored
Merge pull request #62509 from hborla/explicit-pack-reference-keyword
[Parser] Add a contextual `each` keyword for pack references.
2 parents 9850906 + 29f6c0d commit 05443c4

14 files changed

+133
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5150,6 +5150,12 @@ ERROR(expansion_not_allowed,none,
51505150
"function result, tuple element or generic argument list", (Type))
51515151
ERROR(expansion_not_variadic,none,
51525152
"variadic expansion %0 must contain at least one variadic generic parameter", (Type))
5153+
ERROR(pack_reference_outside_expansion,none,
5154+
"pack reference %0 can only appear in pack expansion or generic requirement",
5155+
(Type))
5156+
ERROR(each_non_pack,none,
5157+
"'each' cannot be applied to non-pack type %0",
5158+
(Type))
51535159
ERROR(tuple_duplicate_label,none,
51545160
"cannot create a tuple with a duplicate element label", ())
51555161
ERROR(multiple_ellipsis_in_tuple,none,

include/swift/AST/TypeRepr.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,41 @@ class PackExpansionTypeRepr final : public TypeRepr {
743743
friend class TypeRepr;
744744
};
745745

746+
/// A pack reference spelled with the \c each keyword.
747+
///
748+
/// Pack references can only appear inside pack expansions and in
749+
/// generic requirements.
750+
///
751+
/// \code
752+
/// struct Generic<T...> {
753+
/// func f(value: (each T)...) where each T: P {}
754+
/// }
755+
/// \endcode
756+
class PackReferenceTypeRepr: public TypeRepr {
757+
TypeRepr *PackType;
758+
SourceLoc EachLoc;
759+
760+
public:
761+
PackReferenceTypeRepr(SourceLoc eachLoc, TypeRepr *packType)
762+
: TypeRepr(TypeReprKind::PackReference), PackType(packType),
763+
EachLoc(eachLoc) {}
764+
765+
TypeRepr *getPackType() const { return PackType; }
766+
SourceLoc getEachLoc() const { return EachLoc; }
767+
768+
static bool classof(const TypeRepr *T) {
769+
return T->getKind() == TypeReprKind::PackReference;
770+
}
771+
static bool classof(const PackReferenceTypeRepr *T) { return true; }
772+
773+
private:
774+
SourceLoc getStartLocImpl() const { return EachLoc; }
775+
SourceLoc getEndLocImpl() const { return PackType->getEndLoc(); }
776+
SourceLoc getLocImpl() const { return EachLoc; }
777+
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
778+
friend class TypeRepr;
779+
};
780+
746781
/// A tuple type.
747782
/// \code
748783
/// (Foo, Bar)
@@ -1336,6 +1371,7 @@ inline bool TypeRepr::isSimple() const {
13361371
case TypeReprKind::OpaqueReturn:
13371372
case TypeReprKind::NamedOpaqueReturn:
13381373
case TypeReprKind::Existential:
1374+
case TypeReprKind::PackReference:
13391375
return false;
13401376
case TypeReprKind::SimpleIdent:
13411377
case TypeReprKind::GenericIdent:

include/swift/AST/TypeReprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ TYPEREPR(Protocol, TypeRepr)
6464
TYPEREPR(OpaqueReturn, TypeRepr)
6565
TYPEREPR(NamedOpaqueReturn, TypeRepr)
6666
TYPEREPR(Existential, TypeRepr)
67+
TYPEREPR(PackReference, TypeRepr)
6768
TYPEREPR(Placeholder, TypeRepr)
6869
ABSTRACT_TYPEREPR(Specifier, TypeRepr)
6970
SPECIFIER_TYPEREPR(InOut, SpecifierTypeRepr)

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,6 +3141,12 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr> {
31413141
PrintWithColorRAII(OS, ParenthesisColor) << ')';
31423142
}
31433143

3144+
void visitPackReferenceTypeRepr(PackReferenceTypeRepr *T) {
3145+
printCommon("pack_reference");
3146+
printRec(T->getPackType());
3147+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
3148+
}
3149+
31443150
void visitTupleTypeRepr(TupleTypeRepr *T) {
31453151
printCommon("type_tuple");
31463152

lib/AST/ASTWalker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,10 @@ bool Traversal::visitPackExpansionTypeRepr(PackExpansionTypeRepr *T) {
19951995
return doIt(T->getPatternType());
19961996
}
19971997

1998+
bool Traversal::visitPackReferenceTypeRepr(PackReferenceTypeRepr *T) {
1999+
return doIt(T->getPackType());
2000+
}
2001+
19982002
bool Traversal::visitTupleTypeRepr(TupleTypeRepr *T) {
19992003
for (auto &elem : T->getElements()) {
20002004
if (doIt(elem.Type))

lib/AST/NameLookup.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,13 @@ directReferencesForTypeRepr(Evaluator &evaluator,
25162516
allowUsableFromInline);
25172517
}
25182518

2519+
case TypeReprKind::PackReference: {
2520+
auto packReferenceRepr = cast<PackReferenceTypeRepr>(typeRepr);
2521+
return directReferencesForTypeRepr(evaluator, ctx,
2522+
packReferenceRepr->getPackType(), dc,
2523+
allowUsableFromInline);
2524+
}
2525+
25192526
case TypeReprKind::Error:
25202527
case TypeReprKind::Function:
25212528
case TypeReprKind::InOut:

lib/AST/TypeRepr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ void PackExpansionTypeRepr::printImpl(ASTPrinter &Printer,
413413
Printer << "...";
414414
}
415415

416+
void PackReferenceTypeRepr::printImpl(ASTPrinter &Printer,
417+
const PrintOptions &Opts) const {
418+
Printer.printKeyword("each", Opts, /*Suffix=*/" ");
419+
printTypeRepr(PackType, Printer, Opts);
420+
}
421+
416422
void TupleTypeRepr::printImpl(ASTPrinter &Printer,
417423
const PrintOptions &Opts) const {
418424
Printer.callPrintStructurePre(PrintStructureKind::TupleType);

lib/Parse/ParsePattern.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ bool Parser::startsParameterName(bool isClosure) {
162162
// If the first name wasn't "isolated", we're done.
163163
if (!Tok.isContextualKeyword("isolated") &&
164164
!Tok.isContextualKeyword("some") &&
165-
!Tok.isContextualKeyword("any"))
165+
!Tok.isContextualKeyword("any") &&
166+
!Tok.isContextualKeyword("each"))
166167
return true;
167168

168169
// "isolated" can be an argument label, but it's also a contextual keyword,

lib/Parse/ParseType.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,8 @@ Parser::parseTypeIdentifier(bool isParsingQualifiedDeclBaseType) {
780780
/// type-composition '&' type-simple
781781
ParserResult<TypeRepr>
782782
Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) {
783-
// Check for the opaque modifier.
784-
// This is only semantically allowed in certain contexts, but we parse it
783+
// Check for the contextual keyword modifiers on types.
784+
// These are only semantically allowed in certain contexts, but we parse it
785785
// generally for diagnostics and recovery.
786786
SourceLoc opaqueLoc;
787787
SourceLoc anyLoc;
@@ -793,6 +793,16 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) {
793793
// Treat any as a keyword.
794794
TokReceiver->registerTokenKindChange(Tok.getLoc(), tok::contextual_keyword);
795795
anyLoc = consumeToken();
796+
} else if (Tok.isContextualKeyword("each")) {
797+
// Treat 'each' as a keyword.
798+
TokReceiver->registerTokenKindChange(Tok.getLoc(), tok::contextual_keyword);
799+
SourceLoc eachLoc = consumeToken();
800+
ParserResult<TypeRepr> packRef = parseTypeSimple(MessageID, reason);
801+
if (packRef.isNull())
802+
return packRef;
803+
804+
auto *typeRepr = new (Context) PackReferenceTypeRepr(eachLoc, packRef.get());
805+
return makeParserResult(ParserStatus(packRef), typeRepr);
796806
}
797807

798808
auto applyOpaque = [&](TypeRepr *type) -> TypeRepr * {
@@ -1393,6 +1403,8 @@ bool Parser::canParseType() {
13931403
consumeToken();
13941404
} else if (Tok.isContextualKeyword("any")) {
13951405
consumeToken();
1406+
} else if (Tok.isContextualKeyword("each")) {
1407+
consumeToken();
13961408
}
13971409

13981410
switch (Tok.getKind()) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,6 +2261,7 @@ static Type validateParameterType(ParamDecl *decl) {
22612261
// @escaping in this case.
22622262
options.setContext(TypeResolverContext::VariadicFunctionInput);
22632263
options |= TypeResolutionFlags::Direct;
2264+
options |= TypeResolutionFlags::AllowPackReferences;
22642265

22652266
// FIXME: This duplicates code found elsewhere
22662267
auto *patternRepr = packExpansionRepr->getPatternType();

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ RequirementRequest::evaluate(Evaluator &evaluator,
966966
context = TypeResolverContext::GenericRequirement;
967967
}
968968
auto options = TypeResolutionOptions(context);
969+
options |= TypeResolutionFlags::AllowPackReferences;
969970
if (owner.dc->isInSpecializeExtensionContext())
970971
options |= TypeResolutionFlags::AllowUsableFromInline;
971972
Optional<TypeResolution> resolution;

lib/Sema/TypeCheckType.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,6 +2088,8 @@ namespace {
20882088
TypeResolutionOptions options);
20892089
NeverNullType resolvePackExpansionType(PackExpansionTypeRepr *repr,
20902090
TypeResolutionOptions options);
2091+
NeverNullType resolvePackReference(PackReferenceTypeRepr *repr,
2092+
TypeResolutionOptions options);
20912093
NeverNullType resolveTupleType(TupleTypeRepr *repr,
20922094
TypeResolutionOptions options);
20932095
NeverNullType resolveCompositionType(CompositionTypeRepr *repr,
@@ -2277,6 +2279,9 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
22772279
case TypeReprKind::PackExpansion:
22782280
return resolvePackExpansionType(cast<PackExpansionTypeRepr>(repr), options);
22792281

2282+
case TypeReprKind::PackReference:
2283+
return resolvePackReference(cast<PackReferenceTypeRepr>(repr), options);
2284+
22802285
case TypeReprKind::Tuple:
22812286
return resolveTupleType(cast<TupleTypeRepr>(repr), options);
22822287

@@ -4182,6 +4187,7 @@ std::pair<Type, Type>
41824187
TypeResolver::maybeResolvePackExpansionType(PackExpansionTypeRepr *repr,
41834188
TypeResolutionOptions options) {
41844189
auto elementOptions = options;
4190+
elementOptions |= TypeResolutionFlags::AllowPackReferences;
41854191
auto patternTy = resolveType(repr->getPatternType(), elementOptions);
41864192
if (patternTy->hasError())
41874193
return std::make_pair(ErrorType::get(getASTContext()), Type());
@@ -4243,6 +4249,31 @@ NeverNullType TypeResolver::resolvePackExpansionType(PackExpansionTypeRepr *repr
42434249
return PackExpansionType::get(pair.first, pair.second);
42444250
}
42454251

4252+
NeverNullType TypeResolver::resolvePackReference(PackReferenceTypeRepr *repr,
4253+
TypeResolutionOptions options) {
4254+
auto &ctx = getASTContext();
4255+
auto packReference = resolveType(repr->getPackType(), options);
4256+
4257+
// If we already failed, don't diagnose again.
4258+
if (packReference->hasError())
4259+
return ErrorType::get(ctx);
4260+
4261+
if (!packReference->isParameterPack()) {
4262+
ctx.Diags.diagnose(repr->getLoc(), diag::each_non_pack,
4263+
packReference);
4264+
return packReference;
4265+
}
4266+
4267+
if (!options.contains(TypeResolutionFlags::AllowPackReferences)) {
4268+
ctx.Diags.diagnose(repr->getLoc(),
4269+
diag::pack_reference_outside_expansion,
4270+
packReference);
4271+
return ErrorType::get(ctx);
4272+
}
4273+
4274+
return packReference;
4275+
}
4276+
42464277
NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
42474278
TypeResolutionOptions options) {
42484279
auto &ctx = getASTContext();
@@ -4739,6 +4770,7 @@ class ExistentialTypeVisitor
47394770
case TypeReprKind::Placeholder:
47404771
case TypeReprKind::CompileTimeConst:
47414772
case TypeReprKind::PackExpansion:
4773+
case TypeReprKind::PackReference:
47424774
return false;
47434775
}
47444776
}

lib/Sema/TypeCheckType.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ enum class TypeResolutionFlags : uint16_t {
7070

7171
/// We are in a `@preconcurrency` declaration.
7272
Preconcurrency = 1 << 10,
73+
74+
/// Whether references to type parameter packs are allowed.
75+
///
76+
/// Pack references are only allowed inside pack expansions
77+
/// and in generic requirements.
78+
AllowPackReferences = 1 << 11,
7379
};
7480

7581
/// Type resolution contexts that require special handling.

test/type/pack_expansion.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,14 @@ struct Outer<T...> {
6363
struct AlsoGood<U...> {
6464
typealias Value = ((T, E<U... >)...)
6565
}
66-
}
66+
}
67+
68+
func packRef<T...>(_: (each T)...) where each T: P {}
69+
70+
func packMemberRef<T...>(_: (each T.T)...) where each T: P {}
71+
72+
// expected-error@+1 {{'each' cannot be applied to non-pack type 'Int'}}
73+
func invalidPackRef(_: each Int) {}
74+
75+
// expected-error@+1 {{pack reference 'T' can only appear in pack expansion or generic requirement}}
76+
func packRefOutsideExpansion<T...>(_: each T) {}

0 commit comments

Comments
 (0)