Skip to content

Commit 85762c3

Browse files
authored
Merge pull request #30663 from DougGregor/property-wrapper-default-init-infer-type
[Property wrappers] Allow default initialization to infer a type.
2 parents ff36b5e + d282e3c commit 85762c3

File tree

8 files changed

+77
-40
lines changed

8 files changed

+77
-40
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 5 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

@@ -5138,15 +5141,17 @@ class VarDecl : public AbstractStorageDecl {
51385141
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
51395142

51405143
/// Retrieve the custom attributes that attach property wrappers to this
5141-
/// property. The returned list contains all of the attached property wrapper attributes in source order,
5142-
/// which means the outermost wrapper attribute is provided first.
5144+
/// property. The returned list contains all of the attached property wrapper
5145+
/// attributes in source order, which means the outermost wrapper attribute
5146+
/// is provided first.
51435147
llvm::TinyPtrVector<CustomAttr *> getAttachedPropertyWrappers() const;
51445148

51455149
/// Whether this property has any attached property wrappers.
51465150
bool hasAttachedPropertyWrapper() const;
51475151

5148-
/// Whether all of the attached property wrappers have an init(initialValue:) initializer.
5149-
bool allAttachedPropertyWrappersHaveInitialValueInit() const;
5152+
/// Whether all of the attached property wrappers have an init(wrappedValue:)
5153+
/// initializer.
5154+
bool allAttachedPropertyWrappersHaveWrappedValueInit() const;
51505155

51515156
/// Retrieve the type of the attached property wrapper as a contextual
51525157
/// type.
@@ -5210,7 +5215,7 @@ class VarDecl : public AbstractStorageDecl {
52105215
/// \end
52115216
///
52125217
/// Or when there is no initializer but each composed property wrapper has
5213-
/// a suitable `init(initialValue:)`.
5218+
/// a suitable `init(wrappedValue:)`.
52145219
bool isPropertyMemberwiseInitializedWithWrappedType() const;
52155220

52165221
/// Whether the innermost property wrapper's initializer's 'wrappedValue' parameter

lib/AST/Decl.cpp

Lines changed: 19 additions & 8 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,14 +1875,14 @@ 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 a wrappedValue
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.
1874-
if (!singleVar->allAttachedPropertyWrappersHaveInitialValueInit())
1885+
if (!singleVar->allAttachedPropertyWrappersHaveWrappedValueInit())
18751886
return false;
18761887
}
18771888
}
@@ -5817,7 +5828,7 @@ bool VarDecl::hasAttachedPropertyWrapper() const {
58175828

58185829
/// Whether all of the attached property wrappers have an init(wrappedValue:)
58195830
/// initializer.
5820-
bool VarDecl::allAttachedPropertyWrappersHaveInitialValueInit() const {
5831+
bool VarDecl::allAttachedPropertyWrappersHaveWrappedValueInit() const {
58215832
for (unsigned i : indices(getAttachedPropertyWrappers())) {
58225833
if (!getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit)
58235834
return false;
@@ -5922,7 +5933,7 @@ bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
59225933

59235934
// If all property wrappers have a wrappedValue initializer, the property
59245935
// wrapper will be initialized that way.
5925-
return allAttachedPropertyWrappersHaveInitialValueInit();
5936+
return allAttachedPropertyWrappersHaveWrappedValueInit();
59265937
}
59275938

59285939
bool VarDecl::isInnermostPropertyWrapperInitUsesEscapingAutoClosure() const {

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: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4182,18 +4182,27 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
41824182
if (Expr *initializer = expression.expression) {
41834183
// Form init(wrappedValue:) call(s).
41844184
Expr *wrappedInitializer =
4185-
buildPropertyWrapperInitialValueCall(
4185+
buildPropertyWrapperWrappedValueCall(
41864186
singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false);
41874187
if (!wrappedInitializer)
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

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ using namespace swift;
2828

2929
/// The kind of property initializer to look for
3030
enum class PropertyWrapperInitKind {
31-
/// An initial-value initializer (i.e. `init(initialValue:)`)
31+
/// An initial-value initializer (i.e. `init(initialValue:)`), which is
32+
/// deprecated.
3233
InitialValue,
3334
/// An wrapped-value initializer (i.e. `init(wrappedValue:)`)
3435
WrappedValue,
@@ -679,7 +680,7 @@ static bool isOpaquePlaceholderClosure(const Expr *value) {
679680
return false;
680681
}
681682

682-
Expr *swift::buildPropertyWrapperInitialValueCall(
683+
Expr *swift::buildPropertyWrapperWrappedValueCall(
683684
VarDecl *var, Type backingStorageType, Expr *value,
684685
bool ignoreAttributeArgs) {
685686
// From the innermost wrapper type out, form init(wrapperValue:) calls.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -199,23 +199,9 @@ PatternBindingEntryRequest::evaluate(Evaluator &eval,
199199
}
200200
}
201201

202-
// Check the pattern. We treat type-checking a PatternBindingDecl like
203-
// type-checking an expression because that's how the initial binding is
204-
// checked, and they have the same effect on the file's dependencies.
205-
//
206-
// In particular, it's /not/ correct to check the PBD's DeclContext because
207-
// top-level variables in a script file are accessible from other files,
208-
// even though the PBD is inside a TopLevelCodeDecl.
202+
// Check the pattern.
209203
auto contextualPattern =
210204
ContextualPattern::forPatternBindingDecl(binding, entryNumber);
211-
TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl);
212-
213-
if (binding->isInitialized(entryNumber)) {
214-
// If we have an initializer, we can also have unknown types.
215-
options |= TypeResolutionFlags::AllowUnspecifiedTypes;
216-
options |= TypeResolutionFlags::AllowUnboundGenerics;
217-
}
218-
219205
Type patternType = TypeChecker::typeCheckPattern(contextualPattern);
220206
if (patternType->hasError()) {
221207
swift::setBoundVarsTypeError(pattern, Context);
@@ -2477,7 +2463,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
24772463
}
24782464

24792465
// Get the property wrapper information.
2480-
if (!var->allAttachedPropertyWrappersHaveInitialValueInit() &&
2466+
if (!var->allAttachedPropertyWrappersHaveWrappedValueInit() &&
24812467
!originalInitialValue) {
24822468
return PropertyWrapperBackingPropertyInfo(
24832469
backingVar, storageVar, nullptr, nullptr, nullptr);
@@ -2491,7 +2477,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
24912477
OpaqueValueExpr *origValue =
24922478
new (ctx) OpaqueValueExpr(var->getSourceRange(), origValueType,
24932479
/*isPlaceholder=*/true);
2494-
Expr *initializer = buildPropertyWrapperInitialValueCall(
2480+
Expr *initializer = buildPropertyWrapperWrappedValueCall(
24952481
var, storageType, origValue,
24962482
/*ignoreAttributeArgs=*/!originalInitialValue);
24972483
typeCheckSynthesizedWrapperInitializer(

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,7 @@ Type computeWrappedValueType(VarDecl *var, Type backingStorageType,
14861486

14871487
/// Build a call to the init(wrappedValue:) initializers of the property
14881488
/// wrappers, filling in the given \c value as the original value.
1489-
Expr *buildPropertyWrapperInitialValueCall(VarDecl *var,
1489+
Expr *buildPropertyWrapperWrappedValueCall(VarDecl *var,
14901490
Type backingStorageType,
14911491
Expr *value,
14921492
bool ignoreAttributeArgs);

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)