Merge pull request #10193 from slavapestov/self-init-might-have-an-upcast

DI: Fix 'self.init' delegation to an imported factory initializer inherited from a base class
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
index 49ef519..59b2953 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
@@ -1166,6 +1166,28 @@
   return nullptr;
 }
 
+static bool isUninitializedMetatypeInst(SILInstruction *I) {
+  // A simple reference to "type(of:)" is always fine,
+  // even if self is uninitialized.
+  if (isa<ValueMetatypeInst>(I))
+    return true;
+
+  // Sometimes we get an upcast whose sole usage is a value_metatype_inst,
+  // for example when calling a convenience initializer from a superclass.
+  if (auto *UCI = dyn_cast<UpcastInst>(I)) {
+    for (auto *UI : UCI->getUses()) {
+      auto *User = UI->getUser();
+      if (isa<ValueMetatypeInst>(User))
+        continue;
+      return false;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 /// isSelfInitUse - Return true if this apply_inst is a call to self.init.
 static bool isSelfInitUse(SILInstruction *I) {
   // If we're reading a .sil file, treat a call to "selfinit" as a
@@ -1354,11 +1376,8 @@
       Kind = DIUseKind::SelfInit;
       UseInfo.trackFailableInitCall(TheMemory, User);
     }
-
-    // If this is a ValueMetatypeInst, this is a simple reference
-    // to "type(of:)", which is always fine, even if self is
-    // uninitialized.
-    if (isa<ValueMetatypeInst>(User))
+    
+    if (isUninitializedMetatypeInst(User))
       continue;
 
     // If this is a partial application of self, then this is an escape point
@@ -1630,11 +1649,8 @@
       }
     }
 
-    // A simple reference to "type(of:)" is always fine,
-    // even if self is uninitialized.
-    if (isa<ValueMetatypeInst>(User)) {
+    if (isUninitializedMetatypeInst(User))
       continue;
-    }
 
     UseInfo.trackUse(DIMemoryUse(User, Kind, 0, 1));
   }
diff --git a/test/SILOptimizer/definite_init_objc_factory_init.swift b/test/SILOptimizer/definite_init_objc_factory_init.swift
index 30e6524c..855a990 100644
--- a/test/SILOptimizer/definite_init_objc_factory_init.swift
+++ b/test/SILOptimizer/definite_init_objc_factory_init.swift
@@ -52,3 +52,20 @@
     self.init(value: double)
   }
 }
+
+class SubHive : Hive {
+  // CHECK-LABEL: sil hidden @_T0027definite_init_objc_factory_B07SubHiveCACyt20delegatesToInherited_tcfc : $@convention(method) (@owned SubHive) -> @owned SubHive
+  convenience init(delegatesToInherited: ()) {
+    // CHECK: [[UPCAST:%.*]] = upcast %0 : $SubHive to $Hive
+    // CHECK: [[METATYPE:%.*]] = value_metatype $@thick Hive.Type, [[UPCAST]] : $Hive
+    // CHECK: [[METHOD:%.*]] = class_method [volatile] [[METATYPE]] : $@thick Hive.Type, #Hive.init!allocator.1.foreign : (Hive.Type) -> (Bee!) -> Hive!
+    // CHECK: [[OBJC:%.*]] = thick_to_objc_metatype [[METATYPE]] : $@thick Hive.Type to $@objc_metatype Hive.Type
+    // CHECK: apply [[METHOD]]({{.*}}, [[OBJC]])
+
+    // CHECK: [[METATYPE:%.*]] = value_metatype $@thick SubHive.Type, %0 : $SubHive
+    // CHECK-NEXT: dealloc_partial_ref %0 : $SubHive, [[METATYPE]] : $@thick SubHive.Type
+
+    // CHECK: return {{%.*}} : $SubHive
+    self.init(queen: Bee())
+  }
+}