Skip to content

Commit a2d0bf6

Browse files
committed
[PropertyWrappers] When finding the initial value for the property, properly handle the situation where we have multiple attached property wrappers
If a property has multiple property wrappers attached, we'll have multiple nested calls, where each call's argument is a call to construct the next wrapper in the chain. However, when we use multiple wrappers consecutively, we cannot just rely on the call's type matching the innermost wrapper's type, because it will match the first wrapper in the sequence of consective wrappers and we'll end up crashing in SILGen. So, we should check if the call's argument is another call and look into that before checking the types.
1 parent 9931aab commit a2d0bf6

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

lib/AST/Decl.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6127,13 +6127,25 @@ Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
61276127
if (!call->isImplicit())
61286128
return { true, E };
61296129

6130-
// ... producing a value of the same nominal type as the innermost
6131-
// property wrapper.
6130+
// ... which may call the constructor of another property
6131+
// wrapper if there are multiple wrappers attached to the
6132+
// property.
6133+
if (auto tuple = dyn_cast<TupleExpr>(call->getArg())) {
6134+
if (tuple->getNumElements() > 0) {
6135+
auto elem = tuple->getElement(0);
6136+
if (elem->isImplicit() && isa<CallExpr>(elem)) {
6137+
return { true, E };
6138+
}
6139+
}
6140+
}
6141+
6142+
// ... producing a value of the same nominal type as the
6143+
// innermost property wrapper.
61326144
if (!call->getType() ||
61336145
call->getType()->getAnyNominal() != innermostNominal)
6134-
return { true, E };
6146+
return { false, E };
61356147

6136-
// Find the implicit initialValue argument.
6148+
// Find the implicit initialValue/wrappedValue argument.
61376149
if (auto tuple = dyn_cast<TupleExpr>(call->getArg())) {
61386150
ASTContext &ctx = innermostNominal->getASTContext();
61396151
for (unsigned i : range(tuple->getNumElements())) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend -emit-sil %s
2+
3+
@propertyWrapper
4+
struct Foo<T> {
5+
init(wrappedValue: T) {
6+
self.wrappedValue = wrappedValue
7+
}
8+
9+
var wrappedValue: T
10+
}
11+
12+
@propertyWrapper
13+
struct Bar<T> {
14+
init(wrappedValue: T) {
15+
self.wrappedValue = wrappedValue
16+
}
17+
18+
var wrappedValue: T
19+
}
20+
21+
struct Container {
22+
@Foo @Foo var x: Int = 0
23+
@Foo @Foo @Bar @Bar var y: Int = 1
24+
@Foo @Bar @Foo @Foo var z: Int = 2
25+
}
26+
27+
_ = Container()

0 commit comments

Comments
 (0)