Skip to content

Commit 481f9c7

Browse files
committed
Fix memberwise initializers for structs with variadic-tuple fields
1 parent 88bae35 commit 481f9c7

File tree

2 files changed

+208
-20
lines changed

2 files changed

+208
-20
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 174 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ParameterList.h"
2626
#include "swift/AST/PropertyWrappers.h"
2727
#include "swift/Basic/Defer.h"
28+
#include "swift/Basic/Generators.h"
2829
#include "swift/SIL/SILArgument.h"
2930
#include "swift/SIL/SILInstruction.h"
3031
#include "swift/SIL/SILUndef.h"
@@ -33,6 +34,61 @@
3334
using namespace swift;
3435
using namespace Lowering;
3536

37+
namespace {
38+
39+
class LoweredParamsInContextGenerator {
40+
SILGenFunction &SGF;
41+
ArrayRefGenerator<ArrayRef<SILParameterInfo>> loweredParams;
42+
43+
public:
44+
LoweredParamsInContextGenerator(SILGenFunction &SGF)
45+
: SGF(SGF),
46+
loweredParams(SGF.F.getLoweredFunctionType()->getParameters()) {
47+
}
48+
49+
using reference = SILType;
50+
51+
/// Get the original (unsubstituted into context) lowered parameter
52+
/// type information.
53+
SILParameterInfo getOrigInfo() const {
54+
return loweredParams.get();
55+
}
56+
57+
SILType get() const {
58+
return SGF.getSILTypeInContext(loweredParams.get(),
59+
SGF.F.getLoweredFunctionType());
60+
}
61+
62+
SILType claimNext() {
63+
auto param = get();
64+
advance();
65+
return param;
66+
}
67+
68+
bool isFinished() const {
69+
return loweredParams.isFinished();
70+
}
71+
72+
void advance() {
73+
loweredParams.advance();
74+
}
75+
76+
void finish() {
77+
loweredParams.finish();
78+
}
79+
};
80+
81+
} // end anonymous namespace
82+
83+
static ManagedValue emitManagedParameter(SILGenFunction &SGF,
84+
SILValue value, bool isOwned) {
85+
if (isOwned) {
86+
return SGF.emitManagedRValueWithCleanup(value);
87+
} else {
88+
return ManagedValue::forUnmanaged(value);
89+
}
90+
}
91+
3692
static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF,
3793
ValueDecl *ctor) {
3894
// In addition to the declared arguments, the constructor implicitly takes
@@ -63,14 +119,65 @@ static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF,
63119
static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF,
64120
SILLocation loc,
65121
CanType interfaceType,
66-
DeclContext *DC) {
122+
DeclContext *DC,
123+
LoweredParamsInContextGenerator &loweredParamTypes,
124+
Initialization *argInit = nullptr) {
67125
auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType();
68126

69127
// Restructure tuple arguments.
70-
if (auto tupleTy = dyn_cast<TupleType>(interfaceType)) {
128+
if (auto tupleIfaceTy = dyn_cast<TupleType>(interfaceType)) {
129+
// If we don't have a context to emit into, but we have a tuple
130+
// that contains pack expansions, create a temporary.
131+
TemporaryInitializationPtr tempInit;
132+
if (!argInit && tupleIfaceTy.containsPackExpansionType()) {
133+
tempInit = SGF.emitTemporary(loc, SGF.getTypeLowering(type));
134+
argInit = tempInit.get();
135+
}
136+
137+
// Split the initialization into element initializations if we have
138+
// one. We should never have to deal with an initialization that
139+
// can't be split here.
140+
assert(!argInit || argInit->canSplitIntoTupleElements());
141+
SmallVector<InitializationPtr> initsBuf;
142+
MutableArrayRef<InitializationPtr> eltInits;
143+
if (argInit) {
144+
eltInits = argInit->splitIntoTupleElements(SGF, loc, type, initsBuf);
145+
assert(eltInits.size() == tupleIfaceTy->getNumElements());
146+
}
147+
71148
RValue tuple(type);
72-
for (auto fieldType : tupleTy.getElementTypes())
73-
tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC));
149+
150+
for (auto eltIndex : range(tupleIfaceTy->getNumElements())) {
151+
auto eltIfaceType = tupleIfaceTy.getElementType(eltIndex);
152+
auto eltInit = (argInit ? eltInits[eltIndex].get() : nullptr);
153+
RValue element = emitImplicitValueConstructorArg(SGF, loc, eltIfaceType,
154+
DC, loweredParamTypes,
155+
eltInit);
156+
if (argInit) {
157+
assert(element.isInContext());
158+
} else {
159+
tuple.addElement(std::move(element));
160+
}
161+
}
162+
163+
// If we created a temporary initializer above, finish it and claim
164+
// the managed buffer.
165+
if (tempInit) {
166+
tempInit->finishInitialization(SGF);
167+
168+
auto tupleValue = tempInit->getManagedAddress();
169+
if (tupleValue.getType().isLoadable(SGF.F)) {
170+
tupleValue = SGF.B.createLoadTake(loc, tupleValue);
171+
}
172+
173+
return RValue(SGF, loc, type, tupleValue);
174+
175+
// Otherwise, if we have an emitInto, return forInContext().
176+
} else if (argInit) {
177+
argInit->finishInitialization(SGF);
178+
return RValue::forInContext();
179+
}
180+
74181
return tuple;
75182
}
76183

