Skip to content

Commit 0594efc

Browse files
Merge pull request #66214 from sophiapoirier/tuple-expansion-without-dot-element
[Variadic Generics] drop requirement of .element for tuple expansion
2 parents daaee27 + 93864f6 commit 0594efc

13 files changed

+94
-29
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
@@ -5223,7 +5223,6 @@ void PrintAST::visitPackExpansionExpr(PackExpansionExpr *expr) {
52235223

52245224
void PrintAST::visitMaterializePackExpr(MaterializePackExpr *expr) {
52255225
visit(expr->getFromExpr());
5226-
Printer << ".element";
52275226
}
52285227

52295228
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
@@ -3148,10 +3148,11 @@ namespace {
31483148
if (type->is<ElementArchetypeType>() &&
31493149
CS.hasFixFor(CS.getConstraintLocator(declRef),
31503150
FixKind::IgnoreMissingEachKeyword)) {
3151-
Packs.push_back(PackElementExpr::create(CS.getASTContext(),
3152-
/*eachLoc=*/SourceLoc(),
3153-
declRef,
3154-
/*implicit=*/true));
3151+
auto *packElementExpr =
3152+
PackElementExpr::create(CS.getASTContext(),
3153+
/*eachLoc=*/{}, declRef,
3154+
/*implicit=*/true, type);
3155+
Packs.push_back(CS.cacheType(packElementExpr));
31553156
}
31563157
}
31573158

@@ -3230,8 +3231,17 @@ namespace {
32303231
}
32313232

32323233
Type visitPackElementExpr(PackElementExpr *expr) {
3233-
return openPackElement(CS.getType(expr->getPackRefExpr()),
3234-
CS.getConstraintLocator(expr));
3234+
auto packType = CS.getType(expr->getPackRefExpr());
3235+
3236+
if (isSingleUnlabeledPackExpansionTuple(packType)) {
3237+
packType =
3238+
addMemberRefConstraints(expr, expr->getPackRefExpr(),
3239+
DeclNameRef(CS.getASTContext().Id_element),
3240+
FunctionRefKind::Unapplied, {});
3241+
CS.setType(expr->getPackRefExpr(), packType);
3242+
}
3243+
3244+
return openPackElement(packType, CS.getConstraintLocator(expr));
32353245
}
32363246

32373247
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());
@@ -9121,6 +9129,16 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
91219129
return SolutionKind::Solved;
91229130
}
91239131

9132+
if (isSingleUnlabeledPackExpansionTuple(patternType)) {
9133+
auto *elementVar =
9134+
createTypeVariable(getConstraintLocator(locator), /*options=*/0);
9135+
addValueMemberConstraint(
9136+
patternType, DeclNameRef(getASTContext().Id_element), elementVar, DC,
9137+
FunctionRefKind::Unapplied, {},
9138+
getConstraintLocator(locator, {ConstraintLocator::Member}));
9139+
patternType = elementVar;
9140+
}
9141+
91249142
// Let's try to resolve element type based on the pattern type.
91259143
if (!patternType->hasTypeVariable()) {
91269144
auto *loc = getConstraintLocator(locator);
@@ -9338,6 +9356,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
93389356
if (!memberName.isSpecial()) {
93399357
StringRef nameStr = memberName.getBaseIdentifier().str();
93409358
// Accessing `.element` on an abstract tuple materializes a pack.
9359+
// (deprecated behavior)
93419360
if (nameStr == "element" && baseTuple->getNumElements() == 1 &&
93429361
isPackExpansionType(baseTuple->getElementType(0))) {
93439362
auto elementType = baseTuple->getElementType(0);
@@ -13312,6 +13331,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
1331213331
return SolutionKind::Solved;
1331313332
}
1331413333

13334+
// Map element archetypes to the pack context to check for equality.
13335+
if (packTy->hasElementArchetype()) {
13336+
auto *packEnv = DC->getGenericEnvironmentOfContext();
13337+
packTy = packEnv->mapElementTypeIntoPackContext(packTy);
13338+
}
13339+
1331513340
auto shape = packTy->getReducedShape();
1331613341
addConstraint(ConstraintKind::Bind, shapeTy, shape, locator);
1331713342
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
@@ -129,14 +129,18 @@ func expansionOfNonPackType<T>(_ t: repeat each T) {}
129129

130130
func tupleExpansion<each T, each U>(
131131
_ tuple1: (repeat each T),
132-
_ tuple2: (repeat each U)
132+
_ tuple2: (repeat each U),
133+
_ tuple3: inout (repeat each T)
133134
) {
134-
_ = forward(repeat each tuple1.element)
135+
_ = forward(repeat each tuple1)
135136

136-
_ = zip(repeat each tuple1.element, with: repeat each tuple1.element)
137+
_ = zip(repeat each tuple1, with: repeat each tuple1)
138+
_ = zip(repeat each tuple1, with: repeat each tuple1.element) // legacy syntax
137139

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

142146
protocol Generatable {
@@ -243,10 +247,10 @@ func test_pack_expansion_materialization_from_lvalue_base() {
243247

244248
init() {
245249
self.data = (repeat Data<each T>())
246-
_ = (repeat each data.element) // Ok
250+
_ = (repeat each data) // Ok
247251

248252
var tmp = (repeat Data<each T>()) // expected-warning {{never mutated}}
249-
_ = (repeat each tmp.element) // Ok
253+
_ = (repeat each tmp) // Ok
250254

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

275279
let tuple = (repeat each t)
276280

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

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

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

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

test/Interpreter/Inputs/variadic_generic_library.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ public struct Predicate<each Input> {
4444
builder: (repeat Variable<each Input>) -> Expr
4545
) where Expr: Expression<Bool> {
4646
self.variables = (repeat Variable<each Input>())
47-
self.expression = builder(repeat each variables.element)
47+
self.expression = builder(repeat each variables)
4848
}
4949

5050
public func evaluate(
5151
_ input: repeat each Input
5252
) throws -> Bool {
5353
return try expression.evaluate(
54-
.init(repeat (each variables.element, each input))
54+
.init(repeat (each variables, each input))
5555
)
5656
}
5757
}

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
@@ -123,7 +123,7 @@ func wrapTupleElements<each T>(_ value: repeat each T) -> (repeat Wrapper<each T
123123
// CHECK: [[VAR:%.*]] = alloc_stack [lexical] $(repeat each T)
124124
let values = (repeat each value)
125125

126-
// Create a temporary for the 'values' in 'each values.element'
126+
// Create a temporary for the 'values' in 'each values'
127127
// CHECK: bb3:
128128
// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $(repeat each T)
129129
// CHECK-NEXT: copy_addr [[VAR]] to [init] [[TEMP]] : $*(repeat each T)
@@ -155,7 +155,7 @@ func wrapTupleElements<each T>(_ value: repeat each T) -> (repeat Wrapper<each T
155155
// CHECK-NEXT: [[NEXT_INDEX:%.*]] = builtin "add_Word"([[INDEX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
156156
// CHECK-NEXT: br bb4([[NEXT_INDEX]] : $Builtin.Word)
157157

158-
return (repeat Wrapper(value: each values.element))
158+
return (repeat Wrapper(value: each values))
159159

160160
// CHECK: destroy_addr [[TEMP]] : $*(repeat each T)
161161
// CHECK: dealloc_stack [[TEMP]] : $*(repeat each T)
@@ -303,7 +303,7 @@ struct FancyTuple<each T> {
303303
var x: (repeat each T)
304304

305305
func makeTuple() -> (repeat each T) {
306-
return (repeat each x.element)
306+
return (repeat each x)
307307
}
308308
}
309309

0 commit comments

Comments
 (0)