Skip to content

Commit e857852

Browse files
committed
[SE-0258] Rewrite findOriginalPropertyWrapperInitialValue() for composition.
Rewrite findOriginalPropertyWrapperInitialValue() to cope with composition of property wrappers, making it more robust in the process. Should fix rdar://problem/51576815.
1 parent 166a6b8 commit e857852

File tree

2 files changed

+113
-13
lines changed

2 files changed

+113
-13
lines changed

lib/AST/Decl.cpp

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5794,25 +5794,71 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
57945794

57955795
Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
57965796
Expr *init) {
5797-
auto attr = var->getAttachedPropertyWrappers().front();
5797+
auto *PBD = var->getParentPatternBinding();
5798+
if (!PBD)
5799+
return nullptr;
57985800

5799-
// Direct initialization implies no original initial value.
5800-
if (attr->getArg())
5801+
// If there is no '=' on the pattern, there was no initial value.
5802+
if (PBD->getPatternList()[0].getEqualLoc().isInvalid())
58015803
return nullptr;
58025804

5803-
// Look through any expressions wrapping the initializer.
5804-
init = init->getSemanticsProvidingExpr();
5805-
auto initCall = dyn_cast<CallExpr>(init);
5806-
if (!initCall)
5805+
ASTContext &ctx = var->getASTContext();
5806+
auto dc = var->getInnermostDeclContext();
5807+
auto innermostAttr = var->getAttachedPropertyWrappers().back();
5808+
auto innermostNominal = evaluateOrDefault(
5809+
ctx.evaluator, CustomAttrNominalRequest{innermostAttr, dc}, nullptr);
5810+
if (!innermostNominal)
58075811
return nullptr;
58085812

5809-
auto initArg = cast<TupleExpr>(initCall->getArg())->getElement(0);
5810-
initArg = initArg->getSemanticsProvidingExpr();
5811-
if (auto autoclosure = dyn_cast<AutoClosureExpr>(initArg)) {
5812-
initArg =
5813-
autoclosure->getSingleExpressionBody()->getSemanticsProvidingExpr();
5814-
}
5813+
// Walker
5814+
class Walker : public ASTWalker {
5815+
public:
5816+
NominalTypeDecl *innermostNominal;
5817+
Expr *initArg = nullptr;
5818+
5819+
Walker(NominalTypeDecl *innermostNominal)
5820+
: innermostNominal(innermostNominal) { }
5821+
5822+
virtual std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
5823+
if (initArg)
5824+
return { false, E };
5825+
5826+
if (auto call = dyn_cast<CallExpr>(E)) {
5827+
// We're looking for an implicit call.
5828+
if (!call->isImplicit())
5829+
return { true, E };
5830+
5831+
// ... producing a value of the same nominal type as the innermost
5832+
// property wrapper.
5833+
if (call->getType()->getAnyNominal() != innermostNominal)
5834+
return { true, E };
5835+
5836+
// Find the implicit initialValue argument.
5837+
if (auto tuple = dyn_cast<TupleExpr>(call->getArg())) {
5838+
ASTContext &ctx = innermostNominal->getASTContext();
5839+
for (unsigned i : range(tuple->getNumElements())) {
5840+
if (tuple->getElementName(i) == ctx.Id_initialValue &&
5841+
tuple->getElementNameLoc(i).isInvalid()) {
5842+
initArg = tuple->getElement(i);
5843+
return { false, E };
5844+
}
5845+
}
5846+
}
5847+
}
58155848

5849+
return { true, E };
5850+
}
5851+
} walker(innermostNominal);
5852+
init->walk(walker);
5853+
5854+
Expr *initArg = walker.initArg;
5855+
if (initArg) {
5856+
initArg = initArg->getSemanticsProvidingExpr();
5857+
if (auto autoclosure = dyn_cast<AutoClosureExpr>(initArg)) {
5858+
initArg =
5859+
autoclosure->getSingleExpressionBody()->getSemanticsProvidingExpr();
5860+
}
5861+
}
58165862
return initArg;
58175863
}
58185864

test/SILGen/property_wrappers.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,60 @@ class UseWrapperWithDefaultInit {
296296
// CHECK: function_ref @$s17property_wrappers22WrapperWithDefaultInitVACyxGycfC
297297
// CHECK: return {{%.*}} : $WrapperWithDefaultInit<String>
298298

299+
// Property wrapper composition.
300+
@propertyWrapper
301+
struct WrapperA<Value> {
302+
var value: Value
303+
304+
init(initialValue: Value) {
305+
value = initialValue
306+
}
307+
}
308+
309+
@propertyWrapper
310+
struct WrapperB<Value> {
311+
var value: Value
312+
313+
init(initialValue: Value) {
314+
value = initialValue
315+
}
316+
}
317+
318+
@propertyWrapper
319+
struct WrapperC<Value> {
320+
var value: Value?
321+
322+
init(initialValue: Value?) {
323+
value = initialValue
324+
}
325+
}
326+
327+
struct CompositionMembers {
328+
// CompositionMembers.p1.getter
329+
// CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers18CompositionMembersV2p1SiSgvg : $@convention(method) (@guaranteed CompositionMembers) -> Optional<Int>
330+
// CHECK: bb0([[SELF:%.*]] : @guaranteed $CompositionMembers):
331+
// CHECK: [[P1:%.*]] = struct_extract [[SELF]] : $CompositionMembers, #CompositionMembers.$p1
332+
// CHECK: [[P1_VALUE:%.*]] = struct_extract [[P1]] : $WrapperA<WrapperB<WrapperC<Int>>>, #WrapperA.value
333+
// CHECK: [[P1_VALUE2:%.*]] = struct_extract [[P1_VALUE]] : $WrapperB<WrapperC<Int>>, #WrapperB.value
334+
// CHECK: [[P1_VALUE3:%.*]] = struct_extract [[P1_VALUE2]] : $WrapperC<Int>, #WrapperC.value
335+
// CHECK: return [[P1_VALUE3]] : $Optional<Int>
336+
@WrapperA @WrapperB @WrapperC var p1: Int?
337+
@WrapperA @WrapperB @WrapperC var p2 = "Hello"
338+
339+
// variable initialization expression of CompositionMembers.$p2
340+
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers18CompositionMembersV3$p233_{{.*}}8WrapperAVyAA0N1BVyAA0N1CVySSGGGvpfi : $@convention(thin) () -> @owned Optional<String> {
341+
// CHECK: %0 = string_literal utf8 "Hello"
342+
343+
// CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers18CompositionMembersV2p12p2ACSiSg_SSSgtcfC : $@convention(method) (Optional<Int>, @owned Optional<String>, @thin CompositionMembers.Type) -> @owned CompositionMembers
344+
// CHECK: function_ref @$s17property_wrappers8WrapperCV12initialValueACyxGxSg_tcfC
345+
// CHECK: function_ref @$s17property_wrappers8WrapperBV12initialValueACyxGx_tcfC
346+
// CHECK: function_ref @$s17property_wrappers8WrapperAV12initialValueACyxGx_tcfC
347+
}
348+
349+
func testComposition() {
350+
_ = CompositionMembers(p1: nil)
351+
}
352+
299353

300354
// CHECK-LABEL: sil_vtable ClassUsingWrapper {
301355
// CHECK-NEXT: #ClassUsingWrapper.x!getter.1: (ClassUsingWrapper) -> () -> Int : @$s17property_wrappers17ClassUsingWrapperC1xSivg // ClassUsingWrapper.x.getter

0 commit comments

Comments
 (0)