Skip to content

Commit 8613b05

Browse files
committed
[DI] Support definite initialization for composed property wrappers.
Use the newly-introduced property wrapper backing initializer function in definite initialization (DI) to form the assign_by_wrapper instruction, rather than forming a reference to the (only) property wrapper's `init(wrappedValue:)`. This allows DI to work on properties that have multiple, composed property wrappers applied to them.
1 parent ab5d161 commit 8613b05

File tree

4 files changed

+77
-70
lines changed

4 files changed

+77
-70
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,30 +5006,6 @@ RValue SILGenFunction::emitApplyMethod(SILLocation loc, ConcreteDeclRef declRef,
50065006
return emission.apply(C);
50075007
}
50085008

5009-
RValue SILGenFunction::emitApplyPropertyWrapperAllocator(SILLocation loc,
5010-
SubstitutionMap subs,
5011-
SILDeclRef ctorRef,
5012-
Type wrapperTy,
5013-
CanAnyFunctionType funcTy) {
5014-
Callee callee = Callee::forDirect(*this, ctorRef, subs, loc);
5015-
5016-
MetatypeType *MTty = MetatypeType::get(wrapperTy);
5017-
auto metatypeVal = B.createMetatype(loc, getLoweredType(MTty));
5018-
ManagedValue mtManagedVal = ManagedValue::forUnmanaged(metatypeVal);
5019-
RValue metatypeRVal(*this, loc, MTty->getCanonicalType(), mtManagedVal);
5020-
5021-
ArgumentSource ArgSrc(loc, std::move(metatypeRVal));
5022-
FormalEvaluationScope writebacks(*this);
5023-
CallEmission emission(*this, std::move(callee), std::move(writebacks));
5024-
5025-
AnyFunctionType::Param selfParam((Type(MTty)), Identifier(),
5026-
ParameterTypeFlags());
5027-
emission.addSelfParam(loc, std::move(ArgSrc), selfParam, funcTy.getResult());
5028-
5029-
RValue RV = emission.apply();
5030-
return RV;
5031-
}
5032-
50335009
/// Emit a literal that applies the various initializers.
50345010
RValue SILGenFunction::emitLiteral(LiteralExpr *literal, SGFContext C) {
50355011
ConcreteDeclRef builtinInit;

lib/SILGen/SILGenFunction.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,12 +1492,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14921492
ArgumentSource &&self, PreparedArguments &&args,
14931493
SGFContext C);
14941494

1495-
RValue emitApplyPropertyWrapperAllocator(SILLocation loc,
1496-
SubstitutionMap subs,
1497-
SILDeclRef ctorRef,
1498-
Type wrapperTy,
1499-
CanAnyFunctionType funcTy);
1500-
15011495
CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn,
15021496
SubstitutionMap subs, ArrayRef<ManagedValue> args,
15031497
CanSILFunctionType substFnType,

lib/SILGen/SILGenLValue.cpp

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,29 +1295,26 @@ namespace {
12951295

12961296
bool hasPropertyWrapper() const {
12971297
if (auto *VD = dyn_cast<VarDecl>(Storage)) {
1298-
// FIXME: Handle composition of property wrappers.
1299-
if (VD->getAttachedPropertyWrappers().size() == 1) {
1300-
auto wrapperInfo = VD->getAttachedPropertyWrapperTypeInfo(0);
1301-
1302-
// If there is no init(wrapperValue:), we cannot rewrite an
1303-
// assignment into an initialization.
1304-
if (!wrapperInfo.wrappedValueInit)
1305-
return false;
1306-
1307-
// If we have a nonmutating setter on a value type, the call
1308-
// captures all of 'self' and we cannot rewrite an assignment
1309-
// into an initialization.
1310-
if (!VD->isSetterMutating() &&
1311-
VD->getDeclContext()->getSelfNominalTypeDecl() &&
1312-
VD->isInstanceMember() &&
1313-
!VD->getDeclContext()->getDeclaredInterfaceType()
1314-
->hasReferenceSemantics()) {
1315-
return false;
1316-
}
1317-
1318-
return true;
1298+
// If this is not a wrapper property that can be initialized from
1299+
// a value of the wrapped type, we can't perform the initialization.
1300+
auto wrapperInfo = VD->getPropertyWrapperBackingPropertyInfo();
1301+
if (!wrapperInfo.initializeFromOriginal)
1302+
return false;
1303+
1304+
// If we have a nonmutating setter on a value type, the call
1305+
// captures all of 'self' and we cannot rewrite an assignment
1306+
// into an initialization.
1307+
if (!VD->isSetterMutating() &&
1308+
VD->getDeclContext()->getSelfNominalTypeDecl() &&
1309+
VD->isInstanceMember() &&
1310+
!VD->getDeclContext()->getDeclaredInterfaceType()
1311+
->hasReferenceSemantics()) {
1312+
return false;
13191313
}
1314+
1315+
return true;
13201316
}
1317+
13211318
return false;
13221319
}
13231320

@@ -1404,25 +1401,32 @@ namespace {
14041401
proj = std::move(SEC).project(SGF, loc, base);
14051402
}
14061403

1407-
// Create the allocating initializer function. It captures the metadata.
1408-
// FIXME: Composition.
1409-
assert(field->getAttachedPropertyWrappers().size() == 1);
1410-
auto wrapperInfo = field->getAttachedPropertyWrapperTypeInfo(0);
1411-
auto ctor = wrapperInfo.wrappedValueInit;
1412-
SubstitutionMap subs = ValType->getMemberSubstitutionMap(
1413-
SGF.getModule().getSwiftModule(), ctor);
1414-
1415-
Type ity = ctor->getInterfaceType();
1416-
AnyFunctionType *substIty =
1417-
ity.subst(subs)->getCanonicalType()->castTo<AnyFunctionType>();
1418-
1419-
auto initRef = SILDeclRef(ctor, SILDeclRef::Kind::Allocator)
1420-
.asForeign(requiresForeignEntryPoint(ctor));
1421-
RValue initFuncRV =
1422-
SGF.emitApplyPropertyWrapperAllocator(loc, subs,initRef,
1423-
ValType,
1424-
CanAnyFunctionType(substIty));
1425-
ManagedValue initFn = std::move(initFuncRV).getAsSingleValue(SGF, loc);
1404+
// The property wrapper backing initializer forms an instance of
1405+
// the backing storage type from a wrapped value.
1406+
SILDeclRef initConstant(
1407+
field, SILDeclRef::Kind::PropertyWrapperBackingInitializer);
1408+
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1409+
1410+
SubstitutionMap initSubs;
1411+
if (auto genericSig = field->getInnermostDeclContext()
1412+
->getGenericSignatureOfContext()) {
1413+
initSubs = SubstitutionMap::get(
1414+
genericSig,
1415+
[&](SubstitutableType *type) {
1416+
if (auto gp = type->getAs<GenericTypeParamType>()) {
1417+
return SGF.F.mapTypeIntoContext(gp);
1418+
}
1419+
1420+
return Type(type);
1421+
},
1422+
LookUpConformanceInModule(SGF.SGM.M.getSwiftModule()));
1423+
}
1424+
1425+
PartialApplyInst *initPAI =
1426+
SGF.B.createPartialApply(loc, initFRef,
1427+
initSubs, ArrayRef<SILValue>(),
1428+
ParameterConvention::Direct_Guaranteed);
1429+
ManagedValue initFn = SGF.emitManagedRValueWithCleanup(initPAI);
14261430

14271431
// Create the allocating setter function. It captures the base address.
14281432
auto setterInfo = SGF.getConstantInfo(setter);

test/SILOptimizer/di_property_wrappers.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,43 @@ func testDefaultNilOptIntStruct() {
380380
// CHECK-NEXT: .. init nil
381381
}
382382

383+
@propertyWrapper
384+
struct Wrapper2<T> {
385+
var wrappedValue: T {
386+
didSet {
387+
print(" .. secondSet \(wrappedValue)")
388+
}
389+
}
390+
391+
init(wrappedValue initialValue: T) {
392+
print(" .. secondInit \(initialValue)")
393+
self.wrappedValue = initialValue
394+
}
395+
}
396+
397+
struct HasComposed {
398+
@Wrapper @Wrapper2 var x: Int
399+
400+
init() {
401+
self.x = 17
402+
}
403+
}
404+
405+
func testComposed() {
406+
// CHECK: ## Composed
407+
print("\n## Composed")
408+
_ = HasComposed()
409+
410+
// CHECK-NEXT: .. secondInit 17
411+
// CHECK-NEXT: .. init Wrapper2<Int>(wrappedValue: 17)
412+
}
413+
414+
383415
testIntStruct()
384416
testIntClass()
385417
testRefStruct()
386418
testGenericClass()
387419
testDefaultInit()
388420
testOptIntStruct()
389421
testDefaultNilOptIntStruct()
422+
testComposed()

0 commit comments

Comments
 (0)