Merge pull request #8180 from gottesmm/small_result_plan_refactor

[silgen] Move foreignErrorPreparation code in ResultPlanBuilder into a new buildTopLevelResult method.
diff --git a/lib/SILGen/FormalEvaluation.cpp b/lib/SILGen/FormalEvaluation.cpp
index 8e0922c..b14d0df 100644
--- a/lib/SILGen/FormalEvaluation.cpp
+++ b/lib/SILGen/FormalEvaluation.cpp
@@ -50,8 +50,9 @@
 
 FormalEvaluationScope::FormalEvaluationScope(SILGenFunction &SGF)
     : SGF(SGF), savedDepth(SGF.FormalEvalContext.stable_begin()),
-      wasInWritebackScope(SGF.InWritebackScope) {
-  if (SGF.InInOutConversionScope) {
+      wasInWritebackScope(SGF.InWritebackScope),
+      wasInInOutConversionScope(SGF.InInOutConversionScope) {
+  if (wasInInOutConversionScope) {
     savedDepth.reset();
     return;
   }
@@ -60,7 +61,8 @@
 
 FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o)
     : SGF(o.SGF), savedDepth(o.savedDepth),
-      wasInWritebackScope(o.wasInWritebackScope) {
+      wasInWritebackScope(o.wasInWritebackScope),
+      wasInInOutConversionScope(o.wasInInOutConversionScope) {
   o.savedDepth.reset();
 }
 
diff --git a/lib/SILGen/FormalEvaluation.h b/lib/SILGen/FormalEvaluation.h
index 929bbd9..66a0a51 100644
--- a/lib/SILGen/FormalEvaluation.h
+++ b/lib/SILGen/FormalEvaluation.h
@@ -175,6 +175,7 @@
   SILGenFunction &SGF;
   llvm::Optional<FormalEvaluationContext::stable_iterator> savedDepth;
   bool wasInWritebackScope;
+  bool wasInInOutConversionScope;
 
 public:
   FormalEvaluationScope(SILGenFunction &SGF);
@@ -187,6 +188,9 @@
   bool isPopped() const { return !savedDepth.hasValue(); }
 
   void pop() {
+    if (wasInInOutConversionScope)
+      return;
+
     assert(!isPopped() && "popping an already-popped writeback scope!");
     popImpl();
     savedDepth.reset();
diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp
index a11442d..d47355c 100644
--- a/lib/SILGen/ResultPlan.cpp
+++ b/lib/SILGen/ResultPlan.cpp
@@ -290,6 +290,50 @@
 /// Build a result plan for the results of an apply.
 ///
 /// If the initialization is non-null, the result plan will emit into it.
+ResultPlanPtr ResultPlanBuilder::buildTopLevelResult(Initialization *init) {
+  // First check if we do not have a foreign error. If we don't, just call
+  // build.
+  auto foreignError = calleeTypeInfo.foreignError;
+  if (!foreignError) {
+    return build(init, calleeTypeInfo.origResultType,
+                 calleeTypeInfo.substResultType);
+  }
+
+  // Otherwise, handle the foreign error first.
+  //
+  // The plan needs to be built using the formal result type after foreign-error
+  // adjustment.
+  switch (foreignError->getKind()) {
+  // These conventions make the formal result type ().
+  case ForeignErrorConvention::ZeroResult:
+  case ForeignErrorConvention::NonZeroResult:
+    assert(calleeTypeInfo.substResultType->isVoid());
+    allResults = {};
+    break;
+
+  // These conventions leave the formal result alone.
+  case ForeignErrorConvention::ZeroPreservedResult:
+  case ForeignErrorConvention::NonNilError:
+    break;
+
+  // This convention changes the formal result to the optional object type; we
+  // need to make our own make SILResultInfo array.
+  case ForeignErrorConvention::NilResult: {
+    assert(allResults.size() == 1);
+    CanType objectType = allResults[0].getType().getAnyOptionalObjectType();
+    SILResultInfo optResult = allResults[0].getWithType(objectType);
+    allResults = optResult;
+    break;
+  }
+  }
+
+  return build(init, calleeTypeInfo.origResultType,
+               calleeTypeInfo.substResultType);
+}
+
+/// Build a result plan for the results of an apply.
+///
+/// If the initialization is non-null, the result plan will emit into it.
 ResultPlanPtr ResultPlanBuilder::build(Initialization *init,
                                        AbstractionPattern origType,
                                        CanType substType) {
@@ -310,7 +354,7 @@
     // there are no abstraction differences, then just do it.
     if (initAddr && SGF.silConv.isSILIndirect(result) &&
         !initAddr->getType().hasAbstractionDifference(
-            rep, result.getSILStorageType())) {
+            calleeTypeInfo.getOverrideRep(), result.getSILStorageType())) {
       return ResultPlanPtr(new InPlaceInitializationResultPlan(init));
     }
   }
@@ -329,8 +373,8 @@
     temporary = SGF.emitTemporary(loc, resultTL);
   }
 
-  return ResultPlanPtr(
-      new ScalarResultPlan(std::move(temporary), origType, init, rep));
+  return ResultPlanPtr(new ScalarResultPlan(
+      std::move(temporary), origType, init, calleeTypeInfo.getOverrideRep()));
 }
 
 ResultPlanPtr ResultPlanBuilder::buildForTuple(Initialization *init,
@@ -380,41 +424,6 @@
 ResultPlanBuilder::computeResultPlan(SILGenFunction &SGF,
                                      CalleeTypeInfo &calleeTypeInfo,
                                      SILLocation loc, SGFContext evalContext) {
-  auto origResultTypeForPlan = calleeTypeInfo.origResultType;
-  auto substResultTypeForPlan = calleeTypeInfo.substResultType;
-  ArrayRef<SILResultInfo> allResults = calleeTypeInfo.substFnType->getResults();
-  SILResultInfo optResult;
-
-  // The plan needs to be built using the formal result type
-  // after foreign-error adjustment.
-  if (auto foreignError = calleeTypeInfo.foreignError) {
-    switch (foreignError->getKind()) {
-    // These conventions make the formal result type ().
-    case ForeignErrorConvention::ZeroResult:
-    case ForeignErrorConvention::NonZeroResult:
-      assert(calleeTypeInfo.substResultType->isVoid());
-      allResults = {};
-      break;
-
-    // These conventions leave the formal result alone.
-    case ForeignErrorConvention::ZeroPreservedResult:
-    case ForeignErrorConvention::NonNilError:
-      break;
-
-    // This convention changes the formal result to the optional object
-    // type; we need to make our own make SILResultInfo array.
-    case ForeignErrorConvention::NilResult: {
-      assert(allResults.size() == 1);
-      CanType objectType = allResults[0].getType().getAnyOptionalObjectType();
-      optResult = allResults[0].getWithType(objectType);
-      allResults = optResult;
-      break;
-    }
-    }
-  }
-
-  ResultPlanBuilder builder(SGF, loc, allResults,
-                            calleeTypeInfo.getOverrideRep());
-  return builder.build(evalContext.getEmitInto(), origResultTypeForPlan,
-                       substResultTypeForPlan);
+  ResultPlanBuilder builder(SGF, loc, calleeTypeInfo);
+  return builder.buildTopLevelResult(evalContext.getEmitInto());
 }
diff --git a/lib/SILGen/ResultPlan.h b/lib/SILGen/ResultPlan.h
index 288a7ca..256830b 100644
--- a/lib/SILGen/ResultPlan.h
+++ b/lib/SILGen/ResultPlan.h
@@ -13,6 +13,7 @@
 #ifndef SWIFT_SILGEN_RESULTPLAN_H
 #define SWIFT_SILGEN_RESULTPLAN_H
 
+#include "Callee.h"
 #include "swift/AST/Types.h"
 #include "swift/Basic/LLVM.h"
 #include "swift/SIL/SILLocation.h"
@@ -50,13 +51,13 @@
 struct ResultPlanBuilder {
   SILGenFunction &SGF;
   SILLocation loc;
+  CalleeTypeInfo &calleeTypeInfo;
   ArrayRef<SILResultInfo> allResults;
-  SILFunctionTypeRepresentation rep;
 
   ResultPlanBuilder(SILGenFunction &SGF, SILLocation loc,
-                    ArrayRef<SILResultInfo> allResults,
-                    SILFunctionTypeRepresentation rep)
-      : SGF(SGF), loc(loc), allResults(allResults), rep(rep) {}
+                    CalleeTypeInfo &calleeTypeInfo)
+      : SGF(SGF), loc(loc), calleeTypeInfo(calleeTypeInfo),
+        allResults(calleeTypeInfo.substFnType->getResults()) {}
 
   ResultPlanPtr build(Initialization *emitInto, AbstractionPattern origType,
                       CanType substType);
@@ -72,6 +73,9 @@
   ~ResultPlanBuilder() {
     assert(allResults.empty() && "didn't consume all results!");
   }
+
+private:
+  ResultPlanPtr buildTopLevelResult(Initialization *init);
 };
 
 } // end namespace Lowering