@@ -83,13 +190,51 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF,
83190
VD->setSpecifier(ParamSpecifier::Default);
84191
VD->setInterfaceType(interfaceType);
85192

86-
auto argType = SGF.getLoweredTypeForFunctionArgument(type);
193+
auto origParamInfo = loweredParamTypes.getOrigInfo();
194+
auto argType = loweredParamTypes.claimNext();
195+
87196
auto *arg = SGF.F.begin()->createFunctionArgument(argType, VD);
88-
ManagedValue mvArg;
89-
if (arg->getArgumentConvention().isOwnedConvention()) {
90-
mvArg = SGF.emitManagedRValueWithCleanup(arg);
91-
} else {
92-
mvArg = ManagedValue::forUnmanaged(arg);
197+
bool argIsConsumed = origParamInfo.isConsumed();
198+
199+
// If the lowered parameter is a pack expansion, copy/move the pack
200+
// into the initialization, which we assume is there.
201+
if (auto packTy = argType.getAs<SILPackType>()) {
202+
assert(isa<PackExpansionType>(interfaceType));
203+
assert(packTy->getNumElements() == 1);
204+
assert(argInit);
205+
assert(argInit->canPerformPackExpansionInitialization());
206+
207+
auto expansionTy = packTy->getSILElementType(0);
208+
auto openedEnvAndEltTy =
209+
SGF.createOpenedElementValueEnvironment(expansionTy);
210+
auto openedEnv = openedEnvAndEltTy.first;
211+
auto eltTy = openedEnvAndEltTy.second;
212+
auto formalPackType = CanPackType::get(SGF.getASTContext(), {type});
213+
214+
SGF.emitDynamicPackLoop(loc, formalPackType, /*component*/0, openedEnv,
215+
[&](SILValue indexWithinComponent,
216+
SILValue packExpansionIndex,
217+
SILValue packIndex) {
218+
argInit->performPackExpansionInitialization(SGF, loc,
219+
indexWithinComponent,
220+
[&](Initialization *eltInit) {
221+
auto eltAddr =
222+
SGF.B.createPackElementGet(loc, packIndex, arg, eltTy);
223+
ManagedValue eltMV = emitManagedParameter(SGF, eltAddr, argIsConsumed);
224+
eltInit->copyOrInitValueInto(SGF, loc, eltMV, argIsConsumed);
225+
eltInit->finishInitialization(SGF);
226+
});
227+
});
228+
argInit->finishInitialization(SGF);
229+
return RValue::forInContext();
230+
}
231+
232+
ManagedValue mvArg = emitManagedParameter(SGF, arg, argIsConsumed);
233+
234+
if (argInit) {
235+
argInit->copyOrInitValueInto(SGF, loc, mvArg, argIsConsumed);
236+
argInit->finishInitialization(SGF);
237+
return RValue::forInContext();
93238
}
94239

95240
// This can happen if the value is resilient in the calling convention
@@ -164,15 +309,19 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
164309
AssertingManualScope functionLevelScope(SGF.Cleanups,
165310
CleanupLocation(Loc));
166311

312+
auto loweredFunctionTy = SGF.F.getLoweredFunctionType();
313+
167314
// FIXME: Handle 'self' along with the other arguments.
315+
assert(loweredFunctionTy->getNumResults() == 1);
316+
auto selfResultInfo = loweredFunctionTy->getResults()[0];
168317
auto *paramList = ctor->getParameters();
169318
auto *selfDecl = ctor->getImplicitSelfDecl();
170319
auto selfIfaceTy = selfDecl->getInterfaceType();
171-
SILType selfTy = SGF.getLoweredTypeForFunctionArgument(selfDecl->getType());
320+
SILType selfTy = SGF.getSILTypeInContext(selfResultInfo, loweredFunctionTy);
172321

173322
// Emit the indirect return argument, if any.
174323
SILValue resultSlot;
175-
if (SILModuleConventions::isReturnedIndirectlyInSIL(selfTy, SGF.SGM.M)) {
324+
if (selfTy.isAddress()) {
176325
auto &AC = SGF.getASTContext();
177326
auto VD = new (AC) ParamDecl(SourceLoc(), SourceLoc(),
178327
AC.getIdentifier("$return_value"),
@@ -181,21 +330,25 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
181330
ctor);
182331
VD->setSpecifier(ParamSpecifier::InOut);
183332
VD->setInterfaceType(selfIfaceTy);
184-
resultSlot =
185-
SGF.F.begin()->createFunctionArgument(selfTy.getAddressType(), VD);
333+
resultSlot = SGF.F.begin()->createFunctionArgument(selfTy, VD);
186334
}
187335

336+
LoweredParamsInContextGenerator loweredParams(SGF);
337+
188338
// Emit the elementwise arguments.
189339
SmallVector<RValue, 4> elements;
190340
for (size_t i = 0, size = paramList->size(); i < size; ++i) {
191341
auto &param = paramList->get(i);
192342

193343
elements.push_back(
194344
emitImplicitValueConstructorArg(
195-
SGF, Loc, param->getInterfaceType()->getCanonicalType(), ctor));
345+
SGF, Loc, param->getInterfaceType()->getCanonicalType(), ctor,
346+
loweredParams));
196347
}
197348

198349
emitConstructorMetatypeArg(SGF, ctor);
350+
(void) loweredParams.claimNext();
351+
loweredParams.finish();
199352

200353
auto *decl = selfTy.getStructOrBoundGenericStruct();
201354
assert(decl && "not a struct?!");
@@ -601,16 +754,21 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
601754

602755
Scope scope(Cleanups, CleanupLoc);
603756

757+
LoweredParamsInContextGenerator loweredParams(*this);
758+
604759
// Emit the exploded constructor argument.
605760
ArgumentSource payload;
606761
if (element->hasAssociatedValues()) {
607762
auto eltArgTy = element->getArgumentInterfaceType()->getCanonicalType();
608-
RValue arg = emitImplicitValueConstructorArg(*this, Loc, eltArgTy, element);
763+
RValue arg = emitImplicitValueConstructorArg(*this, Loc, eltArgTy, element,
764+
loweredParams);
609765
payload = ArgumentSource(Loc, std::move(arg));
610766
}
611767

612768
// Emit the metatype argument.
613769
emitConstructorMetatypeArg(*this, element);
770+
(void) loweredParams.claimNext();
771+
loweredParams.finish();
614772

615773
// If possible, emit the enum directly into the indirect return.
616774
SGFContext C = (dest ? SGFContext(dest.get()) : SGFContext());

test/SILGen/variadic-generic-tuples.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,38 @@ func takesConcreteTupleHolderFactory(factory: () -> TupleHolder<Int, String>) {
248248
let holder = factory()
249249
}
250250

251-
/* We still crash with memberwise initializers
252-
func generateConcreteMemberTuple() -> TupleHolder<Int, String> {
253-
return HasMemberTuple(content: (0, "hello"))
251+
struct MemberwiseTupleHolder<each T> {
252+
var content: (repeat each T)
253+
}
254+
255+
// Memberwise initializer.
256+
// TODO: initialize directly into the fields
257+
// CHECK-LABEL: sil{{.*}} @$s4main21MemberwiseTupleHolderV7contentACyxxQp_QPGxxQp_t_tcfC
258+
// CHECK-SAME: $@convention(method) <each T> (@pack_owned Pack{repeat each T}, @thin MemberwiseTupleHolder<repeat each T>.Type) -> @out MemberwiseTupleHolder<repeat each T> {
259+
// CHECK: [[TEMP:%.*]] = alloc_stack $(repeat each T)
260+
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
261+
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
262+
// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T}
263+
// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word)
264+
// CHECK: bb1([[IDX:%.*]] : $Builtin.Word)
265+
// CHECK-NEXT: [[IDX_EQ_LEN:%.*]] = builtin "cmp_eq_Word"([[IDX]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1
266+
// CHECK-NEXT: cond_br [[IDX_EQ_LEN]], bb3, bb2
267+
// CHECK: bb2:
268+
// CHECK-NEXT: [[INDEX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat each T}
269+
// CHECK-NEXT: open_pack_element [[INDEX]] of <each T> at <Pack{repeat each T}>, shape $T, uuid [[UUID:".*"]]
270+
// CHECK-NEXT: [[TUPLE_ELT_ADDR:%.*]] = tuple_pack_element_addr [[INDEX]] of [[TEMP]] : $*(repeat each T) as $*@pack_element([[UUID]]) T
271+
// CHECK-NEXT: [[PACK_ELT_ADDR:%.*]] = pack_element_get [[INDEX]] of %1 : $*Pack{repeat each T} as $*@pack_element([[UUID]]) T
272+
// CHECK-NEXT: copy_addr [take] [[PACK_ELT_ADDR]] to [init] [[TUPLE_ELT_ADDR]]
273+
// CHECK-NEXT: [[NEXT_IDX:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
274+
// CHECK-NEXT: br bb1([[NEXT_IDX]] : $Builtin.Word)
275+
// CHECK: bb3:
276+
// CHECK-NEXT: [[CONTENTS_ADDR:%.*]] = struct_element_addr %0 : $*MemberwiseTupleHolder<repeat each T>, #MemberwiseTupleHolder.content
277+
// CHECK-NEXT: copy_addr [take] [[TEMP]] to [init] [[CONTENTS_ADDR]]
278+
// CHECK-NEXT: tuple ()
279+
// CHECK-NEXT: dealloc_stack [[TEMP]]
280+
// CHECK-NEXT: return
281+
282+
283+
func callVariadicMemberwiseInit() -> MemberwiseTupleHolder<Int, String> {
284+
return MemberwiseTupleHolder(content: (0, "hello"))
254285
}
255-
*/

0 commit comments

Comments
 (0)