Skip to content

Commit 5b2ce0d

Browse files
authored
Merge pull request #62699 from xedin/type-wrapper-fixes
[SILGen/DI] TypeWrapper: Few improvements to synthesis in user-defined initializers
2 parents c4cacd1 + 01b5a9d commit 5b2ce0d

File tree

5 files changed

+129
-16
lines changed

5 files changed

+129
-16
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
}

lib/SILGen/SILGenType.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,14 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
11151115
if (auto *normal = dyn_cast<NormalProtocolConformance>(conformance))
11161116
SGM.getWitnessTable(normal);
11171117
}
1118+
1119+
// Emit `init(for:storage)` initializer as it would be used
1120+
// by DI and IRGen later on.
1121+
if (auto typeWrapperInfo = theType->getTypeWrapper()) {
1122+
auto *ctor = typeWrapperInfo->Wrapper->getTypeWrapperInitializer();
1123+
assert(ctor);
1124+
(void)SGM.getFunction(SILDeclRef(ctor), NotForDefinition);
1125+
}
11181126
}
11191127

11201128
//===--------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,15 +1315,24 @@ void LifetimeChecker::injectTypeWrapperStorageInitalization() {
13151315
wrapperInitArgs.push_back(storageObj);
13161316
wrapperInitArgs.push_back(typeWrapperType);
13171317

1318-
// <wrapper-var> = <TypeWrapper>.init(storage: tmpStorage)
1319-
auto wrapperInitResult = b.createApply(
1320-
loc, typeWrapperInitRef,
1321-
SubstitutionMap::get(typeWrapperInit->getGenericSignature(),
1322-
/*substitutions=*/
1323-
{wrappedType->getMetatypeInstanceType(),
1324-
storageType.getASTType()},
1325-
/*conformances=*/{}),
1326-
wrapperInitArgs);
1318+
TypeSubstitutionMap wrapperInitSubs;
1319+
{
1320+
auto sig =
1321+
typeWrapperInit->getGenericSignature().getCanonicalSignature();
1322+
wrapperInitSubs[sig.getGenericParams()[0]] =
1323+
wrappedType->getMetatypeInstanceType();
1324+
wrapperInitSubs[sig.getGenericParams()[1]] = storageType.getASTType();
1325+
}
1326+
1327+
// <wrapper-var> = <TypeWrapper>.init(for: <Type>, storage: tmpStorage)
1328+
auto wrapperInitResult =
1329+
b.createApply(loc, typeWrapperInitRef,
1330+
SubstitutionMap::get(
1331+
typeWrapperInit->getGenericSignature(),
1332+
QueryTypeSubstitutionMap{wrapperInitSubs},
1333+
LookUpConformanceInModule(
1334+
ctor->getDeclContext()->getParentModule())),
1335+
wrapperInitArgs);
13271336

13281337
// self.$storage is a property access so it has to has to be wrapped
13291338
// in begin/end access instructions.

test/Interpreter/Inputs/type_wrapper_defs.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,53 @@ 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+
}
422+
423+
@typeWrapper
424+
public struct WrapperWithConformance<W : WrappedTypesOnly, S> {
425+
var underlying: S
426+
427+
public init(for wrappedType: W.Type, storage: S) {
428+
print("WrapperWithConformance.init(for: \(wrappedType), storage: \(storage))")
429+
self.underlying = storage
430+
}
431+
432+
public subscript<V>(propertyKeyPath propertyPath: KeyPath<W, V>,
433+
storageKeyPath storagePath: KeyPath<S, V>) -> V {
434+
get {
435+
print("in read-only getter storage: \(storagePath)")
436+
return underlying[keyPath: storagePath]
437+
}
438+
}
439+
440+
public subscript<V>(propertyKeyPath propertyPath: KeyPath<W, V>,
441+
storageKeyPath storagePath: WritableKeyPath<S, V>) -> V {
442+
get {
443+
print("in getter storage: \(storagePath)")
444+
return underlying[keyPath: storagePath]
445+
}
446+
set {
447+
print("in setter => \(newValue)")
448+
underlying[keyPath: storagePath] = newValue
449+
}
450+
}
451+
}
452+
453+
public protocol WrappedTypesOnly {}

test/Interpreter/type_wrappers.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,38 @@ 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+
}
713+
714+
do {
715+
@WrapperWithConformance
716+
struct Test : WrappedTypesOnly {
717+
var a: Int = 42
718+
var b: String = ""
719+
@PropWrapperWithDefaultInit var c: [Int]
720+
721+
init() {}
722+
}
723+
724+
let test = Test()
725+
// CHECK: WrapperWithConformance.init(for: Test, storage: $Storage(a: 42, b: "", _c: type_wrapper_defs.PropWrapperWithDefaultInit<Swift.Array<Swift.Int>>(value: nil)))
726+
}

0 commit comments

Comments
 (0)