Merge pull request #12770 from slavapestov/infinite-fractal-of-corner-cases-4.1

Sema: Fix source compatibility break with default initialization of optional properties [4.1]
diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h
index b6b7171..96f2d3e 100644
--- a/include/swift/AST/Pattern.h
+++ b/include/swift/AST/Pattern.h
@@ -170,8 +170,9 @@
 
   /// Return true if this pattern (or a subpattern) is refutable.
   bool isRefutablePattern() const;
-  
-  
+
+  bool isNeverDefaultInitializable() const;
+
   /// \brief Mark all vardecls in this pattern as having non-pattern initial
   /// values bound into them.
   void markHasNonPatternBindingInit() {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index c019755..dc399d8 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1187,10 +1187,10 @@
 
 // @NSManaged properties never get default initialized, nor do debugger
 // variables and immutable properties.
-bool isNeverDefaultInitializable(const Pattern *p) {
+bool Pattern::isNeverDefaultInitializable() const {
   bool result = false;
 
-  p->forEachVariable([&](const VarDecl *var) {
+  forEachVariable([&](const VarDecl *var) {
     if (var->getAttrs().hasAttribute<NSManagedAttr>())
       return;
 
@@ -1209,7 +1209,7 @@
   if (entry.getInit())
     return true;
 
-  if (isNeverDefaultInitializable(entry.getPattern()))
+  if (entry.getPattern()->isNeverDefaultInitializable())
     return false;
 
   // If the pattern is typed as optional (or tuples thereof), it is
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index d28c754..619a000 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -4133,8 +4133,25 @@
             TC.checkTypeModifyingDeclAttributes(var);
 
           // Decide whether we should suppress default initialization.
-          if (!PBD->isDefaultInitializable(i))
-            continue;
+          //
+          // Note: Swift 4 had a bug where properties with a desugared optional
+          // type like Optional<Int> had a half-way behavior where sometimes
+          // they behave like they are default initialized, and sometimes not.
+          //
+          // In Swift 5 mode, use the right condition here, and only default
+          // initialize properties with a sugared Optional type.
+          //
+          // (The restriction to sugared types only comes because we don't have
+          // the iterative declaration checker yet; so in general, we cannot
+          // look at the type of a property at all, and can only look at the
+          // TypeRepr, because we haven't validated the property yet.)
+          if (TC.Context.isSwiftVersionAtLeast(5)) {
+            if (!PBD->isDefaultInitializable(i))
+              continue;
+          } else {
+            if (PBD->getPattern(i)->isNeverDefaultInitializable())
+              continue;
+          }
 
           auto type = PBD->getPattern(i)->getType();
           if (auto defaultInit = buildDefaultInitializer(TC, type)) {
diff --git a/test/Compatibility/default_init.swift b/test/Compatibility/default_init.swift
new file mode 100644
index 0000000..e6eebc4
--- /dev/null
+++ b/test/Compatibility/default_init.swift
@@ -0,0 +1,16 @@
+// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify -swift-version 4
+
+// Default initialization of variables -- totally broken Swift 4 behavior.
+
+class NotInitializableOptionalClass {
+  var opt: Optional<Int>
+}
+
+struct NotInitializableOptionalStruct { // expected-note {{'init(opt:)' declared here}}
+  var opt: Optional<Int>
+}
+
+func testBadDefaultInit() {
+  _ = NotInitializableOptionalStruct() // expected-error {{missing argument for parameter 'opt' in call}}
+  _ = NotInitializableOptionalClass()
+}
diff --git a/test/decl/var/default_init.swift b/test/decl/var/default_init.swift
index 0f28437..d21ee17 100644
--- a/test/decl/var/default_init.swift
+++ b/test/decl/var/default_init.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify
+// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify -swift-version 5
 
 // Default initialization of variables.
 
@@ -38,3 +38,16 @@
 
 var global: Int?
 
+class NotInitializableOptionalClass { // expected-error{{class 'NotInitializableOptionalClass' has no initializers}}
+  // Do not perform default initialization for properties with explicitly-spelled 'Optional'.
+  var opt: Optional<Int> // expected-note{{stored property 'opt' without initial value prevents synthesized initializers}}
+}
+
+struct NotInitializableOptionalStruct { // expected-note {{'init(opt:)' declared here}}
+  var opt: Optional<Int>
+}
+
+func testBadDefaultInit() {
+  _ = NotInitializableOptionalStruct() // expected-error {{missing argument for parameter 'opt' in call}}
+  _ = NotInitializableOptionalClass() // expected-error {{'NotInitializableOptionalClass' cannot be constructed because it has no accessible initializers}}
+}