Skip to content

Commit 4ba0173

Browse files
authored
Merge pull request #67769 from xedin/rdar-113421273
[TypeChecker] InitAccessors: Fix default initialization of init accessor properties
2 parents d5d11b6 + 416bbae commit 4ba0173

File tree

6 files changed

+146
-3
lines changed

6 files changed

+146
-3
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,12 @@ void LifetimeChecker::doIt() {
11821182
while (returnBB != F.end()) {
11831183
auto *terminator = returnBB->getTerminator();
11841184

1185+
// If this is an unreachable block, let's ignore it.
1186+
if (isa<UnreachableInst>(terminator)) {
1187+
++returnBB;
1188+
continue;
1189+
}
1190+
11851191
if (!isInitializedAtUse(DIMemoryUse(terminator, DIUseKind::Load, 0, 1)))
11861192
diagnoseMissingInit();
11871193

lib/Sema/CodeSynthesis.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,12 +877,19 @@ bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
877877
if (llvm::any_of(initAccessorProperties, [&](const auto &entry) {
878878
auto *property =
879879
entry.second->getParentPatternBinding();
880-
return property->isInitialized(0);
880+
return property->isInitialized(0) ||
881+
property->isDefaultInitializable();
881882
}))
882883
return;
883884

884885
if (VD->hasStorageOrWrapsStorage())
885886
HasStorage = true;
887+
888+
// Treat an init accessor property that doesn't initialize other
889+
// properties as stored for initialization purposes.
890+
if (auto *initAccessor = VD->getAccessor(AccessorKind::Init)) {
891+
HasStorage |= initAccessor->getInitializedProperties().empty();
892+
}
886893
});
887894

888895
if (!HasStorage) continue;

lib/Sema/TypeCheckStorage.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,16 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
491491
}
492492
}
493493

494+
auto isInitAccessorProperty = [](Pattern *pattern) {
495+
auto *var = pattern->getSingleVar();
496+
return var && var->getAccessor(AccessorKind::Init);
497+
};
498+
494499
// If we have a type but no initializer, check whether the type is
495500
// default-initializable. If so, do it.
496501
if (!pbe.isInitialized() &&
497502
binding->isDefaultInitializable(entryNumber) &&
498-
pattern->hasStorage()) {
503+
(pattern->hasStorage() || isInitAccessorProperty(pattern))) {
499504
if (auto defaultInit = TypeChecker::buildDefaultInitializer(patternType)) {
500505
// If we got a default initializer, install it and re-type-check it
501506
// to make sure it is properly coerced to the pattern type.

test/Interpreter/init_accessors.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,3 +801,49 @@ do {
801801
}
802802
// CHECK: Person(name: P)
803803
// CHECK-NEXT: Person(name: O)
804+
805+
do {
806+
struct TestDefaultInitializable : CustomStringConvertible {
807+
var description: String {
808+
"TestDefaultInitializable(a: \(a))"
809+
}
810+
811+
var _a: Int?
812+
var a: Int? {
813+
@storageRestrictions(initializes: _a)
814+
init { _a = newValue }
815+
get { _a }
816+
}
817+
}
818+
819+
print(TestDefaultInitializable())
820+
print(TestDefaultInitializable(a: 42))
821+
822+
struct TestMixedDefaultInitalizable : CustomStringConvertible {
823+
var description: String {
824+
"TestMixedDefaultInitalizable(a: \(a), b: \(b))"
825+
}
826+
827+
var a: Int? {
828+
init {}
829+
get { nil }
830+
}
831+
832+
var _b: String
833+
var b: String? {
834+
@storageRestrictions(initializes: _b)
835+
init { self._b = (newValue ?? "") }
836+
get { _b }
837+
set { _b = newValue ?? "" }
838+
}
839+
}
840+
841+
print(TestMixedDefaultInitalizable())
842+
print(TestMixedDefaultInitalizable(b: "Hello"))
843+
print(TestMixedDefaultInitalizable(a: 42))
844+
}
845+
// CHECK: TestDefaultInitializable(a: nil)
846+
// CHECK-NEXT: TestDefaultInitializable(a: Optional(42))
847+
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))
848+
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional("Hello"))
849+
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))

test/SILOptimizer/init_accessor_definite_init_diagnostics.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ class TestInitWithGuard {
189189
}
190190
}
191191

192+
do {
193+
struct TestPropertyInitWithUnreachableBlocks {
194+
var _a: Int
195+
var a: Int? {
196+
@storageRestrictions(initializes: _a)
197+
init { _a = newValue ?? 0 } // Ok
198+
get { 42 }
199+
}
200+
}
201+
}
202+
192203
do {
193204
class Base<T: Collection> {
194205
private var _v: T

test/decl/var/init_accessors.swift

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ extension TestStructPropWithoutSetter {
530530
}
531531

532532
do {
533-
class TestClassPropWithoutSetter {
533+
class TestClassPropWithoutSetter { // expected-error {{class 'TestClassPropWithoutSetter' has no initializers}}
534534
var x: Int {
535535
init {
536536
}
@@ -539,6 +539,44 @@ do {
539539
}
540540
}
541541

542+
// This should generate only memberwise initializer because `a` doesn't have a default
543+
struct TestStructWithoutSetter { // expected-note {{'init(a:)' declared here}}
544+
var a: Int {
545+
init {
546+
}
547+
get { 0 }
548+
}
549+
}
550+
551+
_ = TestStructWithoutSetter() // expected-error {{missing argument for parameter 'a' in call}}
552+
_ = TestStructWithoutSetter(a: 42) // Ok
553+
554+
struct TestDefaultInitializable {
555+
var a: Int? {
556+
init {}
557+
get { nil }
558+
}
559+
}
560+
561+
_ = TestDefaultInitializable() // Ok (`a` is initialized to `nil`)
562+
563+
struct TestMixedDefaultInitializable {
564+
var a: Int? {
565+
init {}
566+
get { nil }
567+
}
568+
569+
var _b: String
570+
var b: String? {
571+
@storageRestrictions(initializes: _b)
572+
init { _b = newValue ?? "" }
573+
get { _b }
574+
set { _b = newValue ?? "" }
575+
}
576+
}
577+
578+
_ = TestMixedDefaultInitializable() // Ok (both `a` and `b` are initialized to `nil`)
579+
542580
class SubTestPropWithoutSetter : TestClassPropWithoutSetter {
543581
init(otherV: Int) {
544582
x = otherV // Ok
@@ -620,3 +658,33 @@ func test_invalid_storage_restrictions() {
620658
init() {}
621659
}
622660
}
661+
662+
do {
663+
struct Test1 {
664+
var q: String
665+
var a: Int? {
666+
init {}
667+
get { 42 }
668+
}
669+
}
670+
671+
_ = Test1(q: "some question") // Ok `a` is default initialized to `nil`
672+
_ = Test1(q: "ultimate question", a: 42)
673+
674+
struct Test2 {
675+
var q: String
676+
677+
var _a: Int?
678+
var a: Int? {
679+
@storageRestrictions(initializes: _a)
680+
init {
681+
_a = newValue
682+
}
683+
get { _a }
684+
set { _a = newValue }
685+
}
686+
}
687+
688+
_ = Test2(q: "some question") // Ok `a` is default initialized to `nil`
689+
_ = Test2(q: "ultimate question", a: 42)
690+
}

0 commit comments

Comments
 (0)