Skip to content

Commit 8d5b9c8

Browse files
committed
Check default init before synthesizing wrapper backing properties.
Fixes a regression where the compiler would reject something like: @State var x: Int? as not having an initializer, even though an Int? property ought to default to nil. rdar://problem/53504653
1 parent 8faa962 commit 8d5b9c8

File tree

6 files changed

+33
-9
lines changed

6 files changed

+33
-9
lines changed

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5809,7 +5809,8 @@ Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
58095809
return nullptr;
58105810

58115811
// If there is no '=' on the pattern, there was no initial value.
5812-
if (PBD->getPatternList()[0].getEqualLoc().isInvalid())
5812+
if (PBD->getPatternList()[0].getEqualLoc().isInvalid()
5813+
&& !PBD->isDefaultInitializable())
58135814
return nullptr;
58145815

58155816
ASTContext &ctx = var->getASTContext();

lib/Sema/CodeSynthesis.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,18 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
17861786
// Take the initializer from the original property.
17871787
auto parentPBD = var->getParentPatternBinding();
17881788
unsigned patternNumber = parentPBD->getPatternEntryIndexForVarDecl(var);
1789+
1790+
// Force the default initializer to come into existence, if there is one,
1791+
// and the wrapper doesn't provide its own.
1792+
if (!parentPBD->isInitialized(patternNumber)
1793+
&& parentPBD->isDefaultInitializable(patternNumber)
1794+
&& !wrapperInfo.defaultInit) {
1795+
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
1796+
auto ty = parentPBD->getPattern(patternNumber)->getType();
1797+
if (auto defaultInit = tc.buildDefaultInitializer(ty))
1798+
parentPBD->setInit(patternNumber, defaultInit);
1799+
}
1800+
17891801
if (parentPBD->isInitialized(patternNumber) &&
17901802
!parentPBD->isInitializerChecked(patternNumber)) {
17911803
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,10 @@ TypeChecker::handleSILGenericParams(GenericParamList *genericParams,
636636
}
637637

638638
/// Build a default initializer for the given type.
639-
static Expr *buildDefaultInitializer(TypeChecker &tc, Type type) {
639+
Expr *TypeChecker::buildDefaultInitializer(Type type) {
640640
// Default-initialize optional types and weak values to 'nil'.
641641
if (type->getReferenceStorageReferent()->getOptionalObjectType())
642-
return new (tc.Context) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);
642+
return new (Context) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);
643643

644644
// Build tuple literals for tuple types.
645645
if (auto tupleType = type->getAs<TupleType>()) {
@@ -648,14 +648,14 @@ static Expr *buildDefaultInitializer(TypeChecker &tc, Type type) {
648648
if (elt.isVararg())
649649
return nullptr;
650650

651-
auto eltInit = buildDefaultInitializer(tc, elt.getType());
651+
auto eltInit = buildDefaultInitializer(elt.getType());
652652
if (!eltInit)
653653
return nullptr;
654654

655655
inits.push_back(eltInit);
656656
}
657657

658-
return TupleExpr::createImplicit(tc.Context, inits, { });
658+
return TupleExpr::createImplicit(Context, inits, { });
659659
}
660660

661661
// We don't default-initialize anything else.
@@ -2297,7 +2297,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22972297
}
22982298

22992299
auto type = PBD->getPattern(i)->getType();
2300-
if (auto defaultInit = buildDefaultInitializer(TC, type)) {
2300+
if (auto defaultInit = TC.buildDefaultInitializer(type)) {
23012301
// If we got a default initializer, install it and re-type-check it
23022302
// to make sure it is properly coerced to the pattern type.
23032303
PBD->setInit(i, defaultInit);

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -672,10 +672,14 @@ Expr *swift::buildPropertyWrapperInitialValueCall(
672672
= var->getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit) {
673673
argName = init->getFullName().getArgumentNames()[0];
674674
}
675+
676+
auto endLoc = initializer->getEndLoc();
677+
if (endLoc.isInvalid() && startLoc.isValid())
678+
endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End;
675679

676680
initializer = CallExpr::create(
677681
ctx, typeExpr, startLoc, {initializer}, {argName},
678-
{initializer->getStartLoc()}, initializer->getEndLoc(),
682+
{initializer->getStartLoc()}, endLoc,
679683
nullptr, /*implicit=*/true);
680684
continue;
681685
}
@@ -700,10 +704,14 @@ Expr *swift::buildPropertyWrapperInitialValueCall(
700704
elementNames.push_back(Identifier());
701705
elementLocs.push_back(SourceLoc());
702706
}
707+
708+
auto endLoc = attr->getArg()->getEndLoc();
709+
if (endLoc.isInvalid() && startLoc.isValid())
710+
endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End;
703711

704712
initializer = CallExpr::create(
705713
ctx, typeExpr, startLoc, elements, elementNames, elementLocs,
706-
attr->getArg()->getEndLoc(), nullptr, /*implicit=*/true);
714+
endLoc, nullptr, /*implicit=*/true);
707715
}
708716

709717
return initializer;

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,8 @@ class TypeChecker final : public LazyResolver {
19241924
FragileFunctionKind Kind,
19251925
bool TreatUsableFromInlineAsPublic);
19261926

1927+
Expr *buildDefaultInitializer(Type type);
1928+
19271929
private:
19281930
bool diagnoseInlinableDeclRefAccess(SourceLoc loc, const ValueDecl *D,
19291931
const DeclContext *DC,

test/SILOptimizer/di_property_wrappers.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ func testOptIntStruct() {
360360
print("\n## OptIntStruct")
361361

362362
let use = OptIntStruct()
363-
// CHECK-NEXT: .. init Optional(42)
363+
// CHECK-NEXT: .. init nil
364+
// CHECK-NEXT: .. set Optional(42)
364365
}
365366

366367
testIntStruct()

0 commit comments

Comments
 (0)