@@ -49,15 +49,96 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
49
49
void Initialization::_anchor () {}
50
50
void SILDebuggerClient::anchor () {}
51
51
52
+ static void copyOrInitPackExpansionInto (SILGenFunction &SGF,
53
+ SILLocation loc,
54
+ SILValue tupleAddr,
55
+ CanPackType formalPackType,
56
+ unsigned componentIndex,
57
+ CleanupHandle componentCleanup,
58
+ Initialization *expansionInit,
59
+ bool isInit) {
60
+ auto expansionTy = tupleAddr->getType ().getTupleElementType (componentIndex);
61
+ assert (expansionTy.is <PackExpansionType>());
62
+
63
+ auto opening = SGF.createOpenedElementValueEnvironment (expansionTy);
64
+ auto openedEnv = opening.first ;
65
+ auto eltTy = opening.second ;
66
+
67
+ assert (expansionInit);
68
+ assert (expansionInit->canPerformPackExpansionInitialization ());
69
+
70
+ // Exit the component-wide cleanup for the expansion component.
71
+ if (componentCleanup.isValid ())
72
+ SGF.Cleanups .forwardCleanup (componentCleanup);
73
+
74
+ SGF.emitDynamicPackLoop (loc, formalPackType, componentIndex, openedEnv,
75
+ [&](SILValue indexWithinComponent,
76
+ SILValue packExpansionIndex,
77
+ SILValue packIndex) {
78
+ expansionInit->performPackExpansionInitialization (SGF, loc,
79
+ indexWithinComponent,
80
+ [&](Initialization *eltInit) {
81
+ // Project the current tuple element.
82
+ auto eltAddr =
83
+ SGF.B .createTuplePackElementAddr (loc, packIndex, tupleAddr, eltTy);
84
+
85
+ SILValue elt = eltAddr;
86
+ if (!eltTy.isAddressOnly (SGF.F )) {
87
+ elt = SGF.B .emitLoadValueOperation (loc, elt,
88
+ LoadOwnershipQualifier::Take);
89
+ }
90
+
91
+ // Enter a cleanup for the current element, which we need to consume
92
+ // on this iteration of the loop, and the remaining elements in the
93
+ // expansion component, which we need to destroy if we throw from
94
+ // the initialization.
95
+ CleanupHandle eltCleanup = CleanupHandle::invalid ();
96
+ CleanupHandle tailCleanup = CleanupHandle::invalid ();
97
+ if (componentCleanup.isValid ()) {
98
+ eltCleanup = SGF.enterDestroyCleanup (elt);
99
+ tailCleanup = SGF.enterPartialDestroyRemainingTupleCleanup (tupleAddr,
100
+ formalPackType, componentIndex, indexWithinComponent);
101
+ }
102
+
103
+ auto eltMV = ManagedValue (elt, eltCleanup);
104
+
105
+ // Perform the initialization. If this doesn't consume the
106
+ // element value, that's fine, we'll just destroy it as part of
107
+ // leaving the iteration.
108
+ eltInit->copyOrInitValueInto (SGF, loc, eltMV, isInit);
109
+
110
+ // Deactivate the tail cleanup before continuing the loop.
111
+ if (tailCleanup.isValid ())
112
+ SGF.Cleanups .forwardCleanup (tailCleanup);
113
+ });
114
+ });
115
+
116
+ expansionInit->finishInitialization (SGF);
117
+ }
118
+
52
119
void TupleInitialization::copyOrInitValueInto (SILGenFunction &SGF,
53
120
SILLocation loc,
54
121
ManagedValue value, bool isInit) {
55
- // Process all values before initialization all at once to ensure all cleanups
56
- // are setup on all tuple elements before a potential early exit.
122
+ auto sourceType = value.getType ().castTo <TupleType>();
123
+ assert (sourceType->getNumElements () == SubInitializations.size ());
124
+
125
+ // We have to emit a different pattern when there are pack expansions.
126
+ // Fortunately, we can assume this doesn't happen with objects because
127
+ // tuples contain pack expansions are address-only.
128
+ auto containsPackExpansion = sourceType.containsPackExpansionType ();
129
+
130
+ CanPackType formalPackType;
131
+ if (containsPackExpansion)
132
+ formalPackType = FormalTupleType.getInducedPackType ();
133
+
134
+ // Process all values before initialization all at once to ensure
135
+ // all cleanups are setup on all tuple elements before a potential
136
+ // early exit.
57
137
SmallVector<ManagedValue, 8 > destructuredValues;
58
138
59
- // In the object case, emit a destructure operation and return .
139
+ // In the object case, destructure the tuple .
60
140
if (value.getType ().isObject ()) {
141
+ assert (!containsPackExpansion);
61
142
SGF.B .emitDestructureValueOperation (loc, value, destructuredValues);
62
143
} else {
63
144
// In the address case, we forward the underlying value and store it
@@ -67,11 +148,23 @@ void TupleInitialization::copyOrInitValueInto(SILGenFunction &SGF,
67
148
CleanupCloner cloner (SGF, value);
68
149
SILValue v = value.forward (SGF);
69
150
70
- auto sourceType = value.getType ().castTo <TupleType>();
71
151
auto sourceSILType = value.getType ();
72
- for (unsigned i : range (sourceType->getNumElements ())) {
152
+ for (auto i : range (sourceType->getNumElements ())) {
73
153
SILType fieldTy = sourceSILType.getTupleElementType (i);
74
- SILValue elt = SGF.B .createTupleElementAddr (loc, v, i, fieldTy);
154
+ if (containsPackExpansion && fieldTy.is <PackExpansionType>()) {
155
+ destructuredValues.push_back (
156
+ cloner.cloneForTuplePackExpansionComponent (v, formalPackType, i));
157
+ continue ;
158
+ }
159
+
160
+ SILValue elt;
161
+ if (containsPackExpansion) {
162
+ auto packIndex = SGF.B .createScalarPackIndex (loc, i, formalPackType);
163
+ elt = SGF.B .createTuplePackElementAddr (loc, packIndex, v, fieldTy);
164
+ } else {
165
+ elt = SGF.B .createTupleElementAddr (loc, v, i, fieldTy);
166
+ }
167
+
75
168
if (!fieldTy.isAddressOnly (SGF.F )) {
76
169
elt = SGF.B .emitLoadValueOperation (loc, elt,
77
170
LoadOwnershipQualifier::Take);
@@ -80,7 +173,24 @@ void TupleInitialization::copyOrInitValueInto(SILGenFunction &SGF,
80
173
}
81
174
}
82
175
83
- for (unsigned i : indices (destructuredValues)) {
176
+ assert (destructuredValues.size () == SubInitializations.size ());
177
+
178
+ for (auto i : indices (destructuredValues)) {
179
+ if (containsPackExpansion) {
180
+ bool isPackExpansion =
181
+ (destructuredValues[i].getValue () == value.getValue ());
182
+ assert (isPackExpansion ==
183
+ isa<PackExpansionType>(sourceType.getElementType (i)));
184
+ if (isPackExpansion) {
185
+ auto packAddr = destructuredValues[i].getValue ();
186
+ auto componentCleanup = destructuredValues[i].getCleanup ();
187
+ copyOrInitPackExpansionInto (SGF, loc, packAddr, formalPackType,
188
+ i, componentCleanup,
189
+ SubInitializations[i].get (), isInit);
190
+ continue ;
191
+ }
192
+ }
193
+
84
194
SubInitializations[i]->copyOrInitValueInto (SGF, loc, destructuredValues[i],
85
195
isInit);
86
196
SubInitializations[i]->finishInitialization (SGF);
@@ -148,8 +258,7 @@ splitSingleBufferIntoTupleElements(SILGenFunction &SGF, SILLocation loc,
148
258
// type for the tuple elements below.
149
259
CanPackType inducedPackType;
150
260
if (hasExpansion) {
151
- inducedPackType =
152
- tupleType.getInducedPackType (0 , tupleType->getNumElements ());
261
+ inducedPackType = tupleType.getInducedPackType ();
153
262
}
154
263
155
264
// Destructure the buffer into per-element buffers.
@@ -1250,7 +1359,8 @@ struct InitializationForPattern
1250
1359
// Bind a tuple pattern by aggregating the component variables into a
1251
1360
// TupleInitialization.
1252
1361
InitializationPtr visitTuplePattern (TuplePattern *P) {
1253
- TupleInitialization *init = new TupleInitialization ();
1362
+ TupleInitialization *init = new TupleInitialization (
1363
+ cast<TupleType>(P->getType ()->getCanonicalType ()));
1254
1364
for (auto &elt : P->getElements ())
1255
1365
init->SubInitializations .push_back (visit (elt.getPattern ()));
1256
1366
return InitializationPtr (init);
0 commit comments