30
30
#include " swift/SIL/SILInstruction.h"
31
31
#include " swift/SIL/SILUndef.h"
32
32
#include " swift/SIL/TypeLowering.h"
33
+ #include < map>
33
34
34
35
using namespace swift ;
35
36
using namespace Lowering ;
@@ -271,6 +272,47 @@ static RValue maybeEmitPropertyWrapperInitFromValue(
271
272
subs, std::move (arg));
272
273
}
273
274
275
+ static void emitApplyOfInitAccessor (SILGenFunction &SGF, SILLocation loc,
276
+ AccessorDecl *accessor, SILValue selfValue,
277
+ SILType selfTy, RValue &&initialValue) {
278
+ SmallVector<SILValue> arguments;
279
+
280
+ auto emitFieldReference = [&](VarDecl *field) {
281
+ auto fieldTy =
282
+ selfTy.getFieldType (field, SGF.SGM .M , SGF.getTypeExpansionContext ());
283
+ return SGF.B .createStructElementAddr (loc, selfValue, field,
284
+ fieldTy.getAddressType ());
285
+ };
286
+
287
+ // First, let's emit all of the indirect results.
288
+ if (auto *initAttr = accessor->getAttrs ().getAttribute <InitializesAttr>()) {
289
+ for (auto *property : initAttr->getPropertyDecls (accessor)) {
290
+ arguments.push_back (emitFieldReference (property));
291
+ }
292
+ }
293
+
294
+ // `initialValue`
295
+ std::move (initialValue).forwardAll (SGF, arguments);
296
+
297
+ // And finally, all of the properties in `accesses(...)` list which are
298
+ // `inout` arguments.
299
+ if (auto *accessAttr = accessor->getAttrs ().getAttribute <AccessesAttr>()) {
300
+ for (auto *property : accessAttr->getPropertyDecls (accessor)) {
301
+ arguments.push_back (emitFieldReference (property));
302
+ }
303
+ }
304
+
305
+ SubstitutionMap subs;
306
+ if (auto *env =
307
+ accessor->getDeclContext ()->getGenericEnvironmentOfContext ()) {
308
+ subs = env->getForwardingSubstitutionMap ();
309
+ }
310
+
311
+ SILValue accessorRef =
312
+ SGF.emitGlobalFunctionRef (loc, SGF.getAccessorDeclRef (accessor));
313
+ (void )SGF.B .createApply (loc, accessorRef, subs, arguments, ApplyOptions ());
314
+ }
315
+
274
316
static SubstitutionMap getSubstitutionsForPropertyInitializer (
275
317
DeclContext *dc,
276
318
NominalTypeDecl *nominal) {
@@ -312,6 +354,12 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
312
354
auto selfIfaceTy = selfDecl->getInterfaceType ();
313
355
SILType selfTy = SGF.getSILTypeInContext (selfResultInfo, loweredFunctionTy);
314
356
357
+ auto *decl = selfTy.getStructOrBoundGenericStruct ();
358
+ assert (decl && " not a struct?!" );
359
+
360
+ std::multimap<VarDecl *, VarDecl *> initializedViaAccessor;
361
+ decl->collectPropertiesInitializableByInitAccessors (initializedViaAccessor);
362
+
315
363
// Emit the indirect return argument, if any.
316
364
SILValue resultSlot;
317
365
if (selfTy.isAddress ()) {
@@ -324,6 +372,10 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
324
372
VD->setSpecifier (ParamSpecifier::InOut);
325
373
VD->setInterfaceType (selfIfaceTy);
326
374
resultSlot = SGF.F .begin ()->createFunctionArgument (selfTy, VD);
375
+ } else if (!initializedViaAccessor.empty ()) {
376
+ // Allocate "self" on stack which we are going to use to
377
+ // reference/init fields and then load to return.
378
+ resultSlot = SGF.emitTemporaryAllocation (Loc, selfTy);
327
379
}
328
380
329
381
LoweredParamsInContextGenerator loweredParams (SGF);
@@ -343,15 +395,34 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
343
395
(void ) loweredParams.claimNext ();
344
396
loweredParams.finish ();
345
397
346
- auto *decl = selfTy.getStructOrBoundGenericStruct ();
347
- assert (decl && " not a struct?!" );
348
-
349
398
auto subs = getSubstitutionsForPropertyInitializer (decl, decl);
350
399
351
400
// If we have an indirect return slot, initialize it in-place.
352
401
if (resultSlot) {
402
+ // Tracks all the init accessors we have emitted
403
+ // because they can initialize more than one property.
404
+ llvm::SmallPtrSet<AccessorDecl *, 2 > emittedInitAccessors;
405
+
353
406
auto elti = elements.begin (), eltEnd = elements.end ();
354
407
for (VarDecl *field : decl->getStoredProperties ()) {
408
+
409
+ // Handle situations where this stored propery is initialized
410
+ // via a call to an init accessor on some other property.
411
+ if (initializedViaAccessor.count (field)) {
412
+ auto *initProperty = initializedViaAccessor.find (field)->second ;
413
+ auto *initAccessor = initProperty->getAccessor (AccessorKind::Init);
414
+
415
+ if (emittedInitAccessors.count (initAccessor))
416
+ continue ;
417
+
418
+ emitApplyOfInitAccessor (SGF, Loc, initAccessor, resultSlot, selfTy,
419
+ std::move (*elti));
420
+
421
+ emittedInitAccessors.insert (initAccessor);
422
+ ++elti;
423
+ continue ;
424
+ }
425
+
355
426
auto fieldTy =
356
427
selfTy.getFieldType (field, SGF.SGM .M , SGF.getTypeExpansionContext ());
357
428
SILValue slot =
@@ -423,6 +494,16 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
423
494
}
424
495
}
425
496
497
+ // Load as "take" from our stack allocation and return.
498
+ if (!selfTy.isAddress () && !initializedViaAccessor.empty ()) {
499
+ auto resultValue = SGF.B .emitLoadValueOperation (
500
+ Loc, resultSlot, LoadOwnershipQualifier::Take);
501
+
502
+ SGF.B .createReturn (ImplicitReturnLocation (Loc), resultValue,
503
+ std::move (functionLevelScope));
504
+ return ;
505
+ }
506
+
426
507
SGF.B .createReturn (ImplicitReturnLocation (Loc),
427
508
SGF.emitEmptyTuple (Loc), std::move (functionLevelScope));
428
509
return ;
0 commit comments