Skip to content

Commit 0459312

Browse files
authored
Merge pull request #66243 from sophiapoirier/tuple-expansion-without-dot-element
[Variadic Generics] drop requirement of .element for tuple expansion
2 parents b43ed62 + d1fd468 commit 0459312

File tree

12 files changed

+92
-27
lines changed

12 files changed

+92
-27
lines changed

include/swift/AST/Expr.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,15 +3679,15 @@ class PackExpansionExpr final : public Expr {
36793679
};
36803680

36813681
/// An expression to materialize a pack from a tuple containing a pack
3682-
/// expansion, spelled \c tuple.element.
3682+
/// expansion.
36833683
///
36843684
/// These nodes are created by CSApply and should only appear in a
36853685
/// type-checked AST in the context of a \c PackExpansionExpr .
36863686
class MaterializePackExpr final : public Expr {
36873687
/// The expression from which to materialize a pack.
36883688
Expr *FromExpr;
36893689

3690-
/// The source location of \c .element
3690+
/// The source location of (deprecated) \c .element
36913691
SourceLoc ElementLoc;
36923692

36933693
MaterializePackExpr(Expr *fromExpr, SourceLoc elementLoc,
@@ -3711,7 +3711,7 @@ class MaterializePackExpr final : public Expr {
37113711
}
37123712

37133713
SourceLoc getEndLoc() const {
3714-
return ElementLoc;
3714+
return ElementLoc.isInvalid() ? ElementLoc : FromExpr->getEndLoc();
37153715
}
37163716

37173717
static bool classof(const Expr *E) {

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ IDENTIFIER(size)
324324
IDENTIFIER(speed)
325325
IDENTIFIER(unchecked)
326326
IDENTIFIER(unsafe)
327+
IDENTIFIER(element)
327328

328329
// The singleton instance of TupleTypeDecl in the Builtin module
329330
IDENTIFIER(TheTupleType)

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6100,6 +6100,8 @@ Type isPlaceholderVar(PatternBindingDecl *PB);
61006100
/// Dump an anchor node for a constraint locator or contextual type.
61016101
void dumpAnchor(ASTNode anchor, SourceManager *SM, raw_ostream &out);
61026102

6103+
bool isSingleUnlabeledPackExpansionTuple(Type type);
6104+
61036105
} // end namespace constraints
61046106

61056107
template<typename ...Args>

include/swift/Sema/OverloadChoice.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ enum class OverloadChoiceKind : int {
5454
/// The overload choice selects a particular declaration that
5555
/// was found by unwrapping an optional context type.
5656
DeclViaUnwrappedOptional,
57-
/// The overload choice materializes a pack from a tuple using
58-
/// the \c .element syntax.
57+
/// The overload choice materializes a pack from a tuple.
5958
MaterializePack,
6059
/// The overload choice indexes into a tuple. Index zero will
6160
/// have the value of this enumerator, index one will have the value of this

lib/AST/ASTPrinter.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5192,7 +5192,6 @@ void PrintAST::visitPackExpansionExpr(PackExpansionExpr *expr) {
51925192

51935193
void PrintAST::visitMaterializePackExpr(MaterializePackExpr *expr) {
51945194
visit(expr->getFromExpr());
5195-
Printer << ".element";
51965195
}
51975196

51985197
void PrintAST::visitPackElementExpr(PackElementExpr *expr) {

lib/Sema/CSApply.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3846,6 +3846,21 @@ namespace {
38463846
}
38473847

38483848
Expr *visitPackElementExpr(PackElementExpr *expr) {
3849+
if (auto *packRefExpr = expr->getPackRefExpr()) {
3850+
packRefExpr = cs.coerceToRValue(packRefExpr);
3851+
auto packRefType = cs.getType(packRefExpr);
3852+
if (auto *tuple = packRefType->getRValueType()->getAs<TupleType>();
3853+
tuple && tuple->isSingleUnlabeledPackExpansion()) {
3854+
auto *expansion =
3855+
tuple->getElementType(0)->castTo<PackExpansionType>();
3856+
auto patternType = expansion->getPatternType();
3857+
auto *materializedPackExpr = MaterializePackExpr::create(
3858+
cs.getASTContext(), packRefExpr, packRefExpr->getLoc(),
3859+
patternType, /*implicit*/ true);
3860+
cs.cacheType(materializedPackExpr);
3861+
expr->setPackRefExpr(materializedPackExpr);
3862+
}
3863+
}
38493864
return simplifyExprType(expr);
38503865
}
38513866

lib/Sema/CSGen.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3142,10 +3142,11 @@ namespace {
31423142
if (type->is<ElementArchetypeType>() &&
31433143
CS.hasFixFor(CS.getConstraintLocator(declRef),
31443144
FixKind::IgnoreMissingEachKeyword)) {
3145-
Packs.push_back(PackElementExpr::create(CS.getASTContext(),
3146-
/*eachLoc=*/SourceLoc(),
3147-
declRef,
3148-
/*implicit=*/true));
3145+
auto *packElementExpr =
3146+
PackElementExpr::create(CS.getASTContext(),
3147+
/*eachLoc=*/{}, declRef,
3148+
/*implicit=*/true, type);
3149+
Packs.push_back(CS.cacheType(packElementExpr));
31493150
}
31503151
}
31513152

@@ -3224,8 +3225,17 @@ namespace {
32243225
}
32253226

32263227
Type visitPackElementExpr(PackElementExpr *expr) {
3227-
return openPackElement(CS.getType(expr->getPackRefExpr()),
3228-
CS.getConstraintLocator(expr));
3228+
auto packType = CS.getType(expr->getPackRefExpr());
3229+
3230+
if (isSingleUnlabeledPackExpansionTuple(packType)) {
3231+
packType =
3232+
addMemberRefConstraints(expr, expr->getPackRefExpr(),
3233+
DeclNameRef(CS.getASTContext().Id_element),
3234+
FunctionRefKind::Unapplied, {});
3235+
CS.setType(expr->getPackRefExpr(), packType);
3236+
}
3237+
3238+
return openPackElement(packType, CS.getConstraintLocator(expr));
32293239
}
32303240

32313241
Type visitMaterializePackExpr(MaterializePackExpr *expr) {

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ static bool isPackExpansionType(Type type) {
127127
return false;
128128
}
129129

130+
bool constraints::isSingleUnlabeledPackExpansionTuple(Type type) {
131+
auto *tuple = type->getRValueType()->getAs<TupleType>();
132+
// TODO: drop no name requirement
133+
return tuple && (tuple->getNumElements() == 1) &&
134+
isPackExpansionType(tuple->getElementType(0)) &&
135+
!tuple->getElement(0).hasName();
136+
}
137+
130138
static bool containsPackExpansionType(ArrayRef<AnyFunctionType::Param> params) {
131139
return llvm::any_of(params, [&](const auto &param) {
132140
return isPackExpansionType(param.getPlainType());
@@ -9150,6 +9158,16 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
91509158
return SolutionKind::Solved;
91519159
}
91529160

9161+
if (isSingleUnlabeledPackExpansionTuple(patternType)) {
9162+
auto *elementVar =
9163+
createTypeVariable(getConstraintLocator(locator), /*options=*/0);
9164+
addValueMemberConstraint(
9165+
patternType, DeclNameRef(getASTContext().Id_element), elementVar, DC,
9166+
FunctionRefKind::Unapplied, {},
9167+
getConstraintLocator(locator, {ConstraintLocator::Member}));
9168+
patternType = elementVar;
9169+
}
9170+
91539171
// Let's try to resolve element type based on the pattern type.
91549172
if (!patternType->hasTypeVariable()) {
91559173
auto *loc = getConstraintLocator(locator);
@@ -9367,6 +9385,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
93679385
if (!memberName.isSpecial()) {
93689386
StringRef nameStr = memberName.getBaseIdentifier().str();
93699387
// Accessing `.element` on an abstract tuple materializes a pack.
9388+
// (deprecated behavior)
93709389
if (nameStr == "element" && baseTuple->getNumElements() == 1 &&
93719390
isPackExpansionType(baseTuple->getElementType(0))) {
93729391
auto elementType = baseTuple->getElementType(0);
@@ -13341,6 +13360,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
1334113360
return SolutionKind::Solved;
1334213361
}
1334313362

13363+
// Map element archetypes to the pack context to check for equality.
13364+
if (packTy->hasElementArchetype()) {
13365+
auto *packEnv = DC->getGenericEnvironmentOfContext();
13366+
packTy = packEnv->mapElementTypeIntoPackContext(packTy);
13367+
}
13368+
1334413369
auto shape = packTy->getReducedShape();
1334513370
addConstraint(ConstraintKind::Bind, shapeTy, shape, locator);
1334613371
return SolutionKind::Solved;

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3559,7 +3559,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
35593559
break;
35603560

35613561
case OverloadChoiceKind::MaterializePack: {
3562-
// Since `.element` is only applicable to single element tuples at the
3562+
// Since pack expansion is only applicable to single element tuples at the
35633563
// moment we can just look through l-value base to load it.
35643564
//
35653565
// In the future, _if_ the syntax allows for multiple expansions

test/Constraints/pack-expansion-expressions.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,18 @@ func expansionOfNonPackType<T>(_ t: repeat each T) {}
131131

132132
func tupleExpansion<each T, each U>(
133133
_ tuple1: (repeat each T),
134-
_ tuple2: (repeat each U)
134+
_ tuple2: (repeat each U),
135+
_ tuple3: inout (repeat each T)
135136
) {
136-
_ = forward(repeat each tuple1.element)
137+
_ = forward(repeat each tuple1)
137138

138-
_ = zip(repeat each tuple1.element, with: repeat each tuple1.element)
139+
_ = zip(repeat each tuple1, with: repeat each tuple1)
140+
_ = zip(repeat each tuple1, with: repeat each tuple1.element) // legacy syntax
139141

140-
_ = zip(repeat each tuple1.element, with: repeat each tuple2.element)
142+
_ = zip(repeat each tuple1, with: repeat each tuple2)
141143
// expected-error@-1 {{global function 'zip(_:with:)' requires the type packs 'each T' and 'each U' have the same shape}}
144+
145+
_ = forward(repeat each tuple3)
142146
}
143147

144148
protocol Generatable {
@@ -244,10 +248,10 @@ func test_pack_expansion_materialization_from_lvalue_base() {
244248

245249
init() {
246250
self.data = (repeat Data<each T>())
247-
_ = (repeat each data.element) // Ok
251+
_ = (repeat each data) // Ok
248252

249253
var tmp = (repeat Data<each T>()) // expected-warning {{never mutated}}
250-
_ = (repeat each tmp.element) // Ok
254+
_ = (repeat each tmp) // Ok
251255

252256
// TODO: Add subscript test-case when syntax is supported.
253257
}
@@ -275,10 +279,9 @@ func packOutsideExpansion<each T>(_ t: repeat each T) {
275279

276280
let tuple = (repeat each t)
277281

278-
_ = tuple.element
279-
// expected-error@-1{{pack reference 'each T' can only appear in pack expansion}}
282+
_ = tuple
280283

281-
_ = each tuple.element
284+
_ = each tuple
282285
// expected-error@-1{{pack reference 'each T' can only appear in pack expansion}}
283286
}
284287

@@ -482,7 +485,6 @@ do {
482485
func test_misplaced_each<each T: P>(_ value: repeat each T) -> (repeat each T.A) {
483486
return (repeat each value.makeA())
484487
// expected-error@-1 {{value pack 'each T' must be referenced with 'each'}} {{25-25=(each }} {{30-30=)}}
485-
// expected-error@-2 {{pack expansion requires that '()' and 'each T' have the same shape}}
486488
}
487489
}
488490

@@ -540,3 +542,15 @@ do {
540542
test2(repeat each t2, repeat each t1) // expected-error {{local function 'test2' requires that 'each T2' conform to 'RawRepresentable'}}
541543
}
542544
}
545+
546+
do {
547+
func overloaded<each T>(_ a: Int, _ b: repeat each T) -> (repeat each T) {
548+
return (repeat each b)
549+
}
550+
551+
func overloaded() {}
552+
553+
func test<each T>(_ a: repeat each T) {
554+
_ = (repeat overloaded(1, each a))
555+
}
556+
}

test/Interpreter/variadic_generic_tuples.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func makeTuple<each Element>(
5757

5858
func expandTupleElements<each T: Equatable>(_ value: repeat each T) {
5959
let values = makeTuple(repeat each value)
60-
_ = (repeat expectEqual(each value, each values.element))
60+
_ = (repeat expectEqual(each value, each values))
6161
}
6262

6363
tuples.test("expandTuple") {

test/SILGen/variadic-generic-tuples.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func wrapTupleElements<each T>(_ value: repeat each T) -> (repeat Wrapper<each T
126126
// CHECK: [[VAR:%.*]] = alloc_stack [lexical] $(repeat each T)
127127
let values = (repeat each value)
128128

129-
// Create a temporary for the 'values' in 'each values.element'
129+
// Create a temporary for the 'values' in 'each values'
130130
// CHECK: bb3:
131131
// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $(repeat each T)
132132
// CHECK-NEXT: copy_addr [[VAR]] to [init] [[TEMP]] : $*(repeat each T)
@@ -158,7 +158,7 @@ func wrapTupleElements<each T>(_ value: repeat each T) -> (repeat Wrapper<each T
158158
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
159159
// CHECK-NEXT: br bb4([[NEXT_INDEX]] : $Builtin.Word)
160160

161-
return (repeat Wrapper(value: each values.element))
161+
return (repeat Wrapper(value: each values))
162162

163163
// CHECK: destroy_addr [[TEMP]] : $*(repeat each T)
164164
// CHECK: dealloc_stack [[TEMP]] : $*(repeat each T)
@@ -306,7 +306,7 @@ struct FancyTuple<each T> {
306306
var x: (repeat each T)
307307

308308
func makeTuple() -> (repeat each T) {
309-
return (repeat each x.element)
309+
return (repeat each x)
310310
}
311311
}
312312

0 commit comments

Comments
 (0)