Merge pull request #19038 from jckarter/mutating-opened-existential-covariant-return-4.2
[4.2] Fix order of operations when a mutating method invoked on an existential returns Self.
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index c4ba230..fb21df8 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -492,6 +492,9 @@
/// Returns the underlying referent SILType of an @sil_unowned or @sil_weak
/// Type.
SILType getReferentType(SILModule &M) const;
+
+ /// Returns a SILType with any archetypes mapped out of context.
+ SILType mapTypeOutOfContext() const;
/// Given two SIL types which are representations of the same type,
/// check whether they have an abstraction difference.
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 7e5861d..6655705 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -1558,10 +1558,7 @@
// Allocate a new object using the layout.
auto boxedInterfaceType = boxedType;
if (env) {
- boxedInterfaceType = SILType::getPrimitiveType(
- boxedType.getSwiftRValueType()->mapTypeOutOfContext()
- ->getCanonicalType(),
- boxedType.getCategory());
+ boxedInterfaceType = boxedType.mapTypeOutOfContext();
}
auto boxDescriptor = IGF.IGM.getAddrOfBoxDescriptor(
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index a219de5..5b2bc9f 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -390,6 +390,12 @@
return M.Types.getLoweredType(Ty->getReferentType()->getCanonicalType());
}
+SILType SILType::mapTypeOutOfContext() const {
+ return SILType::getPrimitiveType(getSwiftRValueType()->mapTypeOutOfContext()
+ ->getCanonicalType(),
+ getCategory());
+}
+
CanType
SILBoxType::getFieldLoweredType(SILModule &M, unsigned index) const {
auto fieldTy = getLayout()->getFields()[index].getLoweredType();
diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h
index 28dc213..2b9ccad 100644
--- a/lib/SILGen/Cleanup.h
+++ b/lib/SILGen/Cleanup.h
@@ -142,6 +142,10 @@
assert(!stack.empty());
return stack.stable_begin();
}
+
+ Cleanup &getCleanup(CleanupHandle iter) {
+ return *stack.find(iter);
+ }
/// \brief Emit a branch to the given jump destination,
/// threading out through any cleanups we need to run. This does not pop the
diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp
index 861cb9c..70bae80 100644
--- a/lib/SILGen/ResultPlan.cpp
+++ b/lib/SILGen/ResultPlan.cpp
@@ -17,6 +17,7 @@
#include "LValue.h"
#include "RValue.h"
#include "SILGenFunction.h"
+#include "swift/AST/GenericEnvironment.h"
using namespace swift;
using namespace Lowering;
@@ -29,7 +30,7 @@
/// A result plan for evaluating an indirect result into the address
/// associated with an initialization.
-class InPlaceInitializationResultPlan : public ResultPlan {
+class InPlaceInitializationResultPlan final : public ResultPlan {
Initialization *init;
public:
@@ -47,10 +48,150 @@
}
};
+/// A cleanup that handles the delayed emission of an indirect buffer for opened
+/// Self arguments.
+class IndirectOpenedSelfCleanup final : public Cleanup {
+ SILValue box;
+public:
+ IndirectOpenedSelfCleanup()
+ : box()
+ {}
+
+ void setBox(SILValue b) {
+ assert(!box && "buffer already set?!");
+ box = b;
+ }
+
+ void emit(SILGenFunction &SGF, CleanupLocation loc) override {
+ assert(box && "buffer never emitted before activating cleanup?!");
+ SGF.B.createDeallocBox(loc, box);
+ }
+
+ void dump(SILGenFunction &SGF) const override {
+ llvm::errs() << "IndirectOpenedSelfCleanup\n";
+ if (box)
+ box->dump();
+ }
+};
+
+/// Map a type expressed in terms of opened archetypes into a context-free
+/// dependent type, returning the type, a generic signature with parameters
+/// corresponding to each opened type,
+static std::pair<CanType, CanGenericSignature>
+mapTypeOutOfOpenedExistentialContext(CanType t,
+ SmallVectorImpl<Substitution> &mappedSubs) {
+ SmallVector<ArchetypeType *, 4> openedTypes;
+ t->getOpenedExistentials(openedTypes);
+
+ SmallVector<GenericTypeParamType *, 4> params;
+ for (unsigned i : indices(openedTypes)) {
+ params.push_back(GenericTypeParamType::get(0, i, t->getASTContext()));
+ mappedSubs.push_back(Substitution(openedTypes[i], {}));
+ }
+
+ auto mappedSig = GenericSignature::get(params, {});
+
+ auto mappedTy = t.subst(
+ [&](SubstitutableType *t) -> Type {
+ auto index = std::find(openedTypes.begin(), openedTypes.end(), t)
+ - openedTypes.begin();
+ assert(index != openedTypes.end() - openedTypes.begin());
+ return params[index];
+ },
+ MakeAbstractConformanceForGenericType());
+
+ return std::make_pair(mappedTy->getCanonicalType(mappedSig),
+ mappedSig->getCanonicalSignature());
+}
+
+/// A result plan for an indirectly-returned opened existential value.
+///
+/// This defers allocating the temporary for the result to a later point so that
+/// it happens after the arguments are evaluated.
+class IndirectOpenedSelfResultPlan final : public ResultPlan {
+ AbstractionPattern origType;
+ CanType substType;
+ CleanupHandle handle = CleanupHandle::invalid();
+ mutable SILValue resultBox, resultBuf;
+
+public:
+ IndirectOpenedSelfResultPlan(SILGenFunction &SGF,
+ AbstractionPattern origType,
+ CanType substType)
+ : origType(origType), substType(substType)
+ {
+ // Create a cleanup to deallocate the stack buffer at the proper scope.
+ // We won't emit the buffer till later, after arguments have been opened,
+ // though.
+ SGF.Cleanups.pushCleanupInState<IndirectOpenedSelfCleanup>(
+ CleanupState::Dormant);
+ handle = SGF.Cleanups.getCleanupsDepth();
+ }
+
+ void
+ gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+ SmallVectorImpl<SILValue> &outList) const override {
+ assert(!resultBox && "already created temporary?!");
+
+ // We allocate the buffer as a box because the scope nesting won't clean
+ // this up with good stack discipline relative to any stack allocations that
+ // occur during argument emission. Escape analysis during mandatory passes
+ // ought to clean this up.
+
+ auto resultTy = SGF.getLoweredType(origType, substType).getSwiftRValueType();
+ CanType layoutTy;
+ CanGenericSignature layoutSig;
+ SmallVector<Substitution, 4> layoutSubs;
+ std::tie(layoutTy, layoutSig)
+ = mapTypeOutOfOpenedExistentialContext(resultTy, layoutSubs);
+
+ auto boxLayout = SILLayout::get(SGF.getASTContext(),
+ layoutSig->getCanonicalSignature(),
+ SILField(layoutTy->getCanonicalType(layoutSig), true));
+
+ resultBox = SGF.B.createAllocBox(loc,
+ SILBoxType::get(SGF.getASTContext(),
+ boxLayout,
+ layoutSubs));
+
+ // Complete the cleanup to deallocate this buffer later, after we're
+ // finished with the argument.
+ static_cast<IndirectOpenedSelfCleanup&>(SGF.Cleanups.getCleanup(handle))
+ .setBox(resultBox);
+ SGF.Cleanups.setCleanupState(handle, CleanupState::Active);
+
+ resultBuf = SGF.B.createProjectBox(loc, resultBox, 0);
+ outList.emplace_back(resultBuf);
+ }
+
+ RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
+ ArrayRef<ManagedValue> &directResults) override {
+ assert(resultBox && "never emitted temporary?!");
+
+ // Lower the unabstracted result type.
+ auto &substTL = SGF.getTypeLowering(substType);
+
+ ManagedValue value;
+ // If the value isn't address-only, go ahead and load.
+ if (!substTL.isAddressOnly()) {
+ auto load = substTL.emitLoad(SGF.B, loc, resultBuf,
+ LoadOwnershipQualifier::Take);
+ value = SGF.emitManagedRValueWithCleanup(load);
+ } else {
+ value = SGF.emitManagedRValueWithCleanup(resultBuf);
+ }
+
+ // A Self return should never be further abstracted. It's also never emitted
+ // into context; we disable that optimization because Self may not even
+ // be available to pre-allocate a stack buffer before we prepare a call.
+ return RValue(SGF, loc, substType, value);
+ }
+};
+
/// A result plan for working with a single value and potentially
/// reabstracting it. The value can actually be a tuple if the
/// abstraction is opaque.
-class ScalarResultPlan : public ResultPlan {
+class ScalarResultPlan final : public ResultPlan {
std::unique_ptr<TemporaryInitialization> temporary;
AbstractionPattern origType;
Initialization *init;
@@ -150,7 +291,7 @@
/// A result plan which calls copyOrInitValueInto on an Initialization
/// using a temporary buffer initialized by a sub-plan.
-class InitValueFromTemporaryResultPlan : public ResultPlan {
+class InitValueFromTemporaryResultPlan final : public ResultPlan {
Initialization *init;
ResultPlanPtr subPlan;
std::unique_ptr<TemporaryInitialization> temporary;
@@ -184,7 +325,7 @@
/// A result plan which calls copyOrInitValueInto using the result of
/// a sub-plan.
-class InitValueFromRValueResultPlan : public ResultPlan {
+class InitValueFromRValueResultPlan final : public ResultPlan {
Initialization *init;
ResultPlanPtr subPlan;
@@ -212,7 +353,7 @@
/// A result plan which produces a larger RValue from a bunch of
/// components.
-class TupleRValueResultPlan : public ResultPlan {
+class TupleRValueResultPlan final : public ResultPlan {
SmallVector<ResultPlanPtr, 4> eltPlans;
public:
@@ -254,7 +395,7 @@
/// A result plan which evaluates into the sub-components
/// of a splittable tuple initialization.
-class TupleInitializationResultPlan : public ResultPlan {
+class TupleInitializationResultPlan final : public ResultPlan {
Initialization *tupleInit;
SmallVector<InitializationPtr, 4> eltInitsBuffer;
MutableArrayRef<InitializationPtr> eltInits;
@@ -305,7 +446,7 @@
}
};
-class ForeignErrorInitializationPlan : public ResultPlan {
+class ForeignErrorInitializationPlan final : public ResultPlan {
SILLocation loc;
LValue lvalue;
ResultPlanPtr subPlan;
@@ -466,6 +607,16 @@
// - store it to the destination
// We could break this down into different ResultPlan implementations,
// but it's easier not to.
+
+ // If the result type involves an indirectly-returned opened existential,
+ // then we need to evaluate the arguments first in order to have access to
+ // the opened Self type. A special result plan defers allocating the stack
+ // slot to the point the call is emitted.
+ if (result.getType()->hasOpenedExistential()
+ && SGF.silConv.isSILIndirect(result)) {
+ return ResultPlanPtr(
+ new IndirectOpenedSelfResultPlan(SGF, origType, substType));
+ }
// Create a temporary if the result is indirect.
std::unique_ptr<TemporaryInitialization> temporary;
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 82f55a4..ab7b248 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -4409,7 +4409,7 @@
auto directResultsArray = makeArrayRef(directResults);
RValue result =
- resultPlan->finish(*this, loc, substResultType, directResultsArray);
+ resultPlan->finish(*this, loc, substResultType, directResultsArray);
assert(directResultsArray.empty() && "didn't claim all direct results");
return result;
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 6c7d43e..205c83a 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -505,28 +505,94 @@
namespace {
/// This is an initialization for an address-only existential in memory.
-class ExistentialInitialization : public KnownAddressInitialization {
- CleanupHandle Cleanup;
+class ExistentialInitialization final : public SingleBufferInitialization {
+ SILValue existential;
+ CanType concreteFormalType;
+ ArrayRef<ProtocolConformanceRef> conformances;
+ ExistentialRepresentation repr;
+
+ // Initialized lazily when the address for initialization is demanded.
+ SILValue concreteBuffer;
+ CleanupHandle deinitExistentialCleanup;
public:
/// \param existential The existential container
- /// \param address Address of value in existential container
/// \param concreteFormalType Unlowered AST type of value
- /// \param repr Representation of container
- ExistentialInitialization(SILValue existential, SILValue address,
+ /// \param conformances Conformances for concrete type to existential's
+ /// protocols
+ ExistentialInitialization(SILGenFunction &SGF,
+ SILValue existential,
CanType concreteFormalType,
- ExistentialRepresentation repr,
- SILGenFunction &SGF)
- : KnownAddressInitialization(address) {
- // Any early exit before we store a value into the existential must
- // clean up the existential container.
- Cleanup = SGF.enterDeinitExistentialCleanup(existential,
- concreteFormalType,
- repr);
+ ArrayRef<ProtocolConformanceRef> conformances,
+ ExistentialRepresentation repr)
+ : existential(existential),
+ concreteFormalType(concreteFormalType),
+ conformances(conformances),
+ repr(repr)
+ {
+ assert(existential->getType().isAddress());
+
+ // Create a cleanup to deallocate an allocated but uninitialized concrete
+ // type buffer.
+ // It won't be activated until that buffer is formed later, though.
+ deinitExistentialCleanup =
+ SGF.enterDeinitExistentialCleanup(CleanupState::Dormant,
+ existential, concreteFormalType, repr);
+
+ }
+
+ SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+ SILLocation loc) override {
+ // Create the buffer when needed, because in some cases the type may
+ // be the opened type from another existential that hasn't been opened
+ // at the point the existential destination was formed.
+ assert(!concreteBuffer && "concrete buffer already formed?!");
+
+ auto concreteLoweredType =
+ SGF.getLoweredType(AbstractionPattern::getOpaque(), concreteFormalType);
+
+ switch (repr) {
+ case ExistentialRepresentation::Opaque: {
+ concreteBuffer = SGF.B.createInitExistentialAddr(loc, existential,
+ concreteFormalType,
+ concreteLoweredType.getAddressType(),
+ conformances);
+ break;
+ }
+ case ExistentialRepresentation::Boxed: {
+ auto box = SGF.B.createAllocExistentialBox(loc,
+ existential->getType().getObjectType(),
+ concreteFormalType,
+ conformances);
+ concreteBuffer = SGF.B.createProjectExistentialBox(loc,
+ concreteLoweredType.getAddressType(),
+ box);
+ SGF.B.createStore(loc, box, existential,
+ StoreOwnershipQualifier::Init);
+ break;
+ }
+ case ExistentialRepresentation::Class:
+ case ExistentialRepresentation::Metatype:
+ case ExistentialRepresentation::None:
+ llvm_unreachable("not supported");
+ }
+
+ // Activate the cleanup to deallocate the buffer we just allocated, should
+ SGF.Cleanups.setCleanupState(deinitExistentialCleanup,
+ CleanupState::Active);
+
+ return concreteBuffer;
+ }
+
+ bool isInPlaceInitializationOfGlobal() const override {
+ return existential && isa<GlobalAddrInst>(existential);
}
void finishInitialization(SILGenFunction &SGF) override {
SingleBufferInitialization::finishInitialization(SGF);
- SGF.Cleanups.setCleanupState(Cleanup, CleanupState::Dead);
+ // We've fully initialized the existential by this point, so we can
+ // retire the partial cleanup.
+ SGF.Cleanups.setCleanupState(deinitExistentialCleanup,
+ CleanupState::Dead);
}
};
@@ -713,24 +779,32 @@
concreteFormalType, sub, conformances);
}
case ExistentialRepresentation::Boxed: {
- // Allocate the existential.
- auto *existential = B.createAllocExistentialBox(loc,
- existentialTL.getLoweredType(),
- concreteFormalType,
- conformances);
- auto *valueAddr = B.createProjectExistentialBox(loc,
- concreteTL.getLoweredType(),
- existential);
- // Initialize the concrete value in-place.
- ExistentialInitialization init(existential, valueAddr, concreteFormalType,
- ExistentialRepresentation::Boxed, *this);
- ManagedValue mv = F(SGFContext(&init));
- if (!mv.isInContext()) {
- mv.ensurePlusOne(*this, loc).forwardInto(*this, loc, init.getAddress());
- init.finishInitialization(*this);
+ // We defer allocation of the box to when the address is demanded.
+ // Create a stack slot to hold the box once it's allocated.
+ SILValue boxValue;
+ auto buf = B.bufferForExpr(
+ loc, existentialTL.getLoweredType(), existentialTL, C,
+ [&](SILValue existential) {
+ // Initialize the existential in-place.
+ ExistentialInitialization init(*this, existential,
+ concreteFormalType,
+ conformances,
+ ExistentialRepresentation::Boxed);
+ ManagedValue mv = F(SGFContext(&init));
+ if (!mv.isInContext()) {
+ init.copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
+ /*init*/ true);
+ init.finishInitialization(*this);
+ }
+ });
+
+ if (buf.isInContext()) {
+ return buf;
}
-
- return emitManagedRValueWithCleanup(existential);
+
+ auto value = B.createLoad(loc, buf.forward(*this),
+ LoadOwnershipQualifier::Take);
+ return emitManagedRValueWithCleanup(value);
}
case ExistentialRepresentation::Opaque: {
@@ -769,22 +843,16 @@
return B.bufferForExpr(
loc, existentialTL.getLoweredType(), existentialTL, C,
[&](SILValue existential) {
- // Allocate the concrete value inside the container.
- SILValue valueAddr = B.createInitExistentialAddr(
- loc, existential,
- concreteFormalType,
- concreteTLPtr->getLoweredType(),
- conformances);
- // Initialize the concrete value in-place.
- InitializationPtr init(
- new ExistentialInitialization(existential, valueAddr, concreteFormalType,
- ExistentialRepresentation::Opaque,
- *this));
- ManagedValue mv = F(SGFContext(init.get()));
+ // Initialize the existential in-place.
+ ExistentialInitialization init(*this, existential,
+ concreteFormalType,
+ conformances,
+ ExistentialRepresentation::Opaque);
+ ManagedValue mv = F(SGFContext(&init));
if (!mv.isInContext()) {
- init->copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
+ init.copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
/*init*/ true);
- init->finishInitialization(*this);
+ init.finishInitialization(*this);
}
});
}
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index bb22247..16f5644 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -1363,8 +1363,9 @@
}
break;
case ExistentialRepresentation::Boxed:
- SGF.B.createDeallocExistentialBox(l, concreteFormalType,
- existentialAddr);
+ auto box = SGF.B.createLoad(l, existentialAddr,
+ LoadOwnershipQualifier::Take);
+ SGF.B.createDeallocExistentialBox(l, concreteFormalType, box);
break;
}
}
@@ -1382,12 +1383,13 @@
/// Enter a cleanup to emit a DeinitExistentialAddr or DeinitExistentialBox
/// of the specified value.
CleanupHandle SILGenFunction::enterDeinitExistentialCleanup(
- SILValue valueOrAddr,
+ CleanupState state,
+ SILValue addr,
CanType concreteFormalType,
ExistentialRepresentation repr) {
- Cleanups.pushCleanup<DeinitExistentialCleanup>(valueOrAddr,
- concreteFormalType,
- repr);
+ assert(addr->getType().isAddress());
+ Cleanups.pushCleanupInState<DeinitExistentialCleanup>(state, addr,
+ concreteFormalType, repr);
return Cleanups.getTopCleanup();
}
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 453ea74..475077d 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3764,10 +3764,7 @@
auto indexLoweredTy = SGM.Types.getLoweredType(
AbstractionPattern::getOpaque(),
indexTy);
- indexLoweredTy = SILType::getPrimitiveType(
- indexLoweredTy.getSwiftRValueType()->mapTypeOutOfContext()
- ->getCanonicalType(),
- indexLoweredTy.getCategory());
+ indexLoweredTy = indexLoweredTy.mapTypeOutOfContext();
indexPatterns.push_back({indexTy->mapTypeOutOfContext()
->getCanonicalType(),
indexLoweredTy});
@@ -4983,7 +4980,8 @@
auto &optTL = SGF.getTypeLowering(E->getSubExpr()->getType());
ManagedValue optValue;
- if (!SGF.silConv.useLoweredAddresses() || optTL.isLoadable()) {
+ if (!SGF.silConv.useLoweredAddresses() || optTL.isLoadable()
+ || E->getType()->hasOpenedExistential()) {
optValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
} else {
auto temp = SGF.emitTemporary(E, optTL);
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 5fbad2b..5859fbc 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -1752,7 +1752,8 @@
/// Enter a cleanup to emit a DeinitExistentialAddr or DeinitExistentialBox
/// of the specified value.
- CleanupHandle enterDeinitExistentialCleanup(SILValue valueOrAddr,
+ CleanupHandle enterDeinitExistentialCleanup(CleanupState state,
+ SILValue addr,
CanType concreteFormalType,
ExistentialRepresentation repr);
diff --git a/lib/SILGen/Scope.h b/lib/SILGen/Scope.h
index 89ce3c8..ae8e634 100644
--- a/lib/SILGen/Scope.h
+++ b/lib/SILGen/Scope.h
@@ -41,6 +41,18 @@
cleanups.innermostScope = depth;
}
+ Scope(const Scope &other) = delete;
+ Scope &operator=(const Scope &other) = delete;
+
+ Scope(Scope &&other)
+ : cleanups(other.cleanups), depth(other.depth),
+ savedInnermostScope(other.savedInnermostScope),
+ loc(other.loc) {
+ other.depth = CleanupsDepth::invalid();
+ assert(!other.isValid());
+ }
+ Scope &operator=(Scope &&other) = delete; // implementable if needed
+
explicit Scope(SILGenFunction &SGF, SILLocation loc)
: Scope(SGF.Cleanups, CleanupLocation::get(loc)) {}
diff --git a/test/SILGen/boxed_existentials.swift b/test/SILGen/boxed_existentials.swift
index a67d599..065e62e 100644
--- a/test/SILGen/boxed_existentials.swift
+++ b/test/SILGen/boxed_existentials.swift
@@ -20,12 +20,14 @@
}
// CHECK-LABEL: sil hidden @$S18boxed_existentials21test_concrete_erasureys5Error_pAA08ClericalF0OF
// CHECK: bb0([[ARG:%.*]] : @guaranteed $ClericalError):
+// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: [[EXISTENTIAL:%.*]] = alloc_existential_box $Error, $ClericalError
// CHECK: [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $Error
-// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK: store [[EXISTENTIAL]] to [init] [[EXISTENTIAL_BUF:%.*]] :
// CHECK: store [[ARG_COPY]] to [init] [[ADDR]] : $*ClericalError
// CHECK-NOT: destroy_value [[ARG]]
-// CHECK: return [[EXISTENTIAL]] : $Error
+// CHECK: [[EXISTENTIAL2:%.*]] = load [take] [[EXISTENTIAL_BUF]]
+// CHECK: return [[EXISTENTIAL2]] : $Error
protocol HairType {}
@@ -36,9 +38,11 @@
// CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*\) Error & HairType]]
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
// CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK: store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
// CHECK: copy_addr [[VALUE_ADDR]] to [initialization] [[ADDR]]
// CHECK-NOT: destroy_addr [[OLD_EXISTENTIAL]]
-// CHECK: return [[NEW_EXISTENTIAL]]
+// CHECK: [[NEW_EXISTENTIAL2:%.*]] = load [take] [[NEW_EXISTENTIALBUF]]
+// CHECK: return [[NEW_EXISTENTIAL2]]
protocol HairClass: class {}
@@ -49,9 +53,11 @@
// CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*\) Error & HairClass]]
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
// CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK: store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
// CHECK: [[COPIED_VALUE:%.*]] = copy_value [[VALUE]]
// CHECK: store [[COPIED_VALUE]] to [init] [[ADDR]]
-// CHECK: return [[NEW_EXISTENTIAL]]
+// CHECK: [[NEW_EXISTENTIAL2:%.*]] = load [take] [[NEW_EXISTENTIALBUF]]
+// CHECK: return [[NEW_EXISTENTIAL2]]
func test_property(_ x: Error) -> String {
return x._domain
diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift
index 03be0d0..6d5eb10 100644
--- a/test/SILGen/dynamic_self.swift
+++ b/test/SILGen/dynamic_self.swift
@@ -74,8 +74,8 @@
// CHECK: bb0([[P:%[0-9]+]] : @trivial $*P):
// CHECK: [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P to $*@opened([[N:".*"]]) P
// CHECK: [[P_RESULT:%[0-9]+]] = alloc_stack $P
-// CHECK: [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P
// CHECK: [[P_F_METHOD:%[0-9]+]] = witness_method $@opened([[N]]) P, #P.f!1 : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+// CHECK: [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P
// CHECK: apply [[P_F_METHOD]]<@opened([[N]]) P>([[P_RESULT_ADDR]], [[PCOPY_ADDR]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
// CHECK: destroy_addr [[P_RESULT]] : $*P
// CHECK: dealloc_stack [[P_RESULT]] : $*P
diff --git a/test/SILGen/erasure_reabstraction.swift b/test/SILGen/erasure_reabstraction.swift
index 816e3f7..a59ae6d 100644
--- a/test/SILGen/erasure_reabstraction.swift
+++ b/test/SILGen/erasure_reabstraction.swift
@@ -4,17 +4,17 @@
struct Foo {}
class Bar {}
-// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $Foo.Type
// CHECK: [[METATYPE:%.*]] = metatype $@thick Foo.Type
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $Foo.Type
// CHECK: store [[METATYPE]] to [trivial] [[CONCRETE]] : $*@thick Foo.Type
let x: Any = Foo.self
-// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $() -> ()
// CHECK: [[CLOSURE:%.*]] = function_ref
// CHECK: [[CLOSURE_THICK:%.*]] = thin_to_thick_function [[CLOSURE]]
// CHECK: [[REABSTRACTION_THUNK:%.*]] = function_ref @$SIeg_ytytIegnr_TR
// CHECK: [[CLOSURE_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTION_THUNK]]([[CLOSURE_THICK]])
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $() -> ()
// CHECK: store [[CLOSURE_REABSTRACTED]] to [init] [[CONCRETE]]
let y: Any = {() -> () in ()}
diff --git a/test/SILGen/errors.swift b/test/SILGen/errors.swift
index 8ed2c70..b7e247c 100644
--- a/test/SILGen/errors.swift
+++ b/test/SILGen/errors.swift
@@ -35,26 +35,31 @@
}
// CHECK: sil hidden @$S6errors15dont_make_a_cat{{.*}}F : $@convention(thin) () -> (@owned Cat, @error Error) {
-// CHECK: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
-// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
-// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
+// CHECK: [[T0:%.*]] = metatype $@thin HomeworkError.Type
// CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooHard!enumelt
+// CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
+// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
+// CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] :
// CHECK-NEXT: store [[T1]] to [init] [[ADDR]]
+// CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]]
// CHECK-NEXT: builtin "willThrow"
-// CHECK-NEXT: throw [[BOX]]
+// CHECK-NEXT: dealloc_stack [[BOXBUF]]
+// CHECK-NEXT: throw [[BOX2]]
func dont_make_a_cat() throws -> Cat {
throw HomeworkError.TooHard
}
// CHECK: sil hidden @$S6errors11dont_return{{.*}}F : $@convention(thin) <T> (@in_guaranteed T) -> (@out T, @error Error) {
-// CHECK: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
-// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
-// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
+// CHECK: [[T0:%.*]] = metatype $@thin HomeworkError.Type
// CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooMuch!enumelt
+// CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
+// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
+// CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] :
// CHECK-NEXT: store [[T1]] to [init] [[ADDR]]
+// CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]]
// CHECK-NEXT: builtin "willThrow"
-// CHECK-NOT: destroy_addr %1 : $*T
-// CHECK-NEXT: throw [[BOX]]
+// CHECK-NEXT: dealloc_stack [[BOXBUF]]
+// CHECK-NEXT: throw [[BOX2]]
func dont_return<T>(_ argument: T) throws -> T {
throw HomeworkError.TooMuch
}
@@ -224,6 +229,7 @@
//CHECK-LABEL: sil hidden @$S6errors6IThrows5Int32VyKF
//CHECK: builtin "willThrow"
+//CHECK-NEXT: dealloc_stack
//CHECK-NEXT: throw
func IThrow() throws -> Int32 {
throw ColorError.Red
diff --git a/test/SILGen/existential_erasure.swift b/test/SILGen/existential_erasure.swift
index f262a82..b905502 100644
--- a/test/SILGen/existential_erasure.swift
+++ b/test/SILGen/existential_erasure.swift
@@ -44,18 +44,17 @@
// CHECK: bb0(%0 : @trivial $*P):
// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
// CHECK: [[RESULT:%.*]] = alloc_stack $P
-// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
// CHECK: [[FUNC:%.*]] = function_ref @$S19existential_erasure12throwingFuncSbyKF
// CHECK: try_apply [[FUNC]]()
//
// CHECK: bb1([[SUCCESS:%.*]] : @trivial $Bool):
// CHECK: [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.downgrade!1 : {{.*}}, [[OPEN]]
+// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
// CHECK: apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[SUCCESS]], [[OPEN]])
// CHECK: dealloc_stack [[RESULT]]
// CHECK: return
//
// CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
-// CHECK: deinit_existential_addr [[RESULT]]
// CHECK: dealloc_stack [[RESULT]]
// CHECK: throw [[FAILURE]]
//
@@ -67,8 +66,8 @@
// CHECK: bb0(%0 : @trivial $*P):
// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
// CHECK: [[RESULT:%.*]] = alloc_stack $P
-// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
// CHECK: [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.upgrade!1 : {{.*}}, [[OPEN]]
+// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
// CHECK: try_apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[OPEN]])
//
// CHECK: bb1
@@ -96,16 +95,19 @@
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
// CHECK: debug_value [[ARG]] : $Error
// CHECK: [[OPEN:%.*]] = open_existential_box [[ARG]] : $Error to $*[[OPEN_TYPE:@opened\(.*\) Error]]
+// CHECK: [[FUNC:%.*]] = function_ref @$Ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
// CHECK: [[RESULT:%.*]] = alloc_existential_box $Error, $[[OPEN_TYPE]]
// CHECK: [[ADDR:%.*]] = project_existential_box $[[OPEN_TYPE]] in [[RESULT]] : $Error
-// CHECK: [[FUNC:%.*]] = function_ref @$Ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
+// CHECK: store [[RESULT]] to [init] [[RESULT_BUF:%.*]] :
// CHECK: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
//
// CHECK: bb1
-// CHECK: return [[RESULT]] : $Error
+// CHECK: [[RESULT2:%.*]] = load [take] [[RESULT_BUF]]
+// CHECK: return [[RESULT2]] : $Error
//
// CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
-// CHECK: dealloc_existential_box [[RESULT]]
+// CHECK: [[RESULT3:%.*]] = load [take] [[RESULT_BUF]]
+// CHECK: dealloc_existential_box [[RESULT3]]
// CHECK: throw [[FAILURE]] : $Error
//
return try e.returnOrThrowSelf()
diff --git a/test/SILGen/existential_erasure_mutating_covariant_self.swift b/test/SILGen/existential_erasure_mutating_covariant_self.swift
new file mode 100644
index 0000000..68aa566
--- /dev/null
+++ b/test/SILGen/existential_erasure_mutating_covariant_self.swift
@@ -0,0 +1,73 @@
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -verify %s
+// RUN: %target-swift-frontend -emit-sil -enable-sil-ownership %s | %FileCheck --check-prefix=AFTER-MANDATORY-PASSES %s
+
+// ensure escape analysis killed the box allocations used for delayed Self
+// return buffers
+// AFTER-MANDATORY-PASSES-NOT: alloc_box
+
+extension Error {
+ mutating func covariantReturn(_: Int) -> Self { return self }
+ mutating func covariantOptionalReturn(_: Int) -> Self? { return self }
+ mutating func covariantReturnOrThrow(_: Int) throws -> Self { return self }
+ mutating func covariantClosureArgAndReturn(_: (Self) -> Int) -> Self { return self }
+}
+
+protocol MutatingWithCovariantReturn {
+ mutating func covariantReturn(_: Int) -> Self
+ mutating func covariantOptionalReturn(_: Int) -> Self?
+ mutating func covariantReturnOrThrow(_: Int) throws -> Self
+ mutating func covariantClosureArgAndReturn(_: (Self) -> Int) -> Self
+}
+
+protocol ClassConstrainedRefinement: MutatingWithCovariantReturn, AnyObject {}
+
+func int() -> Int { return 0 }
+func intThrows() throws -> Int { return 0 }
+
+func foo(x: inout MutatingWithCovariantReturn, y: inout ClassConstrainedRefinement, z: inout Error) throws {
+ _ = x.covariantReturn(int())
+ _ = x.covariantReturn(try intThrows())
+ _ = x.covariantReturn(try! intThrows())
+
+ _ = x.covariantOptionalReturn(int())
+ _ = x.covariantOptionalReturn(try intThrows())
+ _ = x.covariantOptionalReturn(try! intThrows())
+
+ _ = try x.covariantReturnOrThrow(int())
+ _ = try x.covariantReturnOrThrow(try intThrows())
+ _ = try x.covariantReturnOrThrow(try! intThrows())
+
+ _ = x.covariantClosureArgAndReturn({ _ in 0 })
+
+
+ _ = y.covariantReturn(int())
+ _ = y.covariantReturn(try intThrows())
+ _ = y.covariantReturn(try! intThrows())
+
+ _ = y.covariantOptionalReturn(int())
+ _ = y.covariantOptionalReturn(try intThrows())
+ _ = y.covariantOptionalReturn(try! intThrows())
+
+ _ = try y.covariantReturnOrThrow(int())
+ _ = try y.covariantReturnOrThrow(try intThrows())
+ _ = try y.covariantReturnOrThrow(try! intThrows())
+
+ // FIXME: the dynamic self capture here has to happen after existential
+ // opening as well.
+ //_ = y.covariantClosureArgAndReturn({ _ in 0 })
+
+
+ _ = z.covariantReturn(int())
+ _ = z.covariantReturn(try intThrows())
+ _ = z.covariantReturn(try! intThrows())
+
+ _ = z.covariantOptionalReturn(int())
+ _ = z.covariantOptionalReturn(try intThrows())
+ _ = z.covariantOptionalReturn(try! intThrows())
+
+ _ = try z.covariantReturnOrThrow(int())
+ _ = try z.covariantReturnOrThrow(try intThrows())
+ _ = try z.covariantReturnOrThrow(try! intThrows())
+
+ _ = z.covariantClosureArgAndReturn({ _ in 0 })
+}
diff --git a/test/SILGen/existential_metatypes.swift b/test/SILGen/existential_metatypes.swift
index ceec037..d58045c 100644
--- a/test/SILGen/existential_metatypes.swift
+++ b/test/SILGen/existential_metatypes.swift
@@ -21,8 +21,8 @@
let type1 = type(of: x)
// CHECK: [[INSTANCE1:%.*]] = alloc_stack $P
// CHECK: [[OPEN_TYPE1:%.*]] = open_existential_metatype [[TYPE1]]
- // CHECK: [[INSTANCE1_VALUE:%.*]] = init_existential_addr [[INSTANCE1]] : $*P
// CHECK: [[INIT:%.*]] = witness_method {{.*}} #P.init!allocator
+ // CHECK: [[INSTANCE1_VALUE:%.*]] = init_existential_addr [[INSTANCE1]] : $*P
// CHECK: apply [[INIT]]<{{.*}}>([[INSTANCE1_VALUE]], [[OPEN_TYPE1]])
let instance1 = type1.init()
@@ -31,8 +31,8 @@
let type2: P.Type = S.self
// CHECK: [[INSTANCE2:%.*]] = alloc_stack $P
// CHECK: [[OPEN_TYPE2:%.*]] = open_existential_metatype [[TYPE2]]
- // CHECK: [[INSTANCE2_VALUE:%.*]] = init_existential_addr [[INSTANCE2]] : $*P
// CHECK: [[STATIC_METHOD:%.*]] = witness_method {{.*}} #P.staticMethod
+ // CHECK: [[INSTANCE2_VALUE:%.*]] = init_existential_addr [[INSTANCE2]] : $*P
// CHECK: apply [[STATIC_METHOD]]<{{.*}}>([[INSTANCE2_VALUE]], [[OPEN_TYPE2]])
let instance2 = type2.staticMethod()
}
diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift
index 53c9a88..c1601c6 100644
--- a/test/SILGen/objc_bridging_any.swift
+++ b/test/SILGen/objc_bridging_any.swift
@@ -643,9 +643,9 @@
// CHECK-LABEL: sil hidden @$SSo12GenericClassC17objc_bridging_anyE23pseudogenericAnyErasure1xypx_tF :
func pseudogenericAnyErasure(x: T) -> Any {
// CHECK: bb0([[ANY_OUT:%.*]] : @trivial $*Any, [[ARG:%.*]] : @guaranteed $T, [[SELF:%.*]] : @guaranteed $GenericClass<T>
- // CHECK: [[ANY_BUF:%.*]] = init_existential_addr [[ANY_OUT]] : $*Any, $AnyObject
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[ARG_COPY]] : $T : $T, $AnyObject
+ // CHECK: [[ANY_BUF:%.*]] = init_existential_addr [[ANY_OUT]] : $*Any, $AnyObject
// CHECK: store [[ANYOBJECT]] to [init] [[ANY_BUF]]
return x
}
diff --git a/test/SILGen/objc_error.swift b/test/SILGen/objc_error.swift
index 8e90cea..d44060d 100644
--- a/test/SILGen/objc_error.swift
+++ b/test/SILGen/objc_error.swift
@@ -159,8 +159,10 @@
// CHECK: [[FAILURE]]:
// CHECK: [[ERROR_BOX:%[0-9]+]] = alloc_existential_box $Error, $Self
// CHECK: [[ERROR_PROJECTED:%[0-9]+]] = project_existential_box $Self in [[ERROR_BOX]] : $Error
+ // CHECK: store [[ERROR_BOX]] to [init] [[ERROR_BUF:%.*]] :
// CHECK: copy_addr [take] [[COPY]] to [initialization] [[ERROR_PROJECTED]] : $*Self
- // CHECK: br [[CONTINUATION]]([[ERROR_BOX]] : $Error)
+ // CHECK: [[ERROR_BOX2:%.*]] = load [take] [[ERROR_BUF]]
+ // CHECK: br [[CONTINUATION]]([[ERROR_BOX2]] : $Error)
// CHECK: [[CONTINUATION]]([[ERROR_ARG:%[0-9]+]] : @owned $Error):
return self as NSError
diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift
index ca26608..654855a 100644
--- a/test/SILGen/protocol_extensions.swift
+++ b/test/SILGen/protocol_extensions.swift
@@ -528,8 +528,8 @@
// CHECK: [[P1A:%[0-9]+]] = alloc_box ${ var P1 }
// CHECK: [[PB:%.*]] = project_box [[P1A]]
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
- // CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[PB]] : $*P1, $@opened([[UUID2:".*"]]) P1
// CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE11returnsSelf{{[_0-9a-zA-Z]*}}F
+ // CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[PB]] : $*P1, $@opened([[UUID2:".*"]]) P1
// CHECK: apply [[FN]]<@opened([[UUID]]) P1>([[P1AINIT]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> @out τ_0_0
var p1a: P1 = p1.returnsSelf()
}
diff --git a/test/SILGen/protocols.swift b/test/SILGen/protocols.swift
index 55bb387..9fa6f89 100644
--- a/test/SILGen/protocols.swift
+++ b/test/SILGen/protocols.swift
@@ -230,8 +230,8 @@
// CHECK: bb0([[IM:%[0-9]+]] : @trivial $@thick Initializable.Type, [[I:%[0-9]+]] : @trivial $Int):
// CHECK: [[ARCHETYPE_META:%[0-9]+]] = open_existential_metatype [[IM]] : $@thick Initializable.Type to $@thick (@opened([[N:".*"]]) Initializable).Type
// CHECK: [[TEMP_VALUE:%[0-9]+]] = alloc_stack $Initializable
-// CHECK: [[TEMP_ADDR:%[0-9]+]] = init_existential_addr [[TEMP_VALUE]] : $*Initializable, $@opened([[N]]) Initializable
// CHECK: [[INIT_WITNESS:%[0-9]+]] = witness_method $@opened([[N]]) Initializable, #Initializable.init!allocator.1 : {{.*}}, [[ARCHETYPE_META]]{{.*}} : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+// CHECK: [[TEMP_ADDR:%[0-9]+]] = init_existential_addr [[TEMP_VALUE]] : $*Initializable, $@opened([[N]]) Initializable
// CHECK: [[INIT_RESULT:%[0-9]+]] = apply [[INIT_WITNESS]]<@opened([[N]]) Initializable>([[TEMP_ADDR]], [[I]], [[ARCHETYPE_META]]) : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
// CHECK: destroy_addr [[TEMP_VALUE]] : $*Initializable
// CHECK: dealloc_stack [[TEMP_VALUE]] : $*Initializable
diff --git a/test/SILGen/subclass_existentials.swift b/test/SILGen/subclass_existentials.swift
index dbbfcbf..55c5a8b 100644
--- a/test/SILGen/subclass_existentials.swift
+++ b/test/SILGen/subclass_existentials.swift
@@ -128,16 +128,17 @@
let _: Base<Int> & P = baseAndP.classSelfReturn()
// CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P to $@opened("{{.*}}") Base<Int> & P
- // CHECK: [[RESULT_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
// CHECK: [[SELF_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
// CHECK: store_borrow [[PAYLOAD]] to [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
// CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") Base<Int> & P, #P.protocolSelfReturn!1 : <Self where Self : P> (Self) -> () -> @dynamic_self Self, [[PAYLOAD]] : $@opened("{{.*}}") Base<Int> & P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
- // CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BOX]], [[SELF_BOX]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+ // CHECK: [[RESULT_BOX:%.*]] = alloc_box
+ // CHECK: [[RESULT_BUF:%.*]] = project_box [[RESULT_BOX]]
+ // CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BUF]], [[SELF_BOX]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
// CHECK: dealloc_stack [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
- // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+ // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") Base<Int> & P
// CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
// CHECK: destroy_value [[RESULT]] : $Base<Int> & P
- // CHECK: dealloc_stack [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+ // CHECK: dealloc_box [[RESULT_BOX]]
let _: Base<Int> & P = baseAndP.protocolSelfReturn()
// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
@@ -150,13 +151,14 @@
let _: Base<Int> & P = baseAndPType.classSelfReturn()
// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
- // CHECK: [[RESULT:%.*]] = alloc_stack $@opened("{{.*}}") (Base<Int> & P)
// CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") (Base<Int> & P), #P.protocolSelfReturn!1 : <Self where Self : P> (Self.Type) -> () -> @dynamic_self Self, [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
- // CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
- // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT]] : $*@opened("{{.*}}") (Base<Int> & P)
+ // CHECK: [[RESULT_BOX:%.*]] = alloc_box
+ // CHECK: [[RESULT_BUF:%.*]] = project_box
+ // CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT_BUF]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
+ // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") (Base<Int> & P)
// CHECK: [[RESULT_VALUE:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
// CHECK: destroy_value [[RESULT_VALUE]]
- // CHECK: dealloc_stack [[RESULT]]
+ // CHECK: dealloc_box [[RESULT_BOX]]
let _: Base<Int> & P = baseAndPType.protocolSelfReturn()
// Partial applications
diff --git a/test/SILGen/toplevel_errors.swift b/test/SILGen/toplevel_errors.swift
index f037df0..04b3970 100644
--- a/test/SILGen/toplevel_errors.swift
+++ b/test/SILGen/toplevel_errors.swift
@@ -7,12 +7,14 @@
throw MyError.A
// CHECK: sil @main
+// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
// CHECK: [[ERR:%.*]] = alloc_existential_box $Error, $MyError
// CHECK: [[ADDR:%.*]] = project_existential_box $MyError in [[ERR]] : $Error
-// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
+// CHECK: store [[ERR]] to [init] [[ERRBUF:%.*]] :
// CHECK: store [[T0]] to [trivial] [[ADDR]] : $*MyError
-// CHECK: builtin "willThrow"([[ERR]] : $Error)
-// CHECK: br bb2([[ERR]] : $Error)
+// CHECK: [[ERR2:%.*]] = load [take] [[ERRBUF]]
+// CHECK: builtin "willThrow"([[ERR2]] : $Error)
+// CHECK: br bb2([[ERR2]] : $Error)
// CHECK: bb1([[T0:%.*]] : $Int32):
// CHECK: return [[T0]] : $Int32
diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift
index 58a7198..2998f66 100644
--- a/test/SILOptimizer/access_marker_verify.swift
+++ b/test/SILOptimizer/access_marker_verify.swift
@@ -826,13 +826,13 @@
// CHECK: copy_addr [[P1]] to [initialization] [[TEMP1]] : $*@opened
// CHECK-NOT: begin_access
// CHECK: [[OUTC:%.*]] = apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
-// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
// CHECK: [[P2:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
// CHECK: [[TEMP2:%.*]] = alloc_stack $@opened
// CHECK-NOT: begin_access
// CHECK: copy_addr [[P2]] to [initialization] [[TEMP2]] : $*@opened
// CHECK-NOT: begin_access
// CHECK: apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
+// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
// CHECK: store %{{.*}} to [init] [[OUTANY]] : $*BaseClass
// CHECK: return [[OUTC]] : $BaseClass
// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF'
@@ -1003,8 +1003,8 @@
// CHECK-LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () {
// CHECK: alloc_global @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ
// CHECK: [[GADR:%.*]] = global_addr @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P
-// CHECK: [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP
// CHECK: %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP
+// CHECK: [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP
// CHECK: store %{{.*}} to [trivial] [[EADR]] : $*StructP
// CHECK-LABEL: } // end sil function 'globalinit
@@ -1019,6 +1019,8 @@
// CHECK-LABEL: sil @$S20access_marker_verify11testInitBoxyyKF : $@convention(thin) () -> @error Error {
// CHECK: [[BOXALLOC:%.*]] = alloc_existential_box $Error, $SomeError
// CHECK: [[PROJ:%.*]] = project_existential_box $SomeError in [[BOXALLOC]] : $Error
+// CHECK: store [[BOXALLOC]] to [init] [[BOXBUF:%.*]] :
// CHECK: store %{{.*}} to [trivial] [[PROJ]] : $*SomeError
-// CHECK: throw [[BOXALLOC]] : $Error
+// CHECK: [[BOXALLOC2:%.*]] = load [take] [[BOXBUF]]
+// CHECK: throw [[BOXALLOC2]] : $Error
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11testInitBoxyyKF'