Skip to content

Commit 5ac8d76

Browse files
committed
[Property wrappers] Allow default initialization to infer a type.
Property wrappers are allowed to infer the type of a variable, but this only worked when the property wrapper was provided with an explicit initialization, e.g., @WrapsAnInt() var x // infers type Int from WrapsAnInt.wrappedValue However, when default initialization is supported by the property wrapper, dropping the parentheses would produce an error about the missing type annotation @WrapsAnInt var x Make this second case behave like the first, so that default initialization works consistently with the explicitly-specified version. Fixes rdar://problem/59471019.
1 parent 38964fc commit 5ac8d76

File tree

5 files changed

+59
-11
lines changed

5 files changed

+59
-11
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,9 @@ class PatternBindingDecl final : public Decl,
21862186
/// Can the pattern at index i be default initialized?
21872187
bool isDefaultInitializable(unsigned i) const;
21882188

2189+
/// Can the property wrapper be used to provide default initialization?
2190+
bool isDefaultInitializableViaPropertyWrapper(unsigned i) const;
2191+
21892192
/// Does this pattern have a user-provided initializer expression?
21902193
bool isExplicitlyInitialized(unsigned i) const;
21912194

lib/AST/Decl.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,17 @@ bool Pattern::isNeverDefaultInitializable() const {
18551855
return result;
18561856
}
18571857

1858+
bool PatternBindingDecl::isDefaultInitializableViaPropertyWrapper(unsigned i) const {
1859+
if (auto singleVar = getSingleVar()) {
1860+
if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) {
1861+
if (wrapperInfo.defaultInit)
1862+
return true;
1863+
}
1864+
}
1865+
1866+
return false;
1867+
}
1868+
18581869
bool PatternBindingDecl::isDefaultInitializable(unsigned i) const {
18591870
const auto entry = getPatternList()[i];
18601871

@@ -1864,13 +1875,13 @@ bool PatternBindingDecl::isDefaultInitializable(unsigned i) const {
18641875

18651876
// If the outermost attached property wrapper vends an `init()`, use that
18661877
// for default initialization.
1878+
if (isDefaultInitializableViaPropertyWrapper(i))
1879+
return true;
1880+
1881+
// If one of the attached wrappers is missing an initialValue
1882+
// initializer, cannot default-initialize.
18671883
if (auto singleVar = getSingleVar()) {
18681884
if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) {
1869-
if (wrapperInfo.defaultInit)
1870-
return true;
1871-
1872-
// If one of the attached wrappers is missing an initialValue
1873-
// initializer, cannot default-initialize.
18741885
if (!singleVar->allAttachedPropertyWrappersHaveInitialValueInit())
18751886
return false;
18761887
}

lib/AST/Pattern.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,10 @@ PatternBindingDecl *ContextualPattern::getPatternBindingDecl() const {
516516
}
517517

518518
bool ContextualPattern::allowsInference() const {
519-
if (auto pbd = getPatternBindingDecl())
520-
return pbd->isInitialized(index);
519+
if (auto pbd = getPatternBindingDecl()) {
520+
return pbd->isInitialized(index) ||
521+
pbd->isDefaultInitializableViaPropertyWrapper(index);
522+
}
521523

522524
return true;
523525
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4188,12 +4188,21 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
41884188
return;
41894189

41904190
backingInitializer = wrappedInitializer;
4191-
} else if (auto outermostArg = outermostWrapperAttr->getArg()) {
4191+
} else {
41924192
Type outermostWrapperType =
41934193
singleVar->getAttachedPropertyWrapperType(0);
41944194
if (!outermostWrapperType)
41954195
return;
41964196

4197+
// Retrieve the outermost wrapper argument. If there isn't one, we're
4198+
// performing default initialization.
4199+
auto outermostArg = outermostWrapperAttr->getArg();
4200+
if (!outermostArg) {
4201+
SourceLoc fakeParenLoc = outermostWrapperAttr->getRange().End;
4202+
outermostArg = TupleExpr::createEmpty(
4203+
ctx, fakeParenLoc, fakeParenLoc, /*Implicit=*/true);
4204+
}
4205+
41974206
auto typeExpr = TypeExpr::createImplicitHack(
41984207
outermostWrapperAttr->getTypeLoc().getLoc(),
41994208
outermostWrapperType, ctx);
@@ -4203,8 +4212,6 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
42034212
outermostWrapperAttr->getArgumentLabelLocs(),
42044213
/*hasTrailingClosure=*/false,
42054214
/*implicit=*/false);
4206-
} else {
4207-
llvm_unreachable("No initializer anywhere?");
42084215
}
42094216
wrapperAttrs[0]->setSemanticInit(backingInitializer);
42104217

test/decl/var/property_wrappers.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,7 @@ open class OpenPropertyWrapperWithPublicInit {
18771877
public init(wrappedValue: String) { // Okay
18781878
self.wrappedValue = wrappedValue
18791879
}
1880-
1880+
18811881
open var wrappedValue: String = "Hello, world"
18821882
}
18831883

@@ -1895,3 +1895,28 @@ func sr_11654_generic_func<T>(_ argument: T?) -> T? {
18951895

18961896
let sr_11654_c = SR_11654_C()
18971897
_ = sr_11654_generic_func(sr_11654_c.property) // Okay
1898+
1899+
// rdar://problem/59471019 - property wrapper initializer requires empty parens
1900+
// for default init
1901+
@propertyWrapper
1902+
struct DefaultableIntWrapper {
1903+
var wrappedValue: Int
1904+
1905+
init() {
1906+
self.wrappedValue = 0
1907+
}
1908+
}
1909+
1910+
struct TestDefaultableIntWrapper {
1911+
@DefaultableIntWrapper var x
1912+
@DefaultableIntWrapper() var y
1913+
@DefaultableIntWrapper var z: Int
1914+
1915+
mutating func test() {
1916+
x = y
1917+
y = z
1918+
}
1919+
}
1920+
1921+
1922+

0 commit comments

Comments
 (0)