Skip to content

Commit d1bb5ad

Browse files
committed
[SILGen] TypeWrappers: Handle initialization of property wrapped fields without init exprs
Type wrapper synthesis cannot reply on `getExecutableInit` to determine whether initialization should use backing wrapper call or not, it has to check whether the init expression exists.
1 parent e51176b commit d1bb5ad

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,16 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD,
13471347
auto initialization = emitPatternBindingInitialization(PBD->getPattern(idx),
13481348
JumpDest::invalid());
13491349

1350+
auto getWrappedValueExpr = [&](VarDecl *var) -> Expr * {
1351+
if (auto *orig = var->getOriginalWrappedProperty()) {
1352+
auto initInfo = orig->getPropertyWrapperInitializerInfo();
1353+
if (auto *placeholder = initInfo.getWrappedValuePlaceholder()) {
1354+
return placeholder->getOriginalWrappedValue();
1355+
}
1356+
}
1357+
return nullptr;
1358+
};
1359+
13501360
auto emitInitializer = [&](Expr *initExpr, VarDecl *var, bool forLocalContext,
13511361
InitializationPtr &initialization) {
13521362
// If an initial value expression was specified by the decl, emit it into
@@ -1355,14 +1365,11 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD,
13551365

13561366
if (forLocalContext) {
13571367
if (auto *orig = var->getOriginalWrappedProperty()) {
1358-
auto initInfo = orig->getPropertyWrapperInitializerInfo();
1359-
if (auto *placeholder = initInfo.getWrappedValuePlaceholder()) {
1360-
initExpr = placeholder->getOriginalWrappedValue();
1361-
1368+
if (auto *initExpr = getWrappedValueExpr(var)) {
13621369
auto value = emitRValue(initExpr);
13631370
emitApplyOfPropertyWrapperBackingInitializer(
1364-
PBD, orig, getForwardingSubstitutionMap(), std::move(value))
1365-
.forwardInto(*this, SILLocation(PBD), initialization.get());
1371+
PBD, orig, getForwardingSubstitutionMap(), std::move(value))
1372+
.forwardInto(*this, SILLocation(PBD), initialization.get());
13661373
return;
13671374
}
13681375
}
@@ -1430,7 +1437,11 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD,
14301437

14311438
auto &fieldInit = fieldInits[i];
14321439
if (initExpr) {
1433-
emitInitializer(initExpr, field, /*forLocalContext=*/true, fieldInit);
1440+
// If there is wrapped value expression, we have to emit a
1441+
// backing property initializer call, otherwise let's use
1442+
// default expression (which is just `.init()` call).
1443+
emitInitializer(initExpr, field, bool(getWrappedValueExpr(field)),
1444+
fieldInit);
14341445
} else {
14351446
fieldInit->finishUninitialized(*this);
14361447
}

test/Interpreter/Inputs/type_wrapper_defs.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,21 @@ public protocol WrappedProtocol {
401401

402402
var v: T { get set }
403403
}
404+
405+
@propertyWrapper
406+
public struct PropWrapperWithDefaultInit<T> {
407+
typealias Wrapped = T
408+
409+
public var wrappedValue: T {
410+
get { value! }
411+
set { value = newValue }
412+
}
413+
414+
var value: T?
415+
416+
public init() {}
417+
418+
public init(wrappedValue: T) {
419+
self.value = wrappedValue
420+
}
421+
}

test/Interpreter/type_wrappers.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,24 @@ do {
689689
// CHECK-NEXT: in getter storage: \$Storage.v
690690
// CHECK-NEXT: 1
691691
}
692+
693+
do {
694+
@Wrapper
695+
class Test {
696+
@PropWrapperWithDefaultInit var x: Int
697+
698+
required init() {}
699+
700+
required init(x: Int) {
701+
self.x = x
702+
}
703+
}
704+
705+
var test = Test(x: 42)
706+
print(test.x)
707+
// CHECK: Wrapper.init(for: Test, storage: $Storage(_x: type_wrapper_defs.PropWrapperWithDefaultInit<Swift.Int>(value: nil)))
708+
// CHECK-NEXT: in (reference type) getter storage: \$Storage._x
709+
// CHECK-NEXT: in (reference type) setter => PropWrapperWithDefaultInit<Int>(value: Optional(42))
710+
// CHECK-NEXT: in (reference type) getter storage: \$Storage._x
711+
// CHECK-NEXT: 42
712+
}

0 commit comments

Comments
 (0)