Files
swift-mirror/lib/SILGen/SILGenExpr.cpp
John McCall 338825e73d Fix the emission of r-value pointer conversions to delay the
conversions and extend lifetimes over the call.

Apply this logic to string-to-pointer conversions as well as
array-to-pointer conversions.

Fix the AST verifier to not blow up on optional pointer conversions,
and make sure we SILGen them correctly.  There's still an AST bug
here, but I'll fix that in a follow-up patch.
2017-04-26 14:15:44 -04:00

4525 lines
178 KiB
C++

//===--- SILGenExpr.cpp - Implements Lowering of ASTs -> SIL for Exprs ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "SILGen.h"
#include "ArgumentScope.h"
#include "ArgumentSource.h"
#include "Callee.h"
#include "Condition.h"
#include "ExitableFullExpr.h"
#include "Initialization.h"
#include "LValue.h"
#include "RValue.h"
#include "ResultPlan.h"
#include "SILGenDynamicCast.h"
#include "Scope.h"
#include "Varargs.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/type_traits.h"
#include "swift/SIL/DynamicCasts.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include "swift/AST/DiagnosticsSIL.h"
using namespace swift;
using namespace Lowering;
ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc,
SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedRetain(loc, v, lowering);
}
ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc,
SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType() == v->getType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
if (v->getType().isObject() &&
v.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(v);
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
v = lowering.emitCopyValue(B, loc, v);
return emitManagedRValueWithCleanup(v, lowering);
}
ManagedValue SILGenFunction::emitManagedLoadCopy(SILLocation loc, SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedLoadCopy(loc, v, lowering);
}
ManagedValue SILGenFunction::emitManagedLoadCopy(SILLocation loc, SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getAddressType() == v->getType());
v = lowering.emitLoadOfCopy(B, loc, v, IsNotTake);
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
if (v.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(v);
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
return emitManagedRValueWithCleanup(v, lowering);
}
ManagedValue SILGenFunction::emitManagedLoadBorrow(SILLocation loc,
SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedLoadBorrow(loc, v, lowering);
}
ManagedValue
SILGenFunction::emitManagedLoadBorrow(SILLocation loc, SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getAddressType() == v->getType());
if (lowering.isTrivial()) {
v = lowering.emitLoadOfCopy(B, loc, v, IsNotTake);
return ManagedValue::forUnmanaged(v);
}
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
auto *lbi = B.createLoadBorrow(loc, v);
return emitManagedBorrowedRValueWithCleanup(v, lbi, lowering);
}
ManagedValue SILGenFunction::emitManagedStoreBorrow(SILLocation loc, SILValue v,
SILValue addr) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedStoreBorrow(loc, v, addr, lowering);
}
ManagedValue SILGenFunction::emitManagedStoreBorrow(
SILLocation loc, SILValue v, SILValue addr, const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() == v->getType());
if (lowering.isTrivial() ||
v.getOwnershipKind() == ValueOwnershipKind::Trivial) {
lowering.emitStore(B, loc, v, addr, StoreOwnershipQualifier::Trivial);
return ManagedValue::forUnmanaged(v);
}
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
auto *sbi = B.createStoreBorrow(loc, v, addr);
return emitManagedBorrowedRValueWithCleanup(sbi->getSrc(), sbi, lowering);
}
ManagedValue SILGenFunction::emitManagedBeginBorrow(SILLocation loc,
SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedBeginBorrow(loc, v, lowering);
}
ManagedValue
SILGenFunction::emitManagedBeginBorrow(SILLocation loc, SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() ==
v->getType().getObjectType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
if (v.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(v);
if (v.getOwnershipKind() == ValueOwnershipKind::Guaranteed)
return ManagedValue::forUnmanaged(v);
auto *bbi = B.createBeginBorrow(loc, v);
return emitManagedBorrowedRValueWithCleanup(v, bbi, lowering);
}
namespace {
struct EndBorrowCleanup : Cleanup {
SILValue originalValue;
SILValue borrowedValue;
EndBorrowCleanup(SILValue originalValue, SILValue borrowedValue)
: originalValue(originalValue), borrowedValue(borrowedValue) {}
void emit(SILGenFunction &gen, CleanupLocation l) override {
gen.B.createEndBorrow(l, borrowedValue, originalValue);
}
void dump(SILGenFunction &gen) const override {
#ifndef NDEBUG
llvm::errs() << "EndBorrowCleanup "
<< "State:" << getState() << "\n"
<< "original:" << originalValue << "borrowed:" << borrowedValue
<< "\n";
#endif
}
};
struct FormalEvaluationEndBorrowCleanup : Cleanup {
FormalEvaluationContext::stable_iterator Depth;
FormalEvaluationEndBorrowCleanup() : Depth() {}
void emit(SILGenFunction &gen, CleanupLocation l) override {
getEvaluation(gen).finish(gen);
}
void dump(SILGenFunction &gen) const override {
#ifndef NDEBUG
llvm::errs() << "FormalEvaluationEndBorrowCleanup "
<< "State:" << getState() << "\n"
<< "original:" << getOriginalValue(gen) << "\n"
<< "borrowed:" << getBorrowedValue(gen) << "\n";
#endif
}
SharedBorrowFormalAccess &getEvaluation(SILGenFunction &gen) const {
auto &evaluation = *gen.FormalEvalContext.find(Depth);
assert(evaluation.getKind() == FormalAccess::Shared);
return static_cast<SharedBorrowFormalAccess &>(evaluation);
}
SILValue getOriginalValue(SILGenFunction &gen) const {
return getEvaluation(gen).getOriginalValue();
}
SILValue getBorrowedValue(SILGenFunction &gen) const {
return getEvaluation(gen).getBorrowedValue();
}
};
} // end anonymous namespace
ManagedValue
SILGenFunction::emitFormalEvaluationManagedBeginBorrow(SILLocation loc,
SILValue v) {
if (v.getOwnershipKind() == ValueOwnershipKind::Guaranteed)
return ManagedValue::forUnmanaged(v);
auto &lowering = getTypeLowering(v->getType());
return emitFormalEvaluationManagedBeginBorrow(loc, v, lowering);
}
ManagedValue SILGenFunction::emitFormalEvaluationManagedBeginBorrow(
SILLocation loc, SILValue v, const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() ==
v->getType().getObjectType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
if (v.getOwnershipKind() == ValueOwnershipKind::Guaranteed)
return ManagedValue::forUnmanaged(v);
auto *bbi = B.createBeginBorrow(loc, v);
return emitFormalEvaluationManagedBorrowedRValueWithCleanup(loc, v, bbi,
lowering);
}
ManagedValue
SILGenFunction::emitFormalEvaluationManagedBorrowedRValueWithCleanup(
SILLocation loc, SILValue original, SILValue borrowed) {
auto &lowering = getTypeLowering(original->getType());
return emitFormalEvaluationManagedBorrowedRValueWithCleanup(
loc, original, borrowed, lowering);
}
ManagedValue
SILGenFunction::emitFormalEvaluationManagedBorrowedRValueWithCleanup(
SILLocation loc, SILValue original, SILValue borrowed,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() ==
original->getType().getObjectType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(borrowed);
if (!borrowed->getType().isObject()) {
return ManagedValue(borrowed, CleanupHandle::invalid());
}
assert(InWritebackScope && "Must be in formal evaluation scope");
auto &cleanup = Cleanups.pushCleanup<FormalEvaluationEndBorrowCleanup>();
CleanupHandle handle = Cleanups.getTopCleanup();
FormalEvalContext.push<SharedBorrowFormalAccess>(loc, handle, original,
borrowed);
cleanup.Depth = FormalEvalContext.stable_begin();
return ManagedValue(borrowed, CleanupHandle::invalid());
}
ManagedValue
SILGenFunction::emitManagedBorrowedRValueWithCleanup(SILValue original,
SILValue borrowed) {
assert(original->getType().getObjectType() ==
borrowed->getType().getObjectType());
auto &lowering = getTypeLowering(original->getType());
return emitManagedBorrowedRValueWithCleanup(original, borrowed, lowering);
}
ManagedValue SILGenFunction::emitManagedBorrowedRValueWithCleanup(
SILValue original, SILValue borrowed, const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() ==
original->getType().getObjectType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(borrowed);
if (original->getType().isObject() &&
original.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(borrowed);
if (borrowed->getType().isObject()) {
Cleanups.pushCleanup<EndBorrowCleanup>(original, borrowed);
}
return ManagedValue(borrowed, CleanupHandle::invalid());
}
ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedRValueWithCleanup(v, lowering);
}
ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getObjectType() ==
v->getType().getObjectType());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
if (v->getType().isObject() &&
v.getOwnershipKind() == ValueOwnershipKind::Trivial) {
return ManagedValue::forUnmanaged(v);
}
return ManagedValue(v, enterDestroyCleanup(v));
}
ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v) {
auto &lowering = getTypeLowering(v->getType());
return emitManagedBufferWithCleanup(v, lowering);
}
ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getAddressType() == v->getType() ||
!silConv.useLoweredAddresses());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);
return ManagedValue(v, enterDestroyCleanup(v));
}
void SILGenFunction::emitExprInto(Expr *E, Initialization *I) {
// Handle the special case of copying an lvalue.
if (auto load = dyn_cast<LoadExpr>(E)) {
FormalEvaluationScope writeback(*this);
auto lv = emitLValue(load->getSubExpr(), AccessKind::Read);
emitCopyLValueInto(E, std::move(lv), I);
return;
}
RValue result = emitRValue(E, SGFContext(I));
if (result)
std::move(result).forwardInto(*this, E, I);
}
namespace {
class RValueEmitter
: public Lowering::ExprVisitor<RValueEmitter, RValue, SGFContext>
{
typedef Lowering::ExprVisitor<RValueEmitter,RValue,SGFContext> super;
public:
SILGenFunction &SGF;
RValueEmitter(SILGenFunction &SGF) : SGF(SGF) {}
using super::visit;
RValue visit(Expr *E) {
assert(!E->getType()->is<LValueType>() &&
!E->getType()->is<InOutType>() &&
"RValueEmitter shouldn't be called on lvalues");
return visit(E, SGFContext());
}
// These always produce lvalues.
RValue visitInOutExpr(InOutExpr *E, SGFContext C) {
LValue lv = SGF.emitLValue(E->getSubExpr(), AccessKind::ReadWrite);
return RValue(SGF, E, SGF.emitAddressOfLValue(E->getSubExpr(),
std::move(lv),
AccessKind::ReadWrite));
}
RValue visitApplyExpr(ApplyExpr *E, SGFContext C);
RValue visitDiscardAssignmentExpr(DiscardAssignmentExpr *E, SGFContext C) {
llvm_unreachable("cannot appear in rvalue");
}
RValue visitDeclRefExpr(DeclRefExpr *E, SGFContext C);
RValue visitTypeExpr(TypeExpr *E, SGFContext C);
RValue visitSuperRefExpr(SuperRefExpr *E, SGFContext C);
RValue visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E,
SGFContext C);
RValue visitForceTryExpr(ForceTryExpr *E, SGFContext C);
RValue visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C);
RValue visitNilLiteralExpr(NilLiteralExpr *E, SGFContext C);
RValue visitIntegerLiteralExpr(IntegerLiteralExpr *E, SGFContext C);
RValue visitFloatLiteralExpr(FloatLiteralExpr *E, SGFContext C);
RValue visitBooleanLiteralExpr(BooleanLiteralExpr *E, SGFContext C);
RValue emitStringLiteral(Expr *E, StringRef Str, SGFContext C,
StringLiteralExpr::Encoding encoding);
RValue visitStringLiteralExpr(StringLiteralExpr *E, SGFContext C);
RValue visitLoadExpr(LoadExpr *E, SGFContext C);
RValue visitDerivedToBaseExpr(DerivedToBaseExpr *E, SGFContext C);
RValue visitMetatypeConversionExpr(MetatypeConversionExpr *E,
SGFContext C);
RValue visitCollectionUpcastConversionExpr(
CollectionUpcastConversionExpr *E,
SGFContext C);
RValue visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C);
RValue visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E,
SGFContext C);
RValue visitFunctionConversionExpr(FunctionConversionExpr *E,
SGFContext C);
RValue visitCovariantFunctionConversionExpr(
CovariantFunctionConversionExpr *E,
SGFContext C);
RValue visitCovariantReturnConversionExpr(
CovariantReturnConversionExpr *E,
SGFContext C);
RValue visitErasureExpr(ErasureExpr *E, SGFContext C);
RValue visitAnyHashableErasureExpr(AnyHashableErasureExpr *E, SGFContext C);
RValue visitForcedCheckedCastExpr(ForcedCheckedCastExpr *E,
SGFContext C);
RValue visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *E,
SGFContext C);
RValue visitIsExpr(IsExpr *E, SGFContext C);
RValue visitCoerceExpr(CoerceExpr *E, SGFContext C);
RValue visitTupleExpr(TupleExpr *E, SGFContext C);
RValue visitMemberRefExpr(MemberRefExpr *E, SGFContext C);
RValue visitDynamicMemberRefExpr(DynamicMemberRefExpr *E, SGFContext C);
RValue visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *E,
SGFContext C);
RValue visitTupleElementExpr(TupleElementExpr *E, SGFContext C);
RValue visitSubscriptExpr(SubscriptExpr *E, SGFContext C);
RValue visitKeyPathApplicationExpr(KeyPathApplicationExpr *E, SGFContext C);
RValue visitDynamicSubscriptExpr(DynamicSubscriptExpr *E,
SGFContext C);
RValue visitTupleShuffleExpr(TupleShuffleExpr *E, SGFContext C);
RValue visitDynamicTypeExpr(DynamicTypeExpr *E, SGFContext C);
RValue visitCaptureListExpr(CaptureListExpr *E, SGFContext C);
RValue visitAbstractClosureExpr(AbstractClosureExpr *E, SGFContext C);
RValue visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E,
SGFContext C);
RValue visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C);
RValue visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C);
RValue visitObjCSelectorExpr(ObjCSelectorExpr *E, SGFContext C);
RValue visitKeyPathExpr(KeyPathExpr *E, SGFContext C);
RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E,
SGFContext C);
RValue visitCollectionExpr(CollectionExpr *E, SGFContext C);
RValue visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E,
SGFContext C);
RValue visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E, SGFContext C);
RValue visitClassMetatypeToObjectExpr(ClassMetatypeToObjectExpr *E,
SGFContext C);
RValue visitExistentialMetatypeToObjectExpr(ExistentialMetatypeToObjectExpr *E,
SGFContext C);
RValue visitProtocolMetatypeToObjectExpr(ProtocolMetatypeToObjectExpr *E,
SGFContext C);
RValue visitIfExpr(IfExpr *E, SGFContext C);
RValue visitAssignExpr(AssignExpr *E, SGFContext C);
RValue visitEnumIsCaseExpr(EnumIsCaseExpr *E, SGFContext C);
RValue visitBindOptionalExpr(BindOptionalExpr *E, SGFContext C);
RValue visitOptionalEvaluationExpr(OptionalEvaluationExpr *E,
SGFContext C);
RValue visitForceValueExpr(ForceValueExpr *E, SGFContext C);
RValue emitForceValue(SILLocation loc, Expr *E,
unsigned numOptionalEvaluations,
SGFContext C);
RValue visitOpenExistentialExpr(OpenExistentialExpr *E, SGFContext C);
RValue visitMakeTemporarilyEscapableExpr(
MakeTemporarilyEscapableExpr *E, SGFContext C);
RValue visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C);
RValue visitInOutToPointerExpr(InOutToPointerExpr *E, SGFContext C);
RValue visitArrayToPointerExpr(ArrayToPointerExpr *E, SGFContext C);
RValue visitStringToPointerExpr(StringToPointerExpr *E, SGFContext C);
RValue visitPointerToPointerExpr(PointerToPointerExpr *E, SGFContext C);
RValue visitForeignObjectConversionExpr(ForeignObjectConversionExpr *E,
SGFContext C);
RValue visitUnevaluatedInstanceExpr(UnevaluatedInstanceExpr *E,
SGFContext C);
};
} // end anonymous namespace
RValue RValueEmitter::visitApplyExpr(ApplyExpr *E, SGFContext C) {
return SGF.emitApplyExpr(E, C);
}
SILValue SILGenFunction::emitEmptyTuple(SILLocation loc) {
return B.createTuple(loc,
getLoweredType(TupleType::getEmpty(SGM.M.getASTContext())), {});
}
/// Emit the specified declaration as an address if possible,
/// otherwise return null.
ManagedValue SILGenFunction::emitLValueForDecl(SILLocation loc, VarDecl *var,
CanType formalRValueType,
AccessKind accessKind,
AccessSemantics semantics) {
// For local decls, use the address we allocated or the value if we have it.
auto It = VarLocs.find(var);
if (It != VarLocs.end()) {
// If this has an address, return it. By-value let's have no address.
SILValue ptr = It->second.value;
if (ptr->getType().isAddress())
return ManagedValue::forLValue(ptr);
// Otherwise, it is an RValue let.
return ManagedValue();
}
switch (var->getAccessStrategy(semantics, accessKind)) {
case AccessStrategy::Storage:
// The only kind of stored variable that should make it to here is
// a global variable. Just invoke its accessor function to get its
// address.
return emitGlobalVariableRef(loc, var);
case AccessStrategy::Addressor: {
LValue lvalue =
emitLValueForAddressedNonMemberVarDecl(loc, var, formalRValueType,
accessKind, semantics);
return emitAddressOfLValue(loc, std::move(lvalue), accessKind);
}
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor:
return ManagedValue();
case AccessStrategy::BehaviorStorage:
// TODO: Behaviors aren't supported on non-instance properties yet.
llvm_unreachable("not implemented");
}
llvm_unreachable("bad access strategy");
}
namespace {
/// This is a simple cleanup class that is only meant to help with delegating
/// initializers. Specifically, if the delegating initializer fails to consume
/// the loaded self, we want to write back self into the slot to ensure that
/// ownership is preserved.
struct DelegateInitSelfWritebackCleanup : Cleanup {
/// We store our own loc so that we can ensure that DI ignores our writeback.
SILLocation loc;
SILValue lvalueAddress;
SILValue value;
DelegateInitSelfWritebackCleanup(SILLocation loc, SILValue lvalueAddress,
SILValue value)
: loc(loc), lvalueAddress(lvalueAddress), value(value) {}
void emit(SILGenFunction &gen, CleanupLocation) override {
gen.emitSemanticStore(loc, value, lvalueAddress,
gen.getTypeLowering(lvalueAddress->getType()),
IsInitialization);
}
void dump(SILGenFunction &gen) const override {
#ifndef NDEBUG
llvm::errs() << "SimpleWritebackCleanup "
<< "State:" << getState() << "\n"
<< "lvalueAddress:" << lvalueAddress << "value:" << value
<< "\n";
#endif
}
};
} // end anonymous namespace
CleanupHandle SILGenFunction::enterDelegateInitSelfWritebackCleanup(
SILLocation loc, SILValue address, SILValue newValue) {
Cleanups.pushCleanup<DelegateInitSelfWritebackCleanup>(loc, address,
newValue);
return Cleanups.getTopCleanup();
}
RValue SILGenFunction::emitRValueForSelfInDelegationInit(SILLocation loc,
CanType refType,
SILValue addr,
SGFContext C) {
assert(SelfInitDelegationState != SILGenFunction::NormalSelf &&
"This should never be called unless we are in a delegation sequence");
assert(getTypeLowering(addr->getType()).isLoadable() &&
"Make sure that we are not dealing with semantic rvalues");
// If we are currently in the WillSharedBorrowSelf state, then we know that
// old self is not the self to our delegating initializer. Self in this case
// to the delegating initializer is a metatype. Thus, we perform a
// load_borrow. And move from WillSharedBorrowSelf -> DidSharedBorrowSelf.
if (SelfInitDelegationState == SILGenFunction::WillSharedBorrowSelf) {
SelfInitDelegationState = SILGenFunction::DidSharedBorrowSelf;
ManagedValue result =
B.createFormalAccessLoadBorrow(loc, ManagedValue::forUnmanaged(addr));
return RValue(*this, loc, refType, result);
}
// If we are already in the did shared borrow self state, just return the
// shared borrow value.
if (SelfInitDelegationState == SILGenFunction::DidSharedBorrowSelf) {
ManagedValue result =
B.createFormalAccessLoadBorrow(loc, ManagedValue::forUnmanaged(addr));
return RValue(*this, loc, refType, result);
}
// If we are in WillExclusiveBorrowSelf, then we need to perform an exclusive
// borrow (i.e. a load take) and then move to DidExclusiveBorrowSelf.
if (SelfInitDelegationState == SILGenFunction::WillExclusiveBorrowSelf) {
const auto &typeLowering = getTypeLowering(addr->getType());
SelfInitDelegationState = SILGenFunction::DidExclusiveBorrowSelf;
SILValue self =
emitLoad(loc, addr, typeLowering, C, IsTake, false).forward(*this);
// Forward our initial value for init delegation self and create a new
// cleanup that performs a writeback at the end of lexical scope if our
// value is not consumed.
InitDelegationSelf = ManagedValue(
self, enterDelegateInitSelfWritebackCleanup(*InitDelegationLoc, addr, self));
InitDelegationSelfBox = addr;
return RValue(*this, loc, refType, InitDelegationSelf);
}
// If we hit this point, we must have DidExclusiveBorrowSelf. Thus borrow
// self.
assert(SelfInitDelegationState == SILGenFunction::DidExclusiveBorrowSelf);
// If we do not have a super init delegation self, just perform a formal
// access borrow and return. This occurs with delegating initializers.
if (!SuperInitDelegationSelf) {
return RValue(*this, loc, refType,
InitDelegationSelf.formalAccessBorrow(*this, loc));
}
// Otherwise, we had an upcast of some sort due to a chaining
// initializer. This means that we need to perform a borrow from
// SuperInitDelegationSelf and then downcast that borrow.
ManagedValue borrowedUpcast =
SuperInitDelegationSelf.formalAccessBorrow(*this, loc);
SILValue castedBorrowedType = B.createUncheckedRefCast(
loc, borrowedUpcast.getValue(), InitDelegationSelf.getType());
return RValue(*this, loc, refType,
ManagedValue::forUnmanaged(castedBorrowedType));
}
RValue SILGenFunction::
emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType,
AccessSemantics semantics, SGFContext C) {
assert(!ncRefType->is<LValueType>() &&
"RValueEmitter shouldn't be called on lvalues");
// Any writebacks for this access are tightly scoped.
FormalEvaluationScope scope(*this);
// If this is a decl that we have an lvalue for, produce and return it.
ValueDecl *decl = declRef.getDecl();
if (!ncRefType) {
ncRefType = decl->getInnermostDeclContext()->mapTypeIntoContext(
decl->getInterfaceType());
}
CanType refType = ncRefType->getCanonicalType();
auto getUnmanagedRValue = [&](SILValue value) -> RValue {
return RValue(*this, loc, refType, ManagedValue::forUnmanaged(value));
};
// If this is a reference to a module, produce an undef value. The
// module value should never actually be used.
if (isa<ModuleDecl>(decl)) {
return getUnmanagedRValue(
SILUndef::get(getLoweredLoadableType(ncRefType), SGM.M));
}
// If this is a reference to a type, produce a metatype.
if (isa<TypeDecl>(decl)) {
assert(refType->is<MetatypeType>() &&
"type declref does not have metatype type?!");
return getUnmanagedRValue(B.createMetatype(loc, getLoweredType(refType)));
}
// If this is a reference to a var, produce an address or value.
if (auto *var = dyn_cast<VarDecl>(decl)) {
assert(!declRef.isSpecialized() &&
"Cannot handle specialized variable references");
// If this VarDecl is represented as an address, emit it as an lvalue, then
// perform a load to get the rvalue.
if (ManagedValue result =
emitLValueForDecl(loc, var, refType, AccessKind::Read, semantics)) {
bool guaranteedValid = false;
IsTake_t shouldTake = IsNotTake;
// We should only end up in this path for local and global variables,
// i.e. ones whose lifetime is assured for the duration of the evaluation.
// Therefore, if the variable is a constant, the value is guaranteed
// valid as well.
if (var->isLet())
guaranteedValid = true;
// If we have self, see if we are in an 'init' delegation sequence. If so,
// call out to the special delegation init routine. Otherwise, use the
// normal RValue emission logic.
if (var->getName() == getASTContext().Id_self &&
SelfInitDelegationState != NormalSelf) {
return emitRValueForSelfInDelegationInit(loc, refType,
result.getLValueAddress(), C);
}
return RValue(*this, loc, refType,
emitLoad(loc, result.getLValueAddress(),
getTypeLowering(refType), C, shouldTake,
guaranteedValid));
}
// For local decls, use the address we allocated or the value if we have it.
auto It = VarLocs.find(decl);
if (It != VarLocs.end()) {
// Mutable lvalue and address-only 'let's are LValues.
assert(!It->second.value->getType().isAddress() &&
"LValue cases should be handled above");
SILValue Scalar = It->second.value;
// For weak and unowned types, convert the reference to the right
// pointer.
if (Scalar->getType().is<ReferenceStorageType>()) {
Scalar = emitConversionToSemanticRValue(loc, Scalar,
getTypeLowering(refType));
// emitConversionToSemanticRValue always produces a +1 strong result.
return RValue(*this, loc,
refType, emitManagedRValueWithCleanup(Scalar));
}
// This is a let, so we can make guarantees, so begin the borrow scope.
ManagedValue Result = emitManagedBeginBorrow(loc, Scalar);
// If the client can't handle a +0 result, retain it to get a +1.
// This is a 'let', so we can make guarantees.
return RValue(*this, loc, refType,
C.isGuaranteedPlusZeroOk()
? Result : Result.copyUnmanaged(*this, loc));
}
assert(var->hasAccessorFunctions() && "Unknown rvalue case");
bool isDirectAccessorUse = (semantics == AccessSemantics::DirectToAccessor);
SILDeclRef getter = getGetterDeclRef(var, isDirectAccessorUse);
ArgumentSource selfSource;
// Global properties have no base or subscript. Static properties
// use the metatype as their base.
// FIXME: This has to be dynamically looked up for classes, and
// dynamically instantiated for generics.
if (var->isStatic()) {
auto baseTy = cast<NominalTypeDecl>(var->getDeclContext())
->getDeclaredInterfaceType();
assert(!baseTy->is<BoundGenericType>() &&
"generic static stored properties not implemented");
assert((baseTy->getStructOrBoundGenericStruct() ||
baseTy->getEnumOrBoundGenericEnum()) &&
"static stored properties for classes/protocols not implemented");
auto baseMeta = MetatypeType::get(baseTy)->getCanonicalType();
auto metatype = B.createMetatype(loc,
getLoweredLoadableType(baseMeta));
auto metatypeMV = ManagedValue::forUnmanaged(metatype);
auto metatypeRV = RValue(*this, loc, baseMeta, metatypeMV);
selfSource = ArgumentSource(loc, std::move(metatypeRV));
}
return emitGetAccessor(loc, getter,
SGM.getNonMemberVarDeclSubstitutions(var),
std::move(selfSource),
/*isSuper=*/false, isDirectAccessorUse,
RValue(), C);
}
// If the referenced decl isn't a VarDecl, it should be a constant of some
// sort.
// If the referenced decl is a local func with context, then the SILDeclRef
// uncurry level is one deeper (for the context vars).
bool hasLocalCaptures = false;
unsigned uncurryLevel = 0;
if (auto *fd = dyn_cast<FuncDecl>(decl)) {
hasLocalCaptures = SGM.M.Types.hasLoweredLocalCaptures(fd);
if (hasLocalCaptures)
++uncurryLevel;
}
auto silDeclRef = SILDeclRef(decl, ResilienceExpansion::Minimal, uncurryLevel);
ManagedValue result = emitClosureValue(loc, silDeclRef, refType,
declRef.getSubstitutions());
return RValue(*this, loc, refType, result);
}
static AbstractionPattern
getOrigFormalRValueType(SILGenFunction &gen, VarDecl *field) {
auto origType = gen.SGM.Types.getAbstractionPattern(field);
return origType.getReferenceStorageReferentType();
}
static SILDeclRef getRValueAccessorDeclRef(SILGenFunction &SGF,
AbstractStorageDecl *storage,
AccessStrategy strategy) {
switch (strategy) {
case AccessStrategy::BehaviorStorage:
llvm_unreachable("shouldn't load an rvalue via behavior storage!");
case AccessStrategy::Storage:
llvm_unreachable("should already have been filtered out!");
case AccessStrategy::DirectToAccessor:
return SGF.getGetterDeclRef(storage, true);
case AccessStrategy::DispatchToAccessor:
return SGF.getGetterDeclRef(storage, false);
case AccessStrategy::Addressor:
return SGF.getAddressorDeclRef(storage, AccessKind::Read,
/*always direct for now*/ true);
}
llvm_unreachable("should already have been filtered out!");
}
static RValue
emitRValueWithAccessor(SILGenFunction &SGF, SILLocation loc,
AbstractStorageDecl *storage,
SubstitutionList substitutions,
ArgumentSource &&baseRV, RValue &&subscriptRV,
bool isSuper, AccessStrategy strategy,
SILDeclRef accessor,
AbstractionPattern origFormalType,
CanType substFormalType,
SGFContext C) {
bool isDirectUse = (strategy == AccessStrategy::DirectToAccessor);
switch (strategy) {
case AccessStrategy::BehaviorStorage:
llvm_unreachable("shouldn't load an rvalue via behavior storage!");
case AccessStrategy::Storage:
llvm_unreachable("should already have been filtered out!");
// The easy path here is if we don't need to use an addressor.
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor: {
return SGF.emitGetAccessor(loc, accessor, substitutions,
std::move(baseRV), isSuper, isDirectUse,
std::move(subscriptRV), C);
}
case AccessStrategy::Addressor:
break;
}
auto &storageTL = SGF.getTypeLowering(origFormalType, substFormalType);
SILType storageType = storageTL.getLoweredType().getAddressType();
auto addressorResult =
SGF.emitAddressorAccessor(loc, accessor, substitutions,
std::move(baseRV), isSuper, isDirectUse,
std::move(subscriptRV), storageType);
SILValue address = addressorResult.first.getLValueAddress();
SILType loweredSubstType =
SGF.getLoweredType(substFormalType).getAddressType();
bool hasAbstraction = (loweredSubstType != storageType);
RValue result(SGF, loc, substFormalType,
SGF.emitLoad(loc, address, storageTL,
(hasAbstraction ? SGFContext() : C), IsNotTake));
if (hasAbstraction) {
result = SGF.emitOrigToSubstValue(loc, std::move(result), origFormalType,
substFormalType, C);
}
switch (cast<FuncDecl>(accessor.getDecl())->getAddressorKind()) {
case AddressorKind::NotAddressor: llvm_unreachable("inconsistent");
case AddressorKind::Unsafe:
// Nothing to do.
break;
case AddressorKind::Owning:
case AddressorKind::NativeOwning:
// Emit the release immediately.
SGF.B.emitDestroyValueOperation(loc, addressorResult.second.forward(SGF));
break;
case AddressorKind::NativePinning:
// Emit the unpin immediately.
SGF.B.createStrongUnpin(loc, addressorResult.second.forward(SGF),
SGF.B.getDefaultAtomicity());
break;
}
return result;
}
/// Produce a singular RValue for a load from the specified property. This
/// is designed to work with RValue ManagedValue bases that are either +0 or +1.
RValue SILGenFunction::emitRValueForPropertyLoad(
SILLocation loc, ManagedValue base, CanType baseFormalType,
bool isSuper, VarDecl *field, SubstitutionList substitutions,
AccessSemantics semantics, Type propTy, SGFContext C,
bool isGuaranteedValid) {
AccessStrategy strategy =
field->getAccessStrategy(semantics, AccessKind::Read);
// If we should call an accessor of some kind, do so.
if (strategy != AccessStrategy::Storage) {
auto accessor = getRValueAccessorDeclRef(*this, field, strategy);
ArgumentSource baseRV = prepareAccessorBaseArg(loc, base,
baseFormalType,
accessor);
AbstractionPattern origFormalType =
getOrigFormalRValueType(*this, field);
auto substFormalType = propTy->getCanonicalType();
return emitRValueWithAccessor(*this, loc, field, substitutions,
std::move(baseRV), RValue(),
isSuper, strategy, accessor,
origFormalType, substFormalType, C);
}
assert(field->hasStorage() &&
"Cannot directly access value without storage");
// For static variables, emit a reference to the global variable backing
// them.
// FIXME: This has to be dynamically looked up for classes, and
// dynamically instantiated for generics.
if (field->isStatic()) {
auto baseMeta = base.getType().castTo<MetatypeType>().getInstanceType();
(void)baseMeta;
assert(!baseMeta->is<BoundGenericType>() &&
"generic static stored properties not implemented");
if (field->getDeclContext()->getAsClassOrClassExtensionContext() &&
field->hasStorage())
// FIXME: don't need to check hasStorage, already done above
assert(field->isFinal() && "non-final class stored properties not implemented");
return emitRValueForDecl(loc, field, propTy, semantics, C);
}
// rvalue MemberRefExprs are produced in two cases: when accessing a 'let'
// decl member, and when the base is a (non-lvalue) struct.
assert(baseFormalType->getAnyNominal() &&
base.getType().getSwiftRValueType()->getAnyNominal() &&
"The base of an rvalue MemberRefExpr should be an rvalue value");
// If the accessed field is stored, emit a StructExtract on the base.
auto substFormalType = propTy->getCanonicalType();
auto &lowering = getTypeLowering(substFormalType);
// Check for an abstraction difference.
AbstractionPattern origFormalType = getOrigFormalRValueType(*this, field);
bool hasAbstractionChange = false;
auto &abstractedTL = getTypeLowering(origFormalType, substFormalType);
if (!origFormalType.isExactType(substFormalType)) {
hasAbstractionChange =
(abstractedTL.getLoweredType() != lowering.getLoweredType());
}
// If the base is a reference type, just handle this as loading the lvalue.
if (baseFormalType->hasReferenceSemantics()) {
LValue LV = emitPropertyLValue(loc, base, baseFormalType, field,
AccessKind::Read,
AccessSemantics::DirectToStorage);
return emitLoadOfLValue(loc, std::move(LV), C, isGuaranteedValid);
}
ManagedValue result;
if (!base.getType().isAddress()) {
// For non-address-only structs, we emit a struct_extract sequence.
result = B.createStructExtract(loc, base, field);
if (result.getType().is<ReferenceStorageType>()) {
// For weak and unowned types, convert the reference to the right
// pointer, producing a +1.
result = emitConversionToSemanticRValue(loc, result, lowering);
} else if (hasAbstractionChange ||
(!C.isImmediatePlusZeroOk() &&
!(C.isGuaranteedPlusZeroOk() && isGuaranteedValid))) {
// If we have an abstraction change or if we have to produce a result at
// +1, then emit a RetainValue. If we know that our base will stay alive,
// we can emit at +0 for a guaranteed consumer. Otherwise, since we do not
// have enough information, we can only emit at +0 for immediate clients.
result = result.copyUnmanaged(*this, loc);
}
} else {
// For address-only sequences, the base is in memory. Emit a
// struct_element_addr to get to the field, and then load the element as an
// rvalue.
SILValue ElementPtr =
B.createStructElementAddr(loc, base.getValue(), field);
result = emitLoad(loc, ElementPtr, abstractedTL,
hasAbstractionChange ? SGFContext() : C, IsNotTake);
}
// If we're accessing this member with an abstraction change, perform that
// now.
if (hasAbstractionChange)
result =
emitOrigToSubstValue(loc, result, origFormalType, substFormalType, C);
return RValue(*this, loc, substFormalType, result);
}
RValue RValueEmitter::visitDeclRefExpr(DeclRefExpr *E, SGFContext C) {
return SGF.emitRValueForDecl(E, E->getDeclRef(), E->getType(),
E->getAccessSemantics(), C);
}
RValue RValueEmitter::visitTypeExpr(TypeExpr *E, SGFContext C) {
assert(E->getType()->is<AnyMetatypeType>() &&
"TypeExpr must have metatype type");
auto Val = SGF.B.createMetatype(E, SGF.getLoweredType(E->getType()));
return RValue(SGF, E, ManagedValue::forUnmanaged(Val));
}
RValue RValueEmitter::visitSuperRefExpr(SuperRefExpr *E, SGFContext C) {
assert(!E->getType()->is<LValueType>() &&
"RValueEmitter shouldn't be called on lvalues");
// If we have a normal self call, then use the emitRValueForDecl call. This
// will emit self at +0 since it is guaranteed.
ManagedValue Self =
SGF.emitRValueForDecl(E, E->getSelf(), E->getSelf()->getType(),
AccessSemantics::Ordinary)
.getScalarValue();
// Perform an upcast to convert self to the indicated super type.
auto Result = SGF.B.createUpcast(E, Self.getValue(),
SGF.getLoweredType(E->getType()));
return RValue(SGF, E, ManagedValue(Result, Self.getCleanup()));
}
RValue RValueEmitter::
visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E,
SGFContext C) {
llvm_unreachable("invalid code made its way into SILGen");
}
RValue RValueEmitter::visitOtherConstructorDeclRefExpr(
OtherConstructorDeclRefExpr *E, SGFContext C) {
// This should always be a child of an ApplyExpr and so will be emitted by
// SILGenApply.
llvm_unreachable("unapplied reference to constructor?!");
}
RValue RValueEmitter::visitNilLiteralExpr(NilLiteralExpr *E, SGFContext C) {
llvm_unreachable("NilLiteralExpr not lowered?");
}
RValue RValueEmitter::visitIntegerLiteralExpr(IntegerLiteralExpr *E,
SGFContext C) {
return RValue(SGF, E,
ManagedValue::forUnmanaged(SGF.B.createIntegerLiteral(E)));
}
RValue RValueEmitter::visitFloatLiteralExpr(FloatLiteralExpr *E,
SGFContext C) {
return RValue(SGF, E,
ManagedValue::forUnmanaged(SGF.B.createFloatLiteral(E)));
}
RValue RValueEmitter::visitBooleanLiteralExpr(BooleanLiteralExpr *E,
SGFContext C) {
auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext());
SILValue boolValue = SGF.B.createIntegerLiteral(E, i1Ty, E->getValue());
return RValue(SGF, E, ManagedValue::forUnmanaged(boolValue));
}
RValue RValueEmitter::visitStringLiteralExpr(StringLiteralExpr *E,
SGFContext C) {
return SGF.emitLiteral(E, C);
}
RValue RValueEmitter::visitLoadExpr(LoadExpr *E, SGFContext C) {
// Any writebacks here are tightly scoped.
FormalEvaluationScope writeback(SGF);
LValue lv = SGF.emitLValue(E->getSubExpr(), AccessKind::Read);
return SGF.emitLoadOfLValue(E, std::move(lv), C);
}
SILValue SILGenFunction::emitTemporaryAllocation(SILLocation loc,
SILType ty) {
ty = ty.getObjectType();
auto alloc = B.createAllocStack(loc, ty);
enterDeallocStackCleanup(alloc);
return alloc;
}
SILValue SILGenFunction::
getBufferForExprResult(SILLocation loc, SILType ty, SGFContext C) {
// If you change this, change manageBufferForExprResult below as well.
// If we have a single-buffer "emit into" initialization, use that for the
// result.
if (SILValue address = C.getAddressForInPlaceInitialization(*this, loc))
return address;
// If we couldn't emit into the Initialization, emit into a temporary
// allocation.
return emitTemporaryAllocation(loc, ty.getObjectType());
}
ManagedValue SILGenFunction::
manageBufferForExprResult(SILValue buffer, const TypeLowering &bufferTL,
SGFContext C) {
// If we have a single-buffer "emit into" initialization, use that for the
// result.
if (C.finishInPlaceInitialization(*this))
return ManagedValue::forInContext();
// Add a cleanup for the temporary we allocated.
if (bufferTL.isTrivial())
return ManagedValue::forUnmanaged(buffer);
return ManagedValue(buffer, enterDestroyCleanup(buffer));
}
SILGenFunction::ForceTryEmission::ForceTryEmission(SILGenFunction &SGF,
Expr *loc)
: SGF(SGF), Loc(loc), OldThrowDest(SGF.ThrowDest) {
assert(loc && "cannot pass a null location");
// Set up a "catch" block for when an error occurs.
SILBasicBlock *catchBB = SGF.createBasicBlock(FunctionSection::Postmatter);
SGF.ThrowDest = JumpDest(catchBB, SGF.Cleanups.getCleanupsDepth(),
CleanupLocation::get(loc));
}
void SILGenFunction::ForceTryEmission::finish() {
assert(Loc && "emission already finished");
auto catchBB = SGF.ThrowDest.getBlock();
SGF.ThrowDest = OldThrowDest;
// If there are no uses of the catch block, just drop it.
if (catchBB->pred_empty()) {
SGF.eraseBasicBlock(catchBB);
} else {
// Otherwise, we need to emit it.
SavedInsertionPoint scope(SGF, catchBB, FunctionSection::Postmatter);
ASTContext &ctx = SGF.getASTContext();
auto error = catchBB->createPHIArgument(SILType::getExceptionType(ctx),
ValueOwnershipKind::Owned);
SGF.B.createBuiltin(Loc, ctx.getIdentifier("unexpectedError"),
SGF.SGM.Types.getEmptyTupleType(), {}, {error});
SGF.B.createUnreachable(Loc);
}
// Prevent double-finishing and make the destructor a no-op.
Loc = nullptr;
}
RValue RValueEmitter::visitForceTryExpr(ForceTryExpr *E, SGFContext C) {
SILGenFunction::ForceTryEmission emission(SGF, E);
// Visit the sub-expression.
return visit(E->getSubExpr(), C);
}
RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
// FIXME: Much of this was copied from visitOptionalEvaluationExpr.
auto &optTL = SGF.getTypeLowering(E->getType());
Initialization *optInit = C.getEmitInto();
bool usingProvidedContext =
optInit && optInit->canPerformInPlaceInitialization();
// Form the optional using address operations if the type is address-only or
// if we already have an address to use.
bool isByAddress = usingProvidedContext || optTL.isAddressOnly();
std::unique_ptr<TemporaryInitialization> optTemp;
if (!usingProvidedContext && isByAddress) {
// Allocate the temporary for the Optional<T> if we didn't get one from the
// context.
optTemp = SGF.emitTemporary(E, optTL);
optInit = optTemp.get();
} else if (!usingProvidedContext) {
// If the caller produced a context for us, but we can't use it, then don't.
optInit = nullptr;
}
FullExpr localCleanups(SGF.Cleanups, E);
// Set up a "catch" block for when an error occurs.
SILBasicBlock *catchBB = SGF.createBasicBlock(FunctionSection::Postmatter);
llvm::SaveAndRestore<JumpDest> throwDest{
SGF.ThrowDest,
JumpDest(catchBB, SGF.Cleanups.getCleanupsDepth(), E)};
SILValue branchArg;
if (isByAddress) {
assert(optInit);
SILValue optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
SGF.emitInjectOptionalValueInto(E, E->getSubExpr(), optAddr, optTL);
} else {
ManagedValue subExprValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
ManagedValue wrapped = SGF.getOptionalSomeValue(E, subExprValue, optTL);
branchArg = wrapped.forward(SGF);
}
localCleanups.pop();
// If it turns out there are no uses of the catch block, just drop it.
if (catchBB->pred_empty()) {
// Remove the dead failureBB.
catchBB->eraseFromParent();
// The value we provide is the one we've already got.
if (!isByAddress)
return RValue(SGF, E,
SGF.emitManagedRValueWithCleanup(branchArg, optTL));
optInit->finishInitialization(SGF);
// If we emitted into the provided context, we're done.
if (usingProvidedContext)
return RValue();
return RValue(SGF, E, optTemp->getManagedAddress());
}
SILBasicBlock *contBB = SGF.createBasicBlock();
// Branch to the continuation block.
if (isByAddress)
SGF.B.createBranch(E, contBB);
else
SGF.B.createBranch(E, contBB, branchArg);
// If control branched to the failure block, inject .None into the
// result type.
SGF.B.emitBlock(catchBB);
FullExpr catchCleanups(SGF.Cleanups, E);
auto *errorArg =
catchBB->createPHIArgument(SILType::getExceptionType(SGF.getASTContext()),
ValueOwnershipKind::Owned);
(void) SGF.emitManagedRValueWithCleanup(errorArg);
catchCleanups.pop();
if (isByAddress) {
SGF.emitInjectOptionalNothingInto(E,
optInit->getAddressForInPlaceInitialization(SGF, E), optTL);
SGF.B.createBranch(E, contBB);
} else {
auto branchArg = SGF.getOptionalNoneValue(E, optTL);
SGF.B.createBranch(E, contBB, branchArg);
}
// Emit the continuation block.
SGF.B.emitBlock(contBB);
// If this was done in SSA registers, then the value is provided as an
// argument to the block.
if (!isByAddress) {
auto arg = contBB->createPHIArgument(optTL.getLoweredType(),
ValueOwnershipKind::Owned);
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(arg, optTL));
}
optInit->finishInitialization(SGF);
// If we emitted into the provided context, we're done.
if (usingProvidedContext)
return RValue();
assert(optTemp);
return RValue(SGF, E, optTemp->getManagedAddress());
}
RValue RValueEmitter::visitDerivedToBaseExpr(DerivedToBaseExpr *E,
SGFContext C) {
ManagedValue original = SGF.emitRValueAsSingleValue(E->getSubExpr());
// Derived-to-base casts in the AST might not be reflected as such
// in the SIL type system, for example, a cast from DynamicSelf
// directly to its own Self type.
auto loweredResultTy = SGF.getLoweredType(E->getType());
if (original.getType() == loweredResultTy)
return RValue(SGF, E, original);
ManagedValue converted = SGF.B.createUpcast(E, original, loweredResultTy);
return RValue(SGF, E, converted);
}
RValue RValueEmitter::visitMetatypeConversionExpr(MetatypeConversionExpr *E,
SGFContext C) {
SILValue metaBase =
SGF.emitRValueAsSingleValue(E->getSubExpr()).getUnmanagedValue();
// Metatype conversion casts in the AST might not be reflected as
// such in the SIL type system, for example, a cast from DynamicSelf.Type
// directly to its own Self.Type.
auto loweredResultTy = SGF.getLoweredLoadableType(E->getType());
if (metaBase->getType() == loweredResultTy)
return RValue(SGF, E, ManagedValue::forUnmanaged(metaBase));
auto upcast = SGF.B.createUpcast(E, metaBase, loweredResultTy);
return RValue(SGF, E, ManagedValue::forUnmanaged(upcast));
}
RValue SILGenFunction::emitCollectionConversion(SILLocation loc,
FuncDecl *fn,
CanType fromCollection,
CanType toCollection,
ManagedValue mv,
SGFContext C) {
auto *fromDecl = fromCollection->getAnyNominal();
auto *toDecl = toCollection->getAnyNominal();
auto fromSubMap = fromCollection->getContextSubstitutionMap(
SGM.SwiftModule, fromDecl);
auto toSubMap = toCollection->getContextSubstitutionMap(
SGM.SwiftModule, toDecl);
// Form type parameter substitutions.
auto *genericSig = fn->getGenericSignature();
unsigned fromParamCount = fromDecl->getGenericSignature()
->getGenericParams().size();
auto subMap =
SubstitutionMap::combineSubstitutionMaps(fromSubMap,
toSubMap,
CombineSubstitutionMaps::AtIndex,
fromParamCount,
0,
genericSig);
return emitApplyOfLibraryIntrinsic(loc, fn, subMap, {mv}, C);
}
RValue RValueEmitter::
visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E,
SGFContext C) {
SILLocation loc = RegularLocation(E);
// Get the sub expression argument as a managed value
auto mv = SGF.emitRValueAsSingleValue(E->getSubExpr());
// Compute substitutions for the intrinsic call.
auto fromCollection = E->getSubExpr()->getType()->getCanonicalType();
auto toCollection = E->getType()->getCanonicalType();
// Get the intrinsic function.
auto &ctx = SGF.getASTContext();
FuncDecl *fn = nullptr;
if (fromCollection->getAnyNominal() == ctx.getArrayDecl()) {
fn = SGF.SGM.getArrayForceCast(loc);
} else if (fromCollection->getAnyNominal() == ctx.getDictionaryDecl()) {
fn = SGF.SGM.getDictionaryUpCast(loc);
} else if (fromCollection->getAnyNominal() == ctx.getSetDecl()) {
fn = SGF.SGM.getSetUpCast(loc);
} else {
llvm_unreachable("unsupported collection upcast kind");
}
return SGF.emitCollectionConversion(loc, fn, fromCollection, toCollection,
mv, C);
}
RValue RValueEmitter::visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E,
SGFContext C) {
ManagedValue archetype = SGF.emitRValueAsSingleValue(E->getSubExpr());
// Replace the cleanup with a new one on the superclass value so we always use
// concrete retain/release operations.
SILValue base = SGF.B.createUpcast(E,
archetype.forward(SGF),
SGF.getLoweredLoadableType(E->getType()));
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(base));
}
static ManagedValue convertCFunctionSignature(SILGenFunction &SGF,
FunctionConversionExpr *e,
SILType loweredResultTy,
llvm::function_ref<ManagedValue ()> fnEmitter) {
SILType loweredDestTy = SGF.getLoweredType(e->getType());
ManagedValue result;
// We're converting between C function pointer types. They better be
// ABI-compatible, since we can't emit a thunk.
switch (SGF.SGM.Types.checkForABIDifferences(loweredResultTy, loweredDestTy)){
case TypeConverter::ABIDifference::Trivial:
result = fnEmitter();
assert(result.getType() == loweredResultTy);
if (loweredResultTy != loweredDestTy) {
result = ManagedValue::forUnmanaged(
SGF.B.createConvertFunction(e, result.getUnmanagedValue(),
loweredDestTy));
}
break;
case TypeConverter::ABIDifference::NeedsThunk:
// Note: in this case, we don't call the emitter at all -- doing so
// just runs the risk of tripping up asserts in SILGenBridging.cpp
SGF.SGM.diagnose(e, diag::unsupported_c_function_pointer_conversion,
e->getSubExpr()->getType(), e->getType());
result = SGF.emitUndef(e, loweredDestTy);
break;
case TypeConverter::ABIDifference::ThinToThick:
llvm_unreachable("Cannot have thin to thick conversion here");
}
return result;
}
static
ManagedValue emitCFunctionPointer(SILGenFunction &gen,
FunctionConversionExpr *conversionExpr) {
auto expr = conversionExpr->getSubExpr();
// Look through base-ignored exprs to get to the function ref.
auto semanticExpr = expr->getSemanticsProvidingExpr();
while (auto ignoredBase = dyn_cast<DotSyntaxBaseIgnoredExpr>(semanticExpr)){
gen.emitIgnoredExpr(ignoredBase->getLHS());
semanticExpr = ignoredBase->getRHS()->getSemanticsProvidingExpr();
}
// Recover the decl reference.
SILDeclRef::Loc loc;
auto setLocFromConcreteDeclRef = [&](ConcreteDeclRef declRef) {
// TODO: Handle generic instantiations, where we need to eagerly specialize
// on the given generic parameters, and static methods, where we need to drop
// in the metatype.
assert(!declRef.getDecl()->getDeclContext()->isTypeContext()
&& "c pointers to static methods not implemented");
assert(declRef.getSubstitutions().empty()
&& "c pointers to generics not implemented");
loc = declRef.getDecl();
};
if (auto declRef = dyn_cast<DeclRefExpr>(semanticExpr)) {
setLocFromConcreteDeclRef(declRef->getDeclRef());
} else if (auto memberRef = dyn_cast<MemberRefExpr>(semanticExpr)) {
setLocFromConcreteDeclRef(memberRef->getMember());
} else if (auto closure = dyn_cast<AbstractClosureExpr>(semanticExpr)) {
loc = closure;
// Emit the closure body.
gen.SGM.emitClosure(closure);
} else {
llvm_unreachable("c function pointer converted from a non-concrete decl ref");
}
// Produce a reference to the C-compatible entry point for the function.
SILDeclRef constant(loc, ResilienceExpansion::Minimal,
/*uncurryLevel*/ 0,
/*foreign*/ true);
SILConstantInfo constantInfo = gen.getConstantInfo(constant);
return convertCFunctionSignature(
gen, conversionExpr,
constantInfo.getSILType(),
[&]() -> ManagedValue {
SILValue cRef = gen.emitGlobalFunctionRef(expr, constant);
return ManagedValue::forUnmanaged(cRef);
});
}
// Change the representation without changing the signature or
// abstraction level.
static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
SILLocation loc,
ManagedValue result,
CanAnyFunctionType srcTy,
CanAnyFunctionType destTy) {
auto resultFTy = result.getType().castTo<SILFunctionType>();
// Note that conversions to and from block require a thunk
switch (destTy->getRepresentation()) {
// Convert thin, c, block => thick
case AnyFunctionType::Representation::Swift: {
switch (resultFTy->getRepresentation()) {
case SILFunctionType::Representation::Thin: {
auto v = SGF.B.createThinToThickFunction(loc, result.getValue(),
SILType::getPrimitiveObjectType(
adjustFunctionType(resultFTy, SILFunctionType::Representation::Thick)));
result = ManagedValue(v, result.getCleanup());
break;
}
case SILFunctionType::Representation::Thick:
llvm_unreachable("should not try thick-to-thick repr change");
case SILFunctionType::Representation::CFunctionPointer:
case SILFunctionType::Representation::Block:
result = SGF.emitBlockToFunc(loc, result,
SGF.getLoweredType(destTy).castTo<SILFunctionType>());
break;
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::Closure:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::WitnessMethod:
llvm_unreachable("should not do function conversion from method rep");
}
break;
}
// Convert thin, thick, c => block
case AnyFunctionType::Representation::Block:
switch (resultFTy->getRepresentation()) {
case SILFunctionType::Representation::Thin: {
// Make thick first.
auto v = SGF.B.createThinToThickFunction(loc, result.getValue(),
SILType::getPrimitiveObjectType(
adjustFunctionType(resultFTy, SILFunctionType::Representation::Thick)));
result = ManagedValue(v, result.getCleanup());
LLVM_FALLTHROUGH;
}
case SILFunctionType::Representation::Thick:
case SILFunctionType::Representation::CFunctionPointer:
// Convert to a block.
result = SGF.emitFuncToBlock(loc, result,
SGF.getLoweredType(destTy).castTo<SILFunctionType>());
break;
case SILFunctionType::Representation::Block:
llvm_unreachable("should not try block-to-block repr change");
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::Closure:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::WitnessMethod:
llvm_unreachable("should not do function conversion from method rep");
}
break;
// Unsupported
case AnyFunctionType::Representation::Thin:
llvm_unreachable("should not do function conversion to thin");
case AnyFunctionType::Representation::CFunctionPointer:
llvm_unreachable("should not do C function pointer conversion here");
}
return result;
}
RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
SGFContext C)
{
CanAnyFunctionType srcRepTy =
cast<FunctionType>(e->getSubExpr()->getType()->getCanonicalType());
CanAnyFunctionType destRepTy =
cast<FunctionType>(e->getType()->getCanonicalType());
if (destRepTy->getRepresentation() ==
FunctionTypeRepresentation::CFunctionPointer) {
ManagedValue result;
if (srcRepTy->getRepresentation() !=
FunctionTypeRepresentation::CFunctionPointer) {
// A "conversion" of a DeclRef a C function pointer is done by referencing
// the thunk (or original C function) with the C calling convention.
result = emitCFunctionPointer(SGF, e);
} else {
// Ok, we're converting a C function pointer value to another C function
// pointer.
// Emit the C function pointer
result = SGF.emitRValueAsSingleValue(e->getSubExpr());
// Possibly bitcast the C function pointer to account for ABI-compatible
// parameter and result type conversions
result = convertCFunctionSignature(SGF, e, result.getType(),
[&]() -> ManagedValue {
return result;
});
}
return RValue(SGF, e, result);
}
// Handle a reference to a "thin" native Swift function that only changes
// representation and refers to an inherently thin function reference.
if (destRepTy->getRepresentation() == FunctionTypeRepresentation::Thin) {
if (srcRepTy->getRepresentation() == FunctionTypeRepresentation::Swift
&& srcRepTy->withExtInfo(destRepTy->getExtInfo())->isEqual(destRepTy)) {
auto value = SGF.emitRValueAsSingleValue(e->getSubExpr());
auto expectedTy = SGF.getLoweredType(e->getType());
if (auto thinToThick =
dyn_cast<ThinToThickFunctionInst>(value.getValue())) {
value = ManagedValue::forUnmanaged(thinToThick->getOperand());
} else {
SGF.SGM.diagnose(e->getLoc(), diag::not_implemented,
"nontrivial thin function reference");
value = ManagedValue::forUnmanaged(SILUndef::get(expectedTy, SGF.SGM.M));
}
if (value.getType() != expectedTy) {
SGF.SGM.diagnose(e->getLoc(), diag::not_implemented,
"nontrivial thin function reference");
value = ManagedValue::forUnmanaged(SILUndef::get(expectedTy, SGF.SGM.M));
}
return RValue(SGF, e, value);
}
}
// Break the conversion into three stages:
// 1) changing the representation from foreign to native
// 2) changing the signature within the representation
// 3) changing the representation from native to foreign
//
// We only do one of 1) or 3), but we have to do them in the right order
// with respect to 2).
CanAnyFunctionType srcTy = srcRepTy;
CanAnyFunctionType destTy = destRepTy;
switch(srcRepTy->getRepresentation()) {
case AnyFunctionType::Representation::Swift:
case AnyFunctionType::Representation::Thin:
// Source is native, so we can convert signature first.
destTy = adjustFunctionType(destRepTy,
srcTy->getRepresentation());
break;
case AnyFunctionType::Representation::Block:
case AnyFunctionType::Representation::CFunctionPointer:
// Source is foreign, so do the representation change first.
srcTy = adjustFunctionType(srcRepTy,
destRepTy->getRepresentation());
}
auto result = SGF.emitRValueAsSingleValue(e->getSubExpr());
if (srcRepTy != srcTy)
result = convertFunctionRepresentation(SGF, e, result, srcRepTy, srcTy);
if (srcTy != destTy)
result = SGF.emitTransformedValue(e, result, srcTy, destTy);
if (destTy != destRepTy)
result = convertFunctionRepresentation(SGF, e, result, destTy, destRepTy);
return RValue(SGF, e, result);
}
RValue RValueEmitter::visitCovariantFunctionConversionExpr(
CovariantFunctionConversionExpr *e,
SGFContext C) {
ManagedValue original = SGF.emitRValueAsSingleValue(e->getSubExpr());
CanAnyFunctionType destTy
= cast<AnyFunctionType>(e->getType()->getCanonicalType());
SILType resultType = SGF.getLoweredType(destTy);
SILValue result = SGF.B.createConvertFunction(e,
original.forward(SGF),
resultType);
return RValue(SGF, e, SGF.emitManagedRValueWithCleanup(result));
}
static ManagedValue createUnsafeDowncast(SILGenFunction &gen,
SILLocation loc,
ManagedValue input,
SILType resultTy) {
SILValue result = gen.B.createUncheckedRefCast(loc,
input.forward(gen),
resultTy);
return gen.emitManagedRValueWithCleanup(result);
}
RValue RValueEmitter::visitCovariantReturnConversionExpr(
CovariantReturnConversionExpr *e,
SGFContext C) {
SILType resultType = SGF.getLoweredType(e->getType());
ManagedValue original = SGF.emitRValueAsSingleValue(e->getSubExpr());
ManagedValue result;
if (resultType.getSwiftRValueType().getAnyOptionalObjectType()) {
result = SGF.emitOptionalToOptional(e, original, resultType,
createUnsafeDowncast);
} else {
result = createUnsafeDowncast(SGF, e, original, resultType);
}
return RValue(SGF, e, result);
}
RValue RValueEmitter::visitErasureExpr(ErasureExpr *E, SGFContext C) {
auto &existentialTL = SGF.getTypeLowering(E->getType());
auto concreteFormalType = E->getSubExpr()->getType()->getCanonicalType();
auto archetype = ArchetypeType::getAnyOpened(E->getType());
AbstractionPattern abstractionPattern(archetype);
auto &concreteTL = SGF.getTypeLowering(abstractionPattern,
concreteFormalType);
ManagedValue mv = SGF.emitExistentialErasure(E, concreteFormalType,
concreteTL, existentialTL,
E->getConformances(), C,
[&](SGFContext C) -> ManagedValue {
return SGF.emitRValueAsOrig(E->getSubExpr(),
abstractionPattern,
concreteTL, C);
});
return RValue(SGF, E, mv);
}
RValue SILGenFunction::emitAnyHashableErasure(SILLocation loc,
ManagedValue value,
Type type,
ProtocolConformanceRef conformance,
SGFContext C) {
// Ensure that the intrinsic function exists.
auto convertFn = SGM.getConvertToAnyHashable(loc);
if (!convertFn)
return emitUndefRValue(
loc, getASTContext().getAnyHashableDecl()->getDeclaredType());
// Construct the substitution for T: Hashable.
auto subMap = SubstitutionMap::getProtocolSubstitutions(
conformance.getRequirement(), type, conformance);
return emitApplyOfLibraryIntrinsic(loc, convertFn, subMap, value, C);
}
RValue RValueEmitter::visitAnyHashableErasureExpr(AnyHashableErasureExpr *E,
SGFContext C) {
// Emit the source value into a temporary.
auto sourceOrigType = AbstractionPattern::getOpaque();
auto source =
SGF.emitMaterializedRValueAsOrig(E->getSubExpr(), sourceOrigType);
return SGF.emitAnyHashableErasure(E, source,
E->getSubExpr()->getType(),
E->getConformance(), C);
}
/// Treating this as a successful operation, turn a CMV into a +1 MV.
ManagedValue SILGenFunction::getManagedValue(SILLocation loc,
ConsumableManagedValue value) {
// If the consumption rules say that this is already +1 given a
// successful operation, just use the value.
if (value.isOwned())
return value.getFinalManagedValue();
SILType valueTy = value.getType();
auto &valueTL = getTypeLowering(valueTy);
// If the type is trivial, it's always +1.
if (valueTL.isTrivial())
return ManagedValue::forUnmanaged(value.getValue());
// If it's an object...
if (valueTy.isObject()) {
// See if we have more accurate information from the ownership kind. This
// detects trivial cases of enums.
if (value.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(value.getValue());
// Otherwise, retain and enter a release cleanup.
valueTL.emitCopyValue(B, loc, value.getValue());
return emitManagedRValueWithCleanup(value.getValue(), valueTL);
}
// Otherwise, produce a temporary and copy into that.
auto temporary = emitTemporary(loc, valueTL);
valueTL.emitCopyInto(B, loc, value.getValue(), temporary->getAddress(),
IsNotTake, IsInitialization);
temporary->finishInitialization(*this);
return temporary->getManagedAddress();
}
RValue RValueEmitter::visitForcedCheckedCastExpr(ForcedCheckedCastExpr *E,
SGFContext C) {
return emitUnconditionalCheckedCast(SGF, E, E->getSubExpr(), E->getType(),
E->getCastKind(), C);
}
RValue RValueEmitter::
visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *E,
SGFContext C) {
ManagedValue operand = SGF.emitRValueAsSingleValue(E->getSubExpr());
return emitConditionalCheckedCast(SGF, E, operand, E->getSubExpr()->getType(),
E->getType(), E->getCastKind(), C);
}
RValue RValueEmitter::visitIsExpr(IsExpr *E, SGFContext C) {
SILValue isa = emitIsa(SGF, E, E->getSubExpr(),
E->getCastTypeLoc().getType(), E->getCastKind());
// Call the _getBool library intrinsic.
ASTContext &ctx = SGF.getASTContext();
auto result =
SGF.emitApplyOfLibraryIntrinsic(E, ctx.getGetBoolDecl(nullptr),
SubstitutionMap(),
ManagedValue::forUnmanaged(isa),
C);
return result;
}
RValue RValueEmitter::visitEnumIsCaseExpr(EnumIsCaseExpr *E,
SGFContext C) {
ASTContext &ctx = SGF.getASTContext();
// Get the enum value.
auto subExpr = SGF.emitRValueAsSingleValue(E->getSubExpr(),
SGFContext(SGFContext::AllowImmediatePlusZero));
// Test its case.
auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext());
auto t = SGF.B.createIntegerLiteral(E, i1Ty, 1);
auto f = SGF.B.createIntegerLiteral(E, i1Ty, 0);
SILValue selected;
if (subExpr.getType().isAddress()) {
selected = SGF.B.createSelectEnumAddr(E, subExpr.getValue(), i1Ty, f,
{{E->getEnumElement(), t}});
} else {
selected = SGF.B.createSelectEnum(E, subExpr.getValue(), i1Ty, f,
{{E->getEnumElement(), t}});
}
// Call the _getBool library intrinsic.
auto result =
SGF.emitApplyOfLibraryIntrinsic(E, ctx.getGetBoolDecl(nullptr),
SubstitutionMap(),
ManagedValue::forUnmanaged(selected),
C);
return result;
}
RValue RValueEmitter::visitCoerceExpr(CoerceExpr *E, SGFContext C) {
return visit(E->getSubExpr(), C);
}
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &gen, SILLocation loc,
CanType baseTy, CanType arrayTy,
unsigned numElements) {
// Reabstract the base type against the array element type.
auto baseAbstraction = AbstractionPattern::getOpaque();
// Allocate the array.
SILValue numEltsVal = gen.B.createIntegerLiteral(loc,
SILType::getBuiltinWordType(gen.getASTContext()),
numElements);
// The first result is the array value.
ManagedValue array;
// The second result is a RawPointer to the base address of the array.
SILValue basePtr;
std::tie(array, basePtr)
= gen.emitUninitializedArrayAllocation(arrayTy, numEltsVal, loc);
// Temporarily deactivate the main array cleanup.
if (array.hasCleanup())
gen.Cleanups.setCleanupState(array.getCleanup(), CleanupState::Dormant);
// Push a new cleanup to deallocate the array.
auto abortCleanup =
gen.enterDeallocateUninitializedArrayCleanup(array.getValue());
auto &baseTL = gen.getTypeLowering(baseAbstraction, baseTy);
// Turn the pointer into an address.
basePtr = gen.B.createPointerToAddress(
loc, basePtr, baseTL.getLoweredType().getAddressType(),
/*isStrict*/ true,
/*isInvariant*/ false);
return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction);
}
ManagedValue Lowering::emitEndVarargs(SILGenFunction &gen, SILLocation loc,
VarargsInfo &&varargs) {
// Kill the abort cleanup.
gen.Cleanups.setCleanupState(varargs.getAbortCleanup(), CleanupState::Dead);
// Reactivate the result cleanup.
auto result = varargs.getArray();
if (result.hasCleanup())
gen.Cleanups.setCleanupState(result.getCleanup(), CleanupState::Active);
return result;
}
static ManagedValue emitVarargs(SILGenFunction &gen,
SILLocation loc,
Type _baseTy,
ArrayRef<ManagedValue> elements,
Type _arrayTy) {
auto baseTy = _baseTy->getCanonicalType();
auto arrayTy = _arrayTy->getCanonicalType();
auto varargs = emitBeginVarargs(gen, loc, baseTy, arrayTy, elements.size());
AbstractionPattern baseAbstraction = varargs.getBaseAbstractionPattern();
SILValue basePtr = varargs.getBaseAddress();
// Initialize the members.
// TODO: If we need to cleanly unwind at this point, we would need to arrange
// for the partially-initialized array to be cleaned up somehow, maybe by
// poking its count to the actually-initialized size at the point of failure.
for (size_t i = 0, size = elements.size(); i < size; ++i) {
SILValue eltPtr = basePtr;
if (i != 0) {
SILValue index = gen.B.createIntegerLiteral(loc,
SILType::getBuiltinWordType(gen.F.getASTContext()), i);
eltPtr = gen.B.createIndexAddr(loc, basePtr, index);
}
ManagedValue v = elements[i];
v = gen.emitSubstToOrigValue(loc, v, baseAbstraction, baseTy);
v.forwardInto(gen, loc, eltPtr);
}
return emitEndVarargs(gen, loc, std::move(varargs));
}
RValue RValueEmitter::visitTupleExpr(TupleExpr *E, SGFContext C) {
auto type = cast<TupleType>(E->getType()->getCanonicalType());
// If we have an Initialization, emit the tuple elements into its elements.
if (Initialization *I = C.getEmitInto()) {
bool implodeTuple = false;
if (I->canPerformInPlaceInitialization() &&
I->isInPlaceInitializationOfGlobal() &&
SGF.getTypeLowering(type).getLoweredType().isTrivial(SGF.SGM.M)) {
// Implode tuples in initialization of globals if they are
// of trivial types.
implodeTuple = true;
}
if (!implodeTuple && I->canSplitIntoTupleElements()) {
SmallVector<InitializationPtr, 4> subInitializationBuf;
auto subInitializations =
I->splitIntoTupleElements(SGF, RegularLocation(E), type,
subInitializationBuf);
assert(subInitializations.size() == E->getElements().size() &&
"initialization for tuple has wrong number of elements");
for (unsigned i = 0, size = subInitializations.size(); i < size; ++i)
SGF.emitExprInto(E->getElement(i), subInitializations[i].get());
I->finishInitialization(SGF);
return RValue();
}
}
RValue result(type);
for (Expr *elt : E->getElements())
result.addElement(SGF.emitRValue(elt));
return result;
}
namespace {
/// A helper function with context that tries to emit member refs of nominal
/// types avoiding the conservative lvalue logic.
class NominalTypeMemberRefRValueEmitter {
using SelfTy = NominalTypeMemberRefRValueEmitter;
/// The member ref expression we are emitting.
MemberRefExpr *Expr;
/// The passed in SGFContext.
SGFContext Context;
/// The typedecl of the base expression of the member ref expression.
NominalTypeDecl *Base;
/// The field of the member.
VarDecl *Field;
public:
NominalTypeMemberRefRValueEmitter(MemberRefExpr *Expr, SGFContext Context,
NominalTypeDecl *Base)
: Expr(Expr), Context(Context), Base(Base),
Field(cast<VarDecl>(Expr->getMember().getDecl())) {}
/// Emit the RValue.
Optional<RValue> emit(SILGenFunction &SGF) {
// If we don't have a class or a struct, bail.
if (!isa<ClassDecl>(Base) && !isa<StructDecl>(Base))
return None;
// Check that we have a stored access strategy. If we don't bail.
AccessStrategy strategy =
Field->getAccessStrategy(Expr->getAccessSemantics(), AccessKind::Read);
if (strategy != AccessStrategy::Storage)
return None;
if (isa<StructDecl>(Base))
return emitStructDecl(SGF);
assert(isa<ClassDecl>(Base) && "Expected class");
return emitClassDecl(SGF);
}
NominalTypeMemberRefRValueEmitter(const SelfTy &) = delete;
NominalTypeMemberRefRValueEmitter(SelfTy &&) = delete;
~NominalTypeMemberRefRValueEmitter() = default;
private:
RValue emitStructDecl(SILGenFunction &SGF) {
ManagedValue base =
SGF.emitRValueAsSingleValue(Expr->getBase(),
SGFContext::AllowImmediatePlusZero);
CanType baseFormalType =
Expr->getBase()->getType()->getCanonicalType();
assert(baseFormalType->isMaterializable());
RValue result =
SGF.emitRValueForPropertyLoad(Expr, base, baseFormalType,
Expr->isSuper(),
Field,
Expr->getMember().getSubstitutions(),
Expr->getAccessSemantics(),
Expr->getType(), Context);
return result;
}
Optional<RValue> emitClassDecl(SILGenFunction &SGF) {
// If guaranteed plus zero is not ok, we bail.
if (!Context.isGuaranteedPlusZeroOk())
return None;
// If the field is not a let, bail. We need to use the lvalue logic.
if (!Field->isLet())
return None;
// Ok, now we know that we are able to emit our base at guaranteed plus zero
// emit base.
ManagedValue base =
SGF.emitRValueAsSingleValue(Expr->getBase(), Context);
CanType baseFormalType =
Expr->getBase()->getType()->getCanonicalType();
assert(baseFormalType->isMaterializable());
// And then emit our property using whether or not base is at +0 to
// discriminate whether or not the base was guaranteed.
RValue result =
SGF.emitRValueForPropertyLoad(Expr, base, baseFormalType,
Expr->isSuper(),
Field,
Expr->getMember().getSubstitutions(),
Expr->getAccessSemantics(),
Expr->getType(), Context,
base.isPlusZeroRValueOrTrivial());
return std::move(result);
}
};
} // end anonymous namespace
RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *E, SGFContext C) {
assert(!E->getType()->is<LValueType>() &&
"RValueEmitter shouldn't be called on lvalues");
if (isa<TypeDecl>(E->getMember().getDecl())) {
// Emit the metatype for the associated type.
visit(E->getBase());
SILValue MT =
SGF.B.createMetatype(E, SGF.getLoweredLoadableType(E->getType()));
return RValue(SGF, E, ManagedValue::forUnmanaged(MT));
}
// If we have a nominal type decl as our base, try to emit the base rvalue's
// member using special logic that will let us avoid extra retains
// and releases.
if (auto *N = E->getBase()->getType()->getNominalOrBoundGenericNominal())
if (auto RV = NominalTypeMemberRefRValueEmitter(E, C, N).emit(SGF))
return RValue(std::move(RV.getValue()));
// Everything else should use the l-value logic.
// Any writebacks for this access are tightly scoped.
FormalEvaluationScope scope(SGF);
LValue lv = SGF.emitLValue(E, AccessKind::Read);
return SGF.emitLoadOfLValue(E, std::move(lv), C);
}
RValue RValueEmitter::visitDynamicMemberRefExpr(DynamicMemberRefExpr *E,
SGFContext C) {
return SGF.emitDynamicMemberRefExpr(E, C);
}
RValue RValueEmitter::
visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *E, SGFContext C) {
visit(E->getLHS());
return visit(E->getRHS());
}
RValue RValueEmitter::visitSubscriptExpr(SubscriptExpr *E, SGFContext C) {
// Any writebacks for this access are tightly scoped.
FormalEvaluationScope scope(SGF);
LValue lv = SGF.emitLValue(E, AccessKind::Read);
return SGF.emitLoadOfLValue(E, std::move(lv), C);
}
RValue RValueEmitter::visitDynamicSubscriptExpr(
DynamicSubscriptExpr *E, SGFContext C) {
return SGF.emitDynamicSubscriptExpr(E, C);
}
RValue RValueEmitter::visitTupleElementExpr(TupleElementExpr *E,
SGFContext C) {
assert(!E->getType()->is<LValueType>() &&
"RValueEmitter shouldn't be called on lvalues");
// If our client is ok with a +0 result, then we can compute our base as +0
// and return its element that way. It would not be ok to reuse the Context's
// address buffer though, since our base value will a different type than the
// element.
SGFContext SubContext = C.withFollowingProjection();
return visit(E->getBase(), SubContext).extractElement(E->getFieldNumber());
}
RValue
SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc,
ConcreteDeclRef defaultArgsOwner,
unsigned destIndex,
CanType resultType,
AbstractionPattern origResultType,
SGFContext C) {
SILDeclRef generator
= SILDeclRef::getDefaultArgGenerator(defaultArgsOwner.getDecl(),
destIndex);
// TODO: Should apply the default arg generator's captures, but Sema doesn't
// track them.
auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc,generator));
auto fnType = fnRef.getType().castTo<SILFunctionType>();
auto substFnType = fnType->substGenericArgs(SGM.M,
defaultArgsOwner.getSubstitutions());
CalleeTypeInfo calleeTypeInfo(substFnType, origResultType, resultType);
ResultPlanPtr resultPtr =
ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C);
ArgumentScope argScope(*this, loc);
return emitApply(std::move(resultPtr), std::move(argScope), loc, fnRef,
defaultArgsOwner.getSubstitutions(), {}, calleeTypeInfo,
ApplyOptions::None, C);
}
RValue SILGenFunction::emitApplyOfStoredPropertyInitializer(
SILLocation loc,
const PatternBindingEntry &entry,
SubstitutionList subs,
CanType resultType,
AbstractionPattern origResultType,
SGFContext C) {
VarDecl *var = entry.getAnchoringVarDecl();
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc, constant));
auto fnType = fnRef.getType().castTo<SILFunctionType>();
auto substFnType = fnType->substGenericArgs(SGM.M, subs);
CalleeTypeInfo calleeTypeInfo(substFnType, origResultType, resultType);
ResultPlanPtr resultPlan =
ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C);
ArgumentScope argScope(*this, loc);
return emitApply(std::move(resultPlan), std::move(argScope), loc, fnRef, subs,
{}, calleeTypeInfo, ApplyOptions::None, C);
}
static void emitTupleShuffleExprInto(RValueEmitter &emitter,
TupleShuffleExpr *E,
Initialization *outerTupleInit) {
CanTupleType outerTuple = cast<TupleType>(E->getType()->getCanonicalType());
auto outerFields = outerTuple->getElements();
(void) outerFields;
// Decompose the initialization.
SmallVector<InitializationPtr, 4> outerInitsBuffer;
auto outerInits =
outerTupleInit->splitIntoTupleElements(emitter.SGF, RegularLocation(E),
outerTuple, outerInitsBuffer);
assert(outerInits.size() == outerFields.size() &&
"initialization size does not match tuple size?!");
// Map outer initializations into a tuple of inner initializations:
// - fill out the initialization elements with null
TupleInitialization innerTupleInit;
if (E->isSourceScalar()) {
innerTupleInit.SubInitializations.push_back(nullptr);
} else {
CanTupleType innerTuple =
cast<TupleType>(E->getSubExpr()->getType()->getCanonicalType());
innerTupleInit.SubInitializations.resize(innerTuple->getNumElements());
}
// Map all the outer initializations to their appropriate targets.
for (unsigned outerIndex = 0; outerIndex != outerInits.size(); outerIndex++) {
auto innerMapping = E->getElementMapping()[outerIndex];
assert(innerMapping >= 0 &&
"non-argument tuple shuffle with default arguments or variadics?");
innerTupleInit.SubInitializations[innerMapping] =
std::move(outerInits[outerIndex]);
}
#ifndef NDEBUG
for (auto &innerInit : innerTupleInit.SubInitializations) {
assert(innerInit != nullptr && "didn't map all inner elements");
}
#endif
// Emit the sub-expression into the tuple initialization we just built.
if (E->isSourceScalar()) {
emitter.SGF.emitExprInto(E->getSubExpr(),
innerTupleInit.SubInitializations[0].get());
} else {
emitter.SGF.emitExprInto(E->getSubExpr(), &innerTupleInit);
}
outerTupleInit->finishInitialization(emitter.SGF);
}
RValue RValueEmitter::visitTupleShuffleExpr(TupleShuffleExpr *E,
SGFContext C) {
// If we're emitting into an initialization, we can try shuffling the
// elements of the initialization.
if (Initialization *I = C.getEmitInto()) {
// In Swift 3 mode, we might be stripping off labels from a
// one-element tuple; the destination type is a ParenType in
// that case.
//
// FIXME: Remove this eventually.
if (I->canSplitIntoTupleElements() &&
!(isa<ParenType>(E->getType().getPointer()) &&
SGF.getASTContext().isSwiftVersion3())) {
emitTupleShuffleExprInto(*this, E, I);
return RValue();
}
}
// Emit the sub-expression tuple and destructure it into elements.
SmallVector<RValue, 4> elements;
if (E->isSourceScalar()) {
elements.push_back(visit(E->getSubExpr()));
} else {
visit(E->getSubExpr()).extractElements(elements);
}
// Prepare a new tuple to hold the shuffled result.
RValue result(E->getType()->getCanonicalType());
// In Swift 3 mode, we might be stripping off labels from a
// one-element tuple; the destination type is a ParenType in
// that case.
//
// FIXME: Remove this eventually.
if (isa<ParenType>(E->getType().getPointer()) &&
SGF.getASTContext().isSwiftVersion3()) {
assert(E->getElementMapping().size() == 1);
auto shuffleIndex = E->getElementMapping()[0];
assert(shuffleIndex != TupleShuffleExpr::DefaultInitialize &&
shuffleIndex != TupleShuffleExpr::CallerDefaultInitialize &&
shuffleIndex != TupleShuffleExpr::Variadic &&
"Only argument tuples can have default initializers & varargs");
result.addElement(std::move(elements[shuffleIndex]));
return result;
}
auto outerFields = E->getType()->castTo<TupleType>()->getElements();
auto shuffleIndexIterator = E->getElementMapping().begin();
auto shuffleIndexEnd = E->getElementMapping().end();
(void)shuffleIndexEnd;
for (auto &field : outerFields) {
assert(shuffleIndexIterator != shuffleIndexEnd &&
"ran out of shuffle indexes before running out of fields?!");
int shuffleIndex = *shuffleIndexIterator++;
assert(shuffleIndex != TupleShuffleExpr::DefaultInitialize &&
shuffleIndex != TupleShuffleExpr::CallerDefaultInitialize &&
"Only argument tuples can have default initializers & varargs");
// If the shuffle index is Variadic, the argument sources are stored
// separately.
if (shuffleIndex != TupleShuffleExpr::Variadic) {
// Map from a different tuple element.
result.addElement(std::move(elements[shuffleIndex]));
continue;
}
assert(field.isVararg() && "Cannot initialize nonvariadic element");
// Okay, we have a varargs tuple element. The separately-stored variadic
// elements feed into the varargs portion of this, which is then
// constructed into an Array through an informal protocol captured by the
// InjectionFn in the TupleShuffleExpr.
assert(E->getVarargsArrayTypeOrNull() &&
"no injection type for varargs tuple?!");
SmallVector<ManagedValue, 4> variadicValues;
for (unsigned sourceField : E->getVariadicArgs()) {
variadicValues.push_back(
std::move(elements[sourceField]).getAsSingleValue(SGF, E));
}
ManagedValue varargs = emitVarargs(SGF, E, field.getVarargBaseTy(),
variadicValues,
E->getVarargsArrayType());
result.addElement(RValue(SGF, E, field.getType()->getCanonicalType(),
varargs));
break;
}
return result;
}
SILValue SILGenFunction::emitMetatypeOfValue(SILLocation loc, Expr *baseExpr) {
Type formalBaseType = baseExpr->getType()->getLValueOrInOutObjectType();
CanType baseTy = formalBaseType->getCanonicalType();
// For class, archetype, and protocol types, look up the dynamic metatype.
if (baseTy.isAnyExistentialType()) {
SILType metaTy = getLoweredLoadableType(
CanExistentialMetatypeType::get(baseTy));
auto base = emitRValueAsSingleValue(baseExpr,
SGFContext::AllowImmediatePlusZero).getValue();
return B.createExistentialMetatype(loc, metaTy, base);
}
SILType metaTy = getLoweredLoadableType(CanMetatypeType::get(baseTy));
// If the lowered metatype has a thick representation, we need to derive it
// dynamically from the instance.
if (metaTy.castTo<MetatypeType>()->getRepresentation()
!= MetatypeRepresentation::Thin) {
auto base = emitRValueAsSingleValue(baseExpr,
SGFContext::AllowImmediatePlusZero).getValue();
return B.createValueMetatype(loc, metaTy, base);
}
// Otherwise, ignore the base and return the static thin metatype.
emitIgnoredExpr(baseExpr);
return B.createMetatype(loc, metaTy);
}
RValue RValueEmitter::visitDynamicTypeExpr(DynamicTypeExpr *E, SGFContext C) {
auto metatype = SGF.emitMetatypeOfValue(E, E->getBase());
return RValue(SGF, E, ManagedValue::forUnmanaged(metatype));
}
RValue RValueEmitter::visitCaptureListExpr(CaptureListExpr *E, SGFContext C) {
// Ensure that weak captures are in a separate scope.
DebugScope scope(SGF, CleanupLocation(E));
// ClosureExpr's evaluate their bound variables.
for (auto capture : E->getCaptureList()) {
SGF.visit(capture.Var);
SGF.visit(capture.Init);
}
// Then they evaluate to their body.
return visit(E->getClosureBody(), C);
}
RValue RValueEmitter::visitAbstractClosureExpr(AbstractClosureExpr *e,
SGFContext C) {
// Emit the closure body.
SGF.SGM.emitClosure(e);
SubstitutionList subs;
if (e->getCaptureInfo().hasGenericParamCaptures())
subs = SGF.getForwardingSubstitutions();
// Generate the closure value (if any) for the closure expr's function
// reference.
auto refType = e->getType()->getCanonicalType();
ManagedValue result = SGF.emitClosureValue(e, SILDeclRef(e),
refType, subs);
return RValue(SGF, e, refType, result);
}
RValue RValueEmitter::
visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E,
SGFContext C) {
return visit(E->getSemanticExpr(), C);
}
RValue RValueEmitter::
visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C) {
return visit(E->getSemanticExpr(), C);
}
RValue RValueEmitter::
visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C) {
return visit(E->getSemanticExpr(), C);
}
RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) {
SILType loweredSelectorTy = SGF.getLoweredType(e->getType());
// Dig out the declaration of the Selector type.
auto selectorDecl = e->getType()->getAs<StructType>()->getDecl();
// Dig out the type of its pointer.
Type selectorMemberTy;
for (auto member : selectorDecl->getMembers()) {
if (auto var = dyn_cast<VarDecl>(member)) {
if (!var->isStatic() && var->hasStorage()) {
selectorMemberTy = var->getInterfaceType()->getRValueType();
break;
}
}
}
if (!selectorMemberTy) {
SGF.SGM.diagnose(e, diag::objc_selector_malformed);
return RValue(SGF, e, SGF.emitUndef(e, loweredSelectorTy));
}
// Form the selector string.
llvm::SmallString<64> selectorScratch;
auto selectorString =
e->getMethod()->getObjCSelector().getString(selectorScratch);
// Create an Objective-C selector string literal.
auto selectorLiteral =
SGF.B.createStringLiteral(e, selectorString,
StringLiteralInst::Encoding::ObjCSelector);
// Create the pointer struct from the raw pointer.
SILType loweredPtrTy = SGF.getLoweredType(selectorMemberTy);
auto ptrValue = SGF.B.createStruct(e, loweredPtrTy, { selectorLiteral });
// Wrap that up in a Selector and return it.
auto selectorValue = SGF.B.createStruct(e, loweredSelectorTy, { ptrValue });
return RValue(SGF, e, ManagedValue::forUnmanaged(selectorValue));
}
static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
SILLocation loc,
VarDecl *property,
AccessStrategy strategy) {
// Build the signature of the thunk as expected by the keypath runtime.
// For concrete type properties, this is:
// (@in Root, @thick Root.Type) -> @out Value
// with Root and Value maximally abstracted. For protocol properties, this is:
// <Root: P> (@in Root) -> @out Value
// At the ABI level, this should lower to a signature looking like
// void (sret void *outValue, void *inRoot, type *rootType, wtable *rootP)
// which can be abstractly invoked by the runtime.
auto typeContext = property->getDeclContext();
auto baseType = typeContext->getSelfInterfaceType()
->getCanonicalType();
auto propertyType = baseType->getTypeOfMember(SGF.SGM.M.getSwiftModule(),
property)
->getCanonicalType();
auto genericEnv = typeContext->getGenericEnvironmentOfContext();
auto genericSig = typeContext->getGenericSignatureOfContext()
? typeContext->getGenericSignatureOfContext()->getCanonicalSignature()
: nullptr;
SILType loweredBaseTy, loweredPropTy;
{
GenericContextScope scope(SGF.SGM.Types, genericSig);
loweredBaseTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
baseType);
loweredPropTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
propertyType);
}
SmallVector<SILParameterInfo, 2> params;
params.emplace_back(loweredBaseTy.getSwiftRValueType(),
ParameterConvention::Indirect_In);
if (!typeContext->getAsProtocolOrProtocolExtensionContext()) {
// Add a thick metatype argument. This will act as a metadata source for the
// type's generic context, making the lowered calling convention uniform.
params.emplace_back(
CanMetatypeType::get(baseType, MetatypeRepresentation::Thick),
ParameterConvention::Direct_Unowned);
}
SILResultInfo result(loweredPropTy.getSwiftRValueType(),
ResultConvention::Indirect);
auto signature = SILFunctionType::get(genericSig,
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false),
ParameterConvention::Direct_Unowned,
params, result, None, SGF.getASTContext());
// Find the function and see if we already created it.
auto name = Mangle::ASTMangler()
.mangleKeyPathGetterThunkHelper(property);
auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
signature,
IsBare,
IsNotTransparent,
IsNotSerialized,
IsThunk);
if (!thunk->empty())
return thunk;
// Emit the thunk, which accesses the underlying property normally with
// reabstraction where necessary.
auto &SGM = SGF.SGM;
if (genericEnv) {
baseType = genericEnv->mapTypeIntoContext(baseType)->getCanonicalType();
propertyType = genericEnv->mapTypeIntoContext(propertyType)
->getCanonicalType();
thunk->setGenericEnvironment(genericEnv);
}
SILGenFunction subSGF(SGM, *thunk);
auto entry = thunk->begin();
auto resultArgTy = result.getSILStorageType();
auto paramArgTy = params[0].getSILStorageType();
if (genericEnv) {
resultArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, resultArgTy);
paramArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, paramArgTy);
}
auto resultArg = entry->createFunctionArgument(resultArgTy);
auto paramArg = entry->createFunctionArgument(paramArgTy);
if (!typeContext->getAsProtocolOrProtocolExtensionContext()) {
auto metatypeArgTy = params[1].getSILStorageType();
if (genericEnv)
metatypeArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, metatypeArgTy);
entry->createFunctionArgument(metatypeArgTy);
}
Scope scope(subSGF, loc);
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
AbstractionPattern::getOpaque(),
baseType);
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
property->getInnermostDeclContext()->getInnermostTypeContext());
SmallVector<Substitution, 4> subsList;
if (subs.getGenericSignature())
subs.getGenericSignature()->getSubstitutions(subs, subsList);
auto resultSubst = subSGF.emitRValueForPropertyLoad(loc, paramSubstValue,
baseType, /*super*/false, property,
subsList, AccessSemantics::Ordinary,
propertyType, SGFContext())
.getAsSingleValue(subSGF, loc);
if (resultSubst.getType().getAddressType() != resultArg->getType())
resultSubst = subSGF.emitSubstToOrigValue(loc, resultSubst,
AbstractionPattern::getOpaque(),
propertyType);
resultSubst.forwardInto(subSGF, loc, resultArg);
scope.pop();
subSGF.B.createReturn(loc, subSGF.emitEmptyTuple(loc));
return thunk;
}
SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
SILLocation loc,
VarDecl *property,
AccessStrategy strategy) {
// Build the signature of the thunk as expected by the keypath runtime.
// For concrete type properties, this is:
// (@in Value, @in Root, @thick Root.Type) -> ()
// with Root and Value maximally abstracted. For protocol properties, this is:
// <Root: P> (@in Value, @in Root) -> ()
// At the ABI level, this should lower to a signature looking like
// void (void *inValue, void *inRoot, type *rootType, wtable *rootP)
// which can be abstractly invoked by the runtime.
auto typeContext = property->getDeclContext();
auto baseType = typeContext->getSelfInterfaceType()
->getCanonicalType();
auto propertyType = baseType->getTypeOfMember(SGF.SGM.M.getSwiftModule(),
property)
->getCanonicalType();
auto genericEnv = typeContext->getGenericEnvironmentOfContext();
auto genericSig = typeContext->getGenericSignatureOfContext()
? typeContext->getGenericSignatureOfContext()->getCanonicalSignature()
: nullptr;
// Build the signature of the thunk as expected by the keypath runtime.
SILType loweredBaseTy, loweredPropTy;
{
GenericContextScope scope(SGF.SGM.Types, genericSig);
loweredBaseTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
baseType);
loweredPropTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
propertyType);
}
SmallVector<SILParameterInfo, 3> params;
// The newValue param
params.emplace_back(loweredPropTy.getSwiftRValueType(),
ParameterConvention::Indirect_In);
// The base param
params.emplace_back(loweredBaseTy.getSwiftRValueType(),
property->isSetterNonMutating()
? ParameterConvention::Indirect_In
: ParameterConvention::Indirect_Inout);
if (!typeContext->getAsProtocolOrProtocolExtensionContext()) {
// Add a thick metatype argument. This will act as a metadata source for the
// type's generic context, making the lowered calling convention uniform.
params.emplace_back(
CanMetatypeType::get(baseType, MetatypeRepresentation::Thick),
ParameterConvention::Direct_Unowned);
}
auto signature = SILFunctionType::get(genericSig,
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false),
ParameterConvention::Direct_Unowned,
params, {}, None, SGF.getASTContext());
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
// Find the function and see if we already created it.
auto name = Mangle::ASTMangler().mangleKeyPathSetterThunkHelper(property);
auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
signature,
IsBare,
IsNotTransparent,
IsNotSerialized,
IsThunk);
if (!thunk->empty())
return thunk;
// Emit the thunk, which accesses the underlying property normally with
// reabstraction where necessary.
auto &SGM = SGF.SGM;
if (genericEnv) {
baseType = genericEnv->mapTypeIntoContext(baseType)->getCanonicalType();
propertyType = genericEnv->mapTypeIntoContext(propertyType)
->getCanonicalType();
thunk->setGenericEnvironment(genericEnv);
}
SILGenFunction subSGF(SGM, *thunk);
auto entry = thunk->begin();
auto valueArgTy = params[0].getSILStorageType();
auto baseArgTy = params[1].getSILStorageType();
if (genericEnv) {
valueArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, valueArgTy);
baseArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, baseArgTy);
}
auto valueArg = entry->createFunctionArgument(valueArgTy);
auto baseArg = entry->createFunctionArgument(baseArgTy);
if (!typeContext->getAsProtocolOrProtocolExtensionContext()) {
auto metatypeArgTy = params[2].getSILStorageType();
if (genericEnv)
metatypeArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, metatypeArgTy);
entry->createFunctionArgument(metatypeArgTy);
}
Scope scope(subSGF, loc);
auto valueOrig = subSGF.emitManagedRValueWithCleanup(valueArg);
auto valueSubst = subSGF.emitOrigToSubstValue(loc, valueOrig,
AbstractionPattern::getOpaque(),
propertyType);
LValue lv;
if (property->isSetterNonMutating()) {
auto baseOrig = subSGF.emitManagedRValueWithCleanup(baseArg);
auto baseSubst = subSGF.emitOrigToSubstValue(loc, baseOrig,
AbstractionPattern::getOpaque(),
baseType);
lv = LValue::forValue(baseSubst, baseType);
} else {
auto baseOrig = ManagedValue::forLValue(baseArg);
lv = LValue::forAddress(baseOrig, None,
AbstractionPattern::getOpaque(),
baseType);
}
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
property->getInnermostDeclContext()->getInnermostTypeContext());
SmallVector<Substitution, 4> subsList;
if (subs.getGenericSignature())
subs.getGenericSignature()->getSubstitutions(subs, subsList);
lv.addMemberVarComponent(subSGF, loc, property, subsList, /*super*/ false,
AccessKind::Write, AccessSemantics::Ordinary,
strategy, propertyType);
subSGF.emitAssignToLValue(loc,
RValue(subSGF, loc, propertyType, valueSubst),
std::move(lv));
scope.pop();
subSGF.B.createReturn(loc, subSGF.emitEmptyTuple(loc));
return thunk;
}
static KeyPathPatternComponent::ComputedPropertyId
getIdForKeyPathComponentComputedProperty(SILGenFunction &SGF,
VarDecl *property,
AccessStrategy strategy) {
switch (strategy) {
case AccessStrategy::Storage:
// Identify reabstracted stored properties by the property itself.
return property;
case AccessStrategy::Addressor:
case AccessStrategy::DirectToAccessor: {
// Identify the property using its (unthunked) getter. For a
// computed property, this should be stable ABI; for a resilient public
// property, this should also be stable ABI across modules.
// TODO: If the getter has shared linkage (say it's synthesized for a
// Clang-imported thing), we'll need some other sort of
// stable identifier.
auto getterRef = SILDeclRef(property->getGetter(), SILDeclRef::Kind::Func);
return SGF.SGM.getFunction(getterRef, NotForDefinition);
}
case AccessStrategy::DispatchToAccessor: {
// Identify the property by its vtable or wtable slot.
return SILDeclRef(property->getGetter(), SILDeclRef::Kind::Func);
}
case AccessStrategy::BehaviorStorage:
llvm_unreachable("unpossible");
}
llvm_unreachable("unhandled access strategy");
}
RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
if (E->isObjC()) {
return visit(E->getObjCStringLiteralExpr(), C);
}
// Figure out the key path pattern, abstracting out generic arguments and
// subscript indexes.
SmallVector<KeyPathPatternComponent, 4> loweredComponents;
auto loweredTy = SGF.getLoweredType(E->getType());
auto unsupported = [&](StringRef message) -> RValue {
SGF.SGM.diagnose(E->getLoc(), diag::not_implemented, message);
auto undef = SILUndef::get(loweredTy, SGF.SGM.M);
return RValue(SGF, E, ManagedValue::forUnmanaged(undef));
};
CanType rootTy = E->getType()->castTo<BoundGenericType>()->getGenericArgs()[0]
->getCanonicalType();
bool needsGenericContext = false;
if (rootTy->hasArchetype()) {
needsGenericContext = true;
rootTy = SGF.F.mapTypeOutOfContext(rootTy)->getCanonicalType();
}
auto baseTy = rootTy;
for (auto &component : E->getComponents()) {
switch (component.getKind()) {
case KeyPathExpr::Component::Kind::Property: {
auto decl = cast<VarDecl>(component.getDeclRef().getDecl());
baseTy = baseTy->getTypeOfMember(SGF.SGM.SwiftModule, decl)
->getCanonicalType();
switch (auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
AccessKind::ReadWrite)) {
case AccessStrategy::Storage: {
// If the stored value would need to be reabstracted in fully opaque
// context, then we have to treat the component as computed.
auto componentObjTy =
component.getComponentType()->getLValueOrInOutObjectType();
auto storageTy = SGF.SGM.Types.getSubstitutedStorageType(decl,
componentObjTy);
auto opaqueTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
componentObjTy);
if (storageTy.getAddressType() == opaqueTy.getAddressType()) {
loweredComponents.push_back(
KeyPathPatternComponent::forStoredProperty(decl, baseTy));
break;
}
LLVM_FALLTHROUGH;
}
case AccessStrategy::Addressor:
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor: {
// We need thunks to bring the getter and setter to the right signature
// expected by the key path runtime.
auto id = getIdForKeyPathComponentComputedProperty(SGF, decl,
strategy);
auto getter = getOrCreateKeyPathGetter(SGF, SILLocation(E),
decl, strategy);
if (decl->isSettable(decl->getDeclContext())) {
auto setter = getOrCreateKeyPathSetter(SGF, SILLocation(E),
decl, strategy);
loweredComponents.push_back(
KeyPathPatternComponent::forComputedSettableProperty(id,
getter, setter,
{}, baseTy));
} else {
loweredComponents.push_back(
KeyPathPatternComponent::forComputedGettableProperty(id,
getter,
{}, baseTy));
}
break;
}
case AccessStrategy::BehaviorStorage:
llvm_unreachable("should not occur");
}
break;
}
case KeyPathExpr::Component::Kind::Subscript:
case KeyPathExpr::Component::Kind::OptionalChain:
case KeyPathExpr::Component::Kind::OptionalForce:
case KeyPathExpr::Component::Kind::OptionalWrap:
return unsupported("non-property key path component");
case KeyPathExpr::Component::Kind::UnresolvedProperty:
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
llvm_unreachable("not resolved");
}
}
StringRef objcString;
if (auto objcExpr = dyn_cast_or_null<StringLiteralExpr>
(E->getObjCStringLiteralExpr()))
objcString = objcExpr->getValue();
auto pattern = KeyPathPattern::get(SGF.SGM.M,
needsGenericContext
? SGF.F.getLoweredFunctionType()
->getGenericSignature()
: nullptr,
rootTy, baseTy,
loweredComponents,
objcString);
auto keyPath = SGF.B.createKeyPath(SILLocation(E), pattern,
needsGenericContext
? SGF.F.getForwardingSubstitutions()
: SubstitutionList(),
loweredTy);
auto value = SGF.emitManagedRValueWithCleanup(keyPath);
return RValue(SGF, E, value);
}
RValue RValueEmitter::
visitKeyPathApplicationExpr(KeyPathApplicationExpr *E, SGFContext C) {
// An rvalue key path application always occurs as a read-only projection of
// the base. The base is received maximally abstracted.
auto root = SGF.emitMaterializedRValueAsOrig(E->getBase(),
AbstractionPattern::getOpaque());
auto keyPath = SGF.emitRValueAsSingleValue(E->getKeyPath());
// Get the root and leaf type from the key path type.
auto keyPathTy = E->getKeyPath()->getType()->castTo<BoundGenericType>();
// Upcast the keypath to KeyPath<T, U> if it isn't already.
if (keyPathTy->getDecl() != SGF.getASTContext().getKeyPathDecl()) {
auto castToTy = BoundGenericType::get(SGF.getASTContext().getKeyPathDecl(),
nullptr,
keyPathTy->getGenericArgs())
->getCanonicalType();
auto upcast = SGF.B.createUpcast(SILLocation(E),
keyPath.forward(SGF),
SILType::getPrimitiveObjectType(castToTy));
keyPath = SGF.emitManagedRValueWithCleanup(upcast);
}
auto projectFn = SGF.getASTContext().getProjectKeyPathReadOnly(nullptr);
Substitution genericArgs[] = {
Substitution(keyPathTy->getGenericArgs()[0], {}),
Substitution(keyPathTy->getGenericArgs()[1], {}),
};
auto genericArgsMap =
projectFn->getGenericSignature()->getSubstitutionMap(genericArgs);
return SGF.emitApplyOfLibraryIntrinsic(SILLocation(E),
SGF.getASTContext().getProjectKeyPathReadOnly(nullptr),
genericArgsMap, {root, keyPath}, C);
}
RValue RValueEmitter::
visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) {
ASTContext &Ctx = SGF.getASTContext();
SILType Ty = SGF.getLoweredLoadableType(E->getType());
SourceLoc Loc;
// If "overrideLocationForMagicIdentifiers" is set, then we use it as the
// location point for these magic identifiers.
if (SGF.overrideLocationForMagicIdentifiers)
Loc = SGF.overrideLocationForMagicIdentifiers.getValue();
else
Loc = E->getStartLoc();
switch (E->getKind()) {
case MagicIdentifierLiteralExpr::File:
case MagicIdentifierLiteralExpr::Function:
return SGF.emitLiteral(E, C);
case MagicIdentifierLiteralExpr::Line: {
unsigned Value = 0;
if (Loc.isValid())
Value = Ctx.SourceMgr.getLineAndColumn(Loc).first;
SILValue V = SGF.B.createIntegerLiteral(E, Ty, Value);
return RValue(SGF, E, ManagedValue::forUnmanaged(V));
}
case MagicIdentifierLiteralExpr::Column: {
unsigned Value = 0;
if (Loc.isValid())
Value = Ctx.SourceMgr.getLineAndColumn(Loc).second;
SILValue V = SGF.B.createIntegerLiteral(E, Ty, Value);
return RValue(SGF, E, ManagedValue::forUnmanaged(V));
}
case MagicIdentifierLiteralExpr::DSOHandle: {
auto SILLoc = SILLocation(E);
auto UnsafeRawPointer = SGF.getASTContext().getUnsafeRawPointerDecl();
auto UnsafeRawPtrTy =
SGF.getLoweredType(UnsafeRawPointer->getDeclaredInterfaceType());
SILType BuiltinRawPtrTy = SILType::getRawPointerType(SGF.getASTContext());
auto DSOGlobal = SGF.SGM.M.lookUpGlobalVariable("__dso_handle");
if (!DSOGlobal)
DSOGlobal = SILGlobalVariable::create(SGF.SGM.M,
SILLinkage::HiddenExternal,
IsNotSerialized, "__dso_handle",
BuiltinRawPtrTy);
auto DSOAddr = SGF.B.createGlobalAddr(SILLoc, DSOGlobal);
auto DSOPointer = SGF.B.createAddressToPointer(SILLoc, DSOAddr,
BuiltinRawPtrTy);
auto UnsafeRawPtrStruct = SGF.B.createStruct(SILLoc, UnsafeRawPtrTy,
{ DSOPointer });
return RValue(SGF, E, ManagedValue::forUnmanaged(UnsafeRawPtrStruct));
}
}
llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
}
RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) {
return visit(E->getSemanticExpr(), C);
}
/// Flattens one level of optional from a nested optional value.
static ManagedValue flattenOptional(SILGenFunction &SGF, SILLocation loc,
ManagedValue optVal) {
// FIXME: Largely copied from SILGenFunction::emitOptionalToOptional.
auto contBB = SGF.createBasicBlock();
auto isNotPresentBB = SGF.createBasicBlock();
auto isPresentBB = SGF.createBasicBlock();
SILType resultTy = optVal.getType().getAnyOptionalObjectType();
auto &resultTL = SGF.getTypeLowering(resultTy);
assert(resultTy.getSwiftRValueType().getAnyOptionalObjectType() &&
"input was not a nested optional value");
// If the result is address-only, we need to return something in memory,
// otherwise the result is the BBArgument in the merge point.
SILValue result;
if (resultTL.isAddressOnly())
result = SGF.emitTemporaryAllocation(loc, resultTy);
else
result = contBB->createPHIArgument(resultTy, ValueOwnershipKind::Owned);
// Branch on whether the input is optional, this doesn't consume the value.
auto isPresent = SGF.emitDoesOptionalHaveValue(loc, optVal.getValue());
SGF.B.createCondBranch(loc, isPresent, isPresentBB, isNotPresentBB);
// If it's present, apply the recursive transformation to the value.
SGF.B.emitBlock(isPresentBB);
SILValue branchArg;
{
// Don't allow cleanups to escape the conditional block.
FullExpr presentScope(SGF.Cleanups, CleanupLocation::get(loc));
// Pull the value out. This will load if the value is not address-only.
auto &inputTL = SGF.getTypeLowering(optVal.getType());
auto resultValue = SGF.emitUncheckedGetOptionalValueFrom(loc, optVal,
inputTL);
// Inject that into the result type if the result is address-only.
if (resultTL.isAddressOnly())
resultValue.forwardInto(SGF, loc, result);
else
branchArg = resultValue.forward(SGF);
}
if (branchArg)
SGF.B.createBranch(loc, contBB, branchArg);
else
SGF.B.createBranch(loc, contBB);
// If it's not present, inject 'nothing' into the result.
SGF.B.emitBlock(isNotPresentBB);
if (resultTL.isAddressOnly()) {
SGF.emitInjectOptionalNothingInto(loc, result, resultTL);
SGF.B.createBranch(loc, contBB);
} else {
branchArg = SGF.getOptionalNoneValue(loc, resultTL);
SGF.B.createBranch(loc, contBB, branchArg);
}
// Continue.
SGF.B.emitBlock(contBB);
if (resultTL.isAddressOnly())
return SGF.emitManagedBufferWithCleanup(result, resultTL);
return SGF.emitManagedRValueWithCleanup(result, resultTL);
}
static ManagedValue
computeNewSelfForRebindSelfInConstructorExpr(SILGenFunction &SGF,
RebindSelfInConstructorExpr *E) {
// Get newSelf, forward the cleanup for newSelf and clean everything else
// up.
FormalEvaluationScope Scope(SGF);
ManagedValue newSelfWithCleanup =
SGF.emitRValueAsSingleValue(E->getSubExpr());
SGF.InitDelegationSelf = ManagedValue();
SGF.SuperInitDelegationSelf = ManagedValue();
SGF.InitDelegationLoc.reset();
return newSelfWithCleanup;
}
RValue RValueEmitter::visitRebindSelfInConstructorExpr(
RebindSelfInConstructorExpr *E, SGFContext C) {
auto selfDecl = E->getSelf();
auto ctorDecl = cast<ConstructorDecl>(selfDecl->getDeclContext());
auto selfTy = selfDecl->getType()->getInOutObjectType();
auto newSelfTy = E->getSubExpr()->getType();
OptionalTypeKind failability;
if (auto objTy = newSelfTy->getAnyOptionalObjectType(failability))
newSelfTy = objTy;
// "try? self.init()" can give us two levels of optional if the initializer
// we delegate to is failable.
OptionalTypeKind extraFailability;
if (auto objTy = newSelfTy->getAnyOptionalObjectType(extraFailability))
newSelfTy = objTy;
bool requiresDowncast = !newSelfTy->isEqual(selfTy);
// The subexpression consumes the current 'self' binding.
assert(SGF.SelfInitDelegationState == SILGenFunction::NormalSelf
&& "already doing something funky with self?!");
SGF.SelfInitDelegationState = SILGenFunction::WillSharedBorrowSelf;
SGF.InitDelegationLoc.emplace(E);
// Emit the subexpression, computing new self. New self is always returned at
// +1.
ManagedValue newSelf = computeNewSelfForRebindSelfInConstructorExpr(SGF, E);
// We know that self is a box, so get its address.
SILValue selfAddr =
SGF.emitLValueForDecl(E, selfDecl, selfTy->getCanonicalType(),
AccessKind::Write).getLValueAddress();
// Handle a nested optional case (see above).
if (extraFailability != OTK_None)
newSelf = flattenOptional(SGF, E, newSelf);
// If both the delegated-to initializer and our enclosing initializer can
// fail, deal with the failure.
if (failability != OTK_None && ctorDecl->getFailability() != OTK_None) {
SILBasicBlock *someBB = SGF.createBasicBlock();
auto hasValue = SGF.emitDoesOptionalHaveValue(E, newSelf.getValue());
assert(SGF.FailDest.isValid() && "too big to fail");
auto noneBB = SGF.Cleanups.emitBlockForCleanups(SGF.FailDest, E);
SGF.B.createCondBranch(E, hasValue, someBB, noneBB);
// Otherwise, project out the value and carry on.
SGF.B.emitBlock(someBB);
// If the current constructor is not failable, force out the value.
newSelf = SGF.emitUncheckedGetOptionalValueFrom(E, newSelf,
SGF.getTypeLowering(newSelf.getType()),
SGFContext());
}
// If we called a constructor that requires a downcast, perform the downcast.
if (requiresDowncast) {
assert(newSelf.getType().isObject() &&
newSelf.getType().hasReferenceSemantics() &&
"ctor type mismatch for non-reference type?!");
CleanupHandle newSelfCleanup = newSelf.getCleanup();
SILValue newSelfValue;
auto destTy = SGF.getLoweredLoadableType(
E->getSelf()->getType()->getInOutObjectType());
// Assume that the returned 'self' is the appropriate subclass
// type (or a derived class thereof). Only Objective-C classes can
// violate this assumption.
newSelfValue = SGF.B.createUncheckedRefCast(E, newSelf.getValue(),
destTy);
newSelf = ManagedValue(newSelfValue, newSelfCleanup);
}
// Forward or assign into the box depending on whether we actually consumed
// 'self'.
switch (SGF.SelfInitDelegationState) {
case SILGenFunction::NormalSelf:
llvm_unreachable("self isn't normal in a constructor delegation");
case SILGenFunction::WillSharedBorrowSelf:
// We did not perform any borrow of self, exclusive or shared. This means
// that old self is still located in the relevant box. This will ensure that
// old self is destroyed.
newSelf.assignInto(SGF, E, selfAddr);
break;
case SILGenFunction::DidSharedBorrowSelf:
// We performed a shared borrow of self. This means that old self is still
// located in the self box. Perform an assign to destroy old self.
newSelf.assignInto(SGF, E, selfAddr);
break;
case SILGenFunction::WillExclusiveBorrowSelf:
llvm_unreachable("Should never have newSelf without finishing an exclusive "
"borrow scope");
case SILGenFunction::DidExclusiveBorrowSelf:
// We performed an exclusive borrow of self and have a new value to
// writeback. Writeback the self value into the now empty box.
newSelf.forwardInto(SGF, E, selfAddr);
break;
}
SGF.SelfInitDelegationState = SILGenFunction::NormalSelf;
SGF.InitDelegationSelf = ManagedValue();
// If we are using Objective-C allocation, the caller can return
// nil. When this happens with an explicitly-written super.init or
// self.init invocation, return early if we did get nil.
//
// TODO: Remove this when failable initializers are fully implemented.
auto classDecl = selfTy->getClassOrBoundGenericClass();
if (classDecl && !E->getSubExpr()->isImplicit() &&
usesObjCAllocator(classDecl)) {
// Check whether the new self is null.
SILValue isNonnullSelf = SGF.B.createIsNonnull(E, newSelf.getValue());
Condition cond = SGF.emitCondition(isNonnullSelf, E,
/*hasFalseCode=*/false,
/*invertValue=*/true,
{ });
// If self is null, branch to the epilog.
cond.enterTrue(SGF);
SGF.Cleanups.emitBranchAndCleanups(SGF.ReturnDest, E, { });
cond.exitTrue(SGF);
cond.complete(SGF);
}
return SGF.emitEmptyTupleRValue(E, C);
}
static bool isVerbatimNullableTypeInC(SILModule &M, Type ty) {
ty = ty->getLValueOrInOutObjectType()->getReferenceStorageReferent();
// Class instances, and @objc existentials are all nullable.
if (ty->hasReferenceSemantics()) {
// So are blocks, but we usually bridge them to Swift closures before we get
// a chance to check for optional promotion, so we're already screwed if
// an API lies about nullability.
if (auto fnTy = ty->getAs<AnyFunctionType>()) {
switch (fnTy->getRepresentation()) {
// Carried verbatim from C.
case FunctionTypeRepresentation::Block:
case FunctionTypeRepresentation::CFunctionPointer:
return true;
// Was already bridged.
case FunctionTypeRepresentation::Swift:
case FunctionTypeRepresentation::Thin:
return false;
}
}
return true;
}
// Other types like UnsafePointer can also be nullable.
const DeclContext *DC = M.getAssociatedContext();
if (!DC)
DC = M.getSwiftModule();
ty = OptionalType::get(ty);
return ty->isTriviallyRepresentableIn(ForeignLanguage::C, DC);
}
/// Determine whether the given declaration returns a non-optional object that
/// might actually be nil.
///
/// This is an awful hack that makes it possible to work around several kinds
/// of problems:
/// - initializers currently cannot fail, so they always return non-optional.
/// - an Objective-C method might have been annotated to state (incorrectly)
/// that it returns a non-optional object
/// - an Objective-C property might be annotated to state (incorrectly) that
/// it is non-optional
static bool mayLieAboutNonOptionalReturn(SILModule &M,
ValueDecl *decl) {
// Any Objective-C initializer, because failure propagates from any
// initializer written in Objective-C (and there's no way to tell).
if (auto constructor = dyn_cast<ConstructorDecl>(decl)) {
return constructor->isObjC();
}
// Functions that return non-optional reference type and were imported from
// Objective-C.
if (auto func = dyn_cast<FuncDecl>(decl)) {
assert((func->getResultInterfaceType()->hasTypeParameter()
|| isVerbatimNullableTypeInC(M, func->getResultInterfaceType()))
&& "func's result type is not nullable?!");
return func->hasClangNode();
}
// Computed properties of non-optional reference type that were imported from
// Objective-C.
if (auto var = dyn_cast<VarDecl>(decl)) {
#ifndef NDEBUG
auto type = var->getInterfaceType();
assert((type->hasTypeParameter()
|| isVerbatimNullableTypeInC(M, type->getReferenceStorageReferent()))
&& "property's result type is not nullable?!");
#endif
return var->hasClangNode();
}
// Subscripts of non-optional reference type that were imported from
// Objective-C.
if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
assert((subscript->getElementInterfaceType()->hasTypeParameter()
|| isVerbatimNullableTypeInC(M, subscript->getElementInterfaceType()))
&& "subscript's result type is not nullable?!");
return subscript->hasClangNode();
}
return false;
}
/// Determine whether the given expression returns a non-optional object that
/// might actually be nil.
///
/// This is an awful hack that makes it possible to work around several kinds
/// of problems:
/// - an Objective-C method might have been annotated to state (incorrectly)
/// that it returns a non-optional object
/// - an Objective-C property might be annotated to state (incorrectly) that
/// it is non-optional
static bool mayLieAboutNonOptionalReturn(SILModule &M, Expr *expr) {
expr = expr->getSemanticsProvidingExpr();
// An application that produces a reference type, which we look through to
// get the function we're calling.
if (auto apply = dyn_cast<ApplyExpr>(expr)) {
// The result has to be a nullable type.
if (!isVerbatimNullableTypeInC(M, apply->getType()))
return false;
auto getFuncDeclFromDynamicMemberLookup = [&](Expr *expr) -> FuncDecl * {
if (auto open = dyn_cast<OpenExistentialExpr>(expr))
expr = open->getSubExpr();
if (auto memberRef = dyn_cast<DynamicMemberRefExpr>(expr))
return dyn_cast<FuncDecl>(memberRef->getMember().getDecl());
return nullptr;
};
// The function should come from C, being either an ObjC function or method
// or having a C-derived convention.
ValueDecl *method = nullptr;
if (auto selfApply = dyn_cast<ApplyExpr>(apply->getFn())) {
if (auto methodRef = dyn_cast<DeclRefExpr>(selfApply->getFn())) {
method = methodRef->getDecl();
}
} else if (auto force = dyn_cast<ForceValueExpr>(apply->getFn())) {
method = getFuncDeclFromDynamicMemberLookup(force->getSubExpr());
} else if (auto bind = dyn_cast<BindOptionalExpr>(apply->getFn())) {
method = getFuncDeclFromDynamicMemberLookup(bind->getSubExpr());
} else if (auto fnRef = dyn_cast<DeclRefExpr>(apply->getFn())) {
// Only consider a full application of a method. Partial applications
// never lie.
if (auto func = dyn_cast<AbstractFunctionDecl>(fnRef->getDecl()))
if (func->getParameterLists().size() == 1)
method = fnRef->getDecl();
}
if (method && mayLieAboutNonOptionalReturn(M, method))
return true;
auto convention = apply->getFn()->getType()->castTo<AnyFunctionType>()
->getRepresentation();
switch (convention) {
case FunctionTypeRepresentation::Block:
case FunctionTypeRepresentation::CFunctionPointer:
return true;
case FunctionTypeRepresentation::Swift:
case FunctionTypeRepresentation::Thin:
return false;
}
}
// A load.
if (auto load = dyn_cast<LoadExpr>(expr)) {
return mayLieAboutNonOptionalReturn(M, load->getSubExpr());
}
// A reference to a member property.
if (auto member = dyn_cast<MemberRefExpr>(expr)) {
return isVerbatimNullableTypeInC(M, member->getType()) &&
mayLieAboutNonOptionalReturn(M, member->getMember().getDecl());
}
// A reference to a subscript.
if (auto subscript = dyn_cast<SubscriptExpr>(expr)) {
return isVerbatimNullableTypeInC(M, subscript->getType()) &&
mayLieAboutNonOptionalReturn(M, subscript->getDecl().getDecl());
}
// A reference to a member property found via dynamic lookup.
if (auto member = dyn_cast<DynamicMemberRefExpr>(expr)) {
return isVerbatimNullableTypeInC(M, member->getType()) &&
mayLieAboutNonOptionalReturn(M, member->getMember().getDecl());
}
// A reference to a subscript found via dynamic lookup.
if (auto subscript = dyn_cast<DynamicSubscriptExpr>(expr)) {
return isVerbatimNullableTypeInC(M, subscript->getType()) &&
mayLieAboutNonOptionalReturn(M, subscript->getMember().getDecl());
}
return false;
}
RValue RValueEmitter::visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E,
SGFContext C) {
// This is an awful hack. When the source expression might produce a
// non-optional reference that could legitimated be nil, such as with an
// initializer, allow this workaround to capture that nil:
//
// let x: NSFoo? = NSFoo(potentiallyFailingInit: x)
//
// However, our optimizer is smart enough now to recognize that an initializer
// can "never" produce nil, and will optimize away any attempts to check the
// resulting optional for nil. As a special case, when we're injecting the
// result of an ObjC constructor into an optional, do it using an unchecked
// bitcast, which is opaque to the optimizer.
if (mayLieAboutNonOptionalReturn(SGF.SGM.M, E->getSubExpr())) {
auto result = SGF.emitRValueAsSingleValue(E->getSubExpr());
auto optType = SGF.getLoweredLoadableType(E->getType());
SILValue bitcast = SGF.B.createUncheckedBitCast(E, result.getValue(),
optType);
ManagedValue bitcastMV = ManagedValue(bitcast, result.getCleanup());
return RValue(SGF, E, bitcastMV);
}
OptionalTypeKind OTK;
E->getType()->getAnyOptionalObjectType(OTK);
assert(OTK != OTK_None);
auto someDecl = SGF.getASTContext().getOptionalSomeDecl(OTK);
ManagedValue result = SGF.emitInjectEnum(E, ArgumentSource(E->getSubExpr()),
SGF.getLoweredType(E->getType()),
someDecl, C);
if (result.isInContext())
return RValue();
return RValue(SGF, E, result);
}
RValue RValueEmitter::visitClassMetatypeToObjectExpr(
ClassMetatypeToObjectExpr *E,
SGFContext C) {
ManagedValue v = SGF.emitRValueAsSingleValue(E->getSubExpr());
SILType resultTy = SGF.getLoweredLoadableType(E->getType());
return RValue(SGF, E, SGF.emitClassMetatypeToObject(E, v, resultTy));
}
RValue RValueEmitter::visitExistentialMetatypeToObjectExpr(
ExistentialMetatypeToObjectExpr *E,
SGFContext C) {
ManagedValue v = SGF.emitRValueAsSingleValue(E->getSubExpr());
SILType resultTy = SGF.getLoweredLoadableType(E->getType());
return RValue(SGF, E, SGF.emitExistentialMetatypeToObject(E, v, resultTy));
}
RValue RValueEmitter::visitProtocolMetatypeToObjectExpr(
ProtocolMetatypeToObjectExpr *E,
SGFContext C) {
SGF.emitIgnoredExpr(E->getSubExpr());
CanType inputTy = E->getSubExpr()->getType()->getCanonicalType();
SILType resultTy = SGF.getLoweredLoadableType(E->getType());
ManagedValue v = SGF.emitProtocolMetatypeToObject(E, inputTy, resultTy);
return RValue(SGF, E, v);
}
RValue RValueEmitter::visitIfExpr(IfExpr *E, SGFContext C) {
auto &lowering = SGF.getTypeLowering(E->getType());
if (lowering.isLoadable() || !SGF.silConv.useLoweredAddresses()) {
// If the result is loadable, emit each branch and forward its result
// into the destination block argument.
// FIXME: We could avoid imploding and reexploding tuples here.
Condition cond = SGF.emitCondition(E->getCondExpr(),
/*hasFalse*/ true,
/*invertCondition*/ false,
SGF.getLoweredType(E->getType()));
cond.enterTrue(SGF);
SGF.emitProfilerIncrement(E->getThenExpr());
SILValue trueValue;
{
auto TE = E->getThenExpr();
FullExpr trueScope(SGF.Cleanups, CleanupLocation(TE));
trueValue = visit(TE).forwardAsSingleValue(SGF, TE);
}
cond.exitTrue(SGF, trueValue);
cond.enterFalse(SGF);
SILValue falseValue;
{
auto EE = E->getElseExpr();
FullExpr falseScope(SGF.Cleanups, CleanupLocation(EE));
falseValue = visit(EE).forwardAsSingleValue(SGF, EE);
}
cond.exitFalse(SGF, falseValue);
SILBasicBlock *cont = cond.complete(SGF);
assert(cont && "no continuation block for if expr?!");
SILValue result = cont->args_begin()[0];
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(result));
} else {
// If the result is address-only, emit the result into a common stack buffer
// that dominates both branches.
SILValue resultAddr = SGF.getBufferForExprResult(
E, lowering.getLoweredType(), C);
Condition cond = SGF.emitCondition(E->getCondExpr(),
/*hasFalse*/ true,
/*invertCondition*/ false);
cond.enterTrue(SGF);
SGF.emitProfilerIncrement(E->getThenExpr());
{
auto TE = E->getThenExpr();
FullExpr trueScope(SGF.Cleanups, CleanupLocation(TE));
KnownAddressInitialization init(resultAddr);
SGF.emitExprInto(TE, &init);
}
cond.exitTrue(SGF);
cond.enterFalse(SGF);
{
auto EE = E->getElseExpr();
FullExpr trueScope(SGF.Cleanups, CleanupLocation(EE));
KnownAddressInitialization init(resultAddr);
SGF.emitExprInto(EE, &init);
}
cond.exitFalse(SGF);
cond.complete(SGF);
return RValue(SGF, E,
SGF.manageBufferForExprResult(resultAddr, lowering, C));
}
}
RValue SILGenFunction::emitEmptyTupleRValue(SILLocation loc,
SGFContext C) {
return RValue(CanType(TupleType::getEmpty(F.getASTContext())));
}
namespace {
/// A visitor for creating a flattened list of LValues from a
/// tuple-of-lvalues expression.
///
/// Note that we can have tuples down to arbitrary depths in the
/// type, but every branch should lead to an l-value otherwise.
class TupleLValueEmitter
: public Lowering::ExprVisitor<TupleLValueEmitter> {
SILGenFunction &SGF;
AccessKind TheAccessKind;
/// A flattened list of l-values.
SmallVectorImpl<Optional<LValue>> &Results;
public:
TupleLValueEmitter(SILGenFunction &SGF, AccessKind accessKind,
SmallVectorImpl<Optional<LValue>> &results)
: SGF(SGF), TheAccessKind(accessKind), Results(results) {}
// If the destination is a tuple, recursively destructure.
void visitTupleExpr(TupleExpr *E) {
assert(E->getType()->is<TupleType>());
assert(!E->getType()->isMaterializable() || E->getType()->isVoid());
for (auto &elt : E->getElements()) {
visit(elt);
}
}
// If the destination is '_', queue up a discard.
void visitDiscardAssignmentExpr(DiscardAssignmentExpr *E) {
Results.push_back(None);
}
// Otherwise, queue up a scalar assignment to an lvalue.
void visitExpr(Expr *E) {
assert(E->getType()->is<LValueType>());
Results.push_back(SGF.emitLValue(E, TheAccessKind));
}
};
/// A visitor for consuming tuples of l-values.
class TupleLValueAssigner
: public CanTypeVisitor<TupleLValueAssigner, void, RValue &&> {
SILGenFunction &SGF;
SILLocation AssignLoc;
MutableArrayRef<Optional<LValue>> DestLVQueue;
Optional<LValue> &&getNextDest() {
assert(!DestLVQueue.empty());
Optional<LValue> &next = DestLVQueue.front();
DestLVQueue = DestLVQueue.slice(1);
return std::move(next);
}
public:
TupleLValueAssigner(SILGenFunction &SGF, SILLocation assignLoc,
SmallVectorImpl<Optional<LValue>> &destLVs)
: SGF(SGF), AssignLoc(assignLoc), DestLVQueue(destLVs) {}
/// Top-level entrypoint.
void emit(CanType destType, RValue &&src) {
visitTupleType(cast<TupleType>(destType), std::move(src));
assert(DestLVQueue.empty() && "didn't consume all l-values!");
}
// If the destination is a tuple, recursively destructure.
void visitTupleType(CanTupleType destTupleType, RValue &&srcTuple) {
// Break up the source r-value.
SmallVector<RValue, 4> srcElts;
std::move(srcTuple).extractElements(srcElts);
// Consume source elements off the queue.
unsigned eltIndex = 0;
for (CanType destEltType : destTupleType.getElementTypes()) {
visit(destEltType, std::move(srcElts[eltIndex++]));
}
}
// Okay, otherwise we pull one destination off the queue.
void visitType(CanType destType, RValue &&src) {
assert(isa<LValueType>(destType));
Optional<LValue> &&next = getNextDest();
// If the destination is a discard, do nothing.
if (!next.hasValue())
return;
// Otherwise, emit the scalar assignment.
SGF.emitAssignToLValue(AssignLoc, std::move(src),
std::move(next.getValue()));
}
};
} // end anonymous namespace
/// Emit a simple assignment, i.e.
///
/// dest = src
///
/// The destination operand can be an arbitrarily-structured tuple of
/// l-values.
static void emitSimpleAssignment(SILGenFunction &SGF, SILLocation loc,
Expr *dest, Expr *src) {
// Handle lvalue-to-lvalue assignments with a high-level copy_addr
// instruction if possible.
if (auto *srcLoad = dyn_cast<LoadExpr>(src)) {
// Check that the two l-value expressions have the same type.
// Compound l-values like (a,b) have tuple type, so this check
// also prevents us from getting into that case.
if (dest->getType()->isEqual(srcLoad->getSubExpr()->getType())) {
assert(!dest->getType()->is<TupleType>());
FormalEvaluationScope writeback(SGF);
auto destLV = SGF.emitLValue(dest, AccessKind::Write);
auto srcLV = SGF.emitLValue(srcLoad->getSubExpr(), AccessKind::Read);
SGF.emitAssignLValueToLValue(loc, std::move(srcLV), std::move(destLV));
return;
}
}
// Handle tuple destinations by destructuring them if present.
CanType destType = dest->getType()->getCanonicalType();
assert(!destType->isMaterializable() || destType->isVoid());
// But avoid this in the common case.
if (!isa<TupleType>(destType)) {
// If we're assigning to a discard, just emit the operand as ignored.
dest = dest->getSemanticsProvidingExpr();
if (isa<DiscardAssignmentExpr>(dest)) {
SGF.emitIgnoredExpr(src);
return;
}
FormalEvaluationScope writeback(SGF);
LValue destLV = SGF.emitLValue(dest, AccessKind::Write);
RValue srcRV = SGF.emitRValue(src);
SGF.emitAssignToLValue(loc, std::move(srcRV), std::move(destLV));
return;
}
FormalEvaluationScope writeback(SGF);
// Produce a flattened queue of LValues.
SmallVector<Optional<LValue>, 4> destLVs;
TupleLValueEmitter(SGF, AccessKind::Write, destLVs).visit(dest);
// Emit the r-value.
RValue srcRV = SGF.emitRValue(src);
// Recurse on the type of the destination, pulling LValues as
// needed from the queue we built up before.
TupleLValueAssigner(SGF, loc, destLVs).emit(destType, std::move(srcRV));
}
RValue RValueEmitter::visitAssignExpr(AssignExpr *E, SGFContext C) {
FullExpr scope(SGF.Cleanups, CleanupLocation(E));
emitSimpleAssignment(SGF, E, E->getDest(), E->getSrc());
return SGF.emitEmptyTupleRValue(E, C);
}
void SILGenFunction::emitBindOptional(SILLocation loc,
ManagedValue optionalAddrOrValue,
unsigned depth) {
assert(depth < BindOptionalFailureDests.size());
auto failureDest = BindOptionalFailureDests[BindOptionalFailureDests.size()
- depth - 1];
// Check whether the optional has a value.
SILBasicBlock *hasValueBB = createBasicBlock();
auto hasValue =
emitDoesOptionalHaveValue(loc, optionalAddrOrValue.getValue());
// If not, thread out through a bunch of cleanups.
SILBasicBlock *hasNoValueBB = Cleanups.emitBlockForCleanups(failureDest, loc);
B.createCondBranch(loc, hasValue, hasValueBB, hasNoValueBB);
// If so, continue.
B.emitBlock(hasValueBB);
}
RValue RValueEmitter::visitBindOptionalExpr(BindOptionalExpr *E, SGFContext C) {
// Create a temporary of type Optional<T> if it is address-only.
auto &optTL = SGF.getTypeLowering(E->getSubExpr()->getType());
ManagedValue optValue;
if (optTL.isLoadable()) {
optValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
} else {
auto temp = SGF.emitTemporary(E, optTL);
optValue = temp->getManagedAddress();
// Emit the operand into the temporary.
SGF.emitExprInto(E->getSubExpr(), temp.get());
}
// Check to see whether the optional is present, if not, jump to the current
// nil handler block.
SGF.emitBindOptional(E, optValue, E->getDepth());
// If we continued, get the value out as the result of the expression.
auto resultValue = SGF.emitUncheckedGetOptionalValueFrom(E, optValue,
optTL, C);
return RValue(SGF, E, resultValue);
}
namespace {
/// A RAII object to save and restore BindOptionalFailureDest.
class RestoreOptionalFailureDest {
SILGenFunction &SGF;
#ifndef NDEBUG
unsigned Depth;
#endif
public:
RestoreOptionalFailureDest(SILGenFunction &SGF, JumpDest &&dest)
: SGF(SGF)
#ifndef NDEBUG
, Depth(SGF.BindOptionalFailureDests.size())
#endif
{
SGF.BindOptionalFailureDests.push_back(std::move(dest));
}
~RestoreOptionalFailureDest() {
assert(SGF.BindOptionalFailureDests.size() == Depth + 1);
SGF.BindOptionalFailureDests.pop_back();
}
};
} // end anonymous namespace
/// emitOptimizedOptionalEvaluation - Look for cases where we can short-circuit
/// evaluation of an OptionalEvaluationExpr by pattern matching the AST.
///
static bool emitOptimizedOptionalEvaluation(SILGenFunction &SGF,
OptionalEvaluationExpr *E,
ManagedValue &result,
SGFContext ctx) {
// It is a common occurrence to get conversions back and forth from T! to T?.
// Peephole these by looking for a subexpression that is a BindOptionalExpr.
// If we see one, we can produce a single instruction, which doesn't require
// a CFG diamond.
//
// Check for:
// (optional_evaluation_expr type='T?'
// (inject_into_optional type='T?'
// (bind_optional_expr type='T'
// (whatever type='T?' ...)
auto *IIO = dyn_cast<InjectIntoOptionalExpr>(E->getSubExpr()
->getSemanticsProvidingExpr());
if (!IIO) return false;
// Make sure the bind is to the OptionalEvaluationExpr we're emitting.
auto *BO = dyn_cast<BindOptionalExpr>(IIO->getSubExpr()
->getSemanticsProvidingExpr());
if (!BO || BO->getDepth() != 0) return false;
// SIL defines away abstraction differences between T? and T!,
// so we can just emit the sub-initialization normally.
result = SGF.emitRValueAsSingleValue(BO->getSubExpr(), ctx);
return true;
}
RValue RValueEmitter::visitOptionalEvaluationExpr(OptionalEvaluationExpr *E,
SGFContext C) {
SmallVector<ManagedValue, 1> results;
SGF.emitOptionalEvaluation(E, E->getType(), results, C,
[&](SmallVectorImpl<ManagedValue> &results, SGFContext primaryC) {
ManagedValue result;
if (!emitOptimizedOptionalEvaluation(SGF, E, result, primaryC)) {
result = SGF.emitRValueAsSingleValue(E->getSubExpr(), primaryC);
}
assert(results.empty());
results.push_back(result);
});
assert(results.size() == 1);
if (results[0].isInContext()) {
return RValue();
} else {
return RValue(SGF, E, results[0]);
}
}
void SILGenFunction::emitOptionalEvaluation(SILLocation loc, Type optType,
SmallVectorImpl<ManagedValue> &results,
SGFContext C,
llvm::function_ref<void(SmallVectorImpl<ManagedValue> &,
SGFContext primaryC)>
generateNormalResults) {
assert(results.empty());
auto &optTL = getTypeLowering(optType);
Initialization *optInit = C.getEmitInto();
bool usingProvidedContext =
optInit && optInit->canPerformInPlaceInitialization();
// Form the optional using address operations if the type is address-only or
// if we already have an address to use.
bool isByAddress = ((usingProvidedContext || optTL.isAddressOnly()) &&
silConv.useLoweredAddresses());
std::unique_ptr<TemporaryInitialization> optTemp;
if (!isByAddress) {
// If the caller produced a context for us, but we're not going
// to use it, make sure we don't.
optInit = nullptr;
} else if (!usingProvidedContext) {
// Allocate the temporary for the Optional<T> if we didn't get one from the
// context. This needs to happen outside of the cleanups scope we're about
// to push.
optTemp = emitTemporary(loc, optTL);
optInit = optTemp.get();
}
assert(isByAddress == (optInit != nullptr));
// Acquire the address to emit into outside of the cleanups scope.
SILValue optAddr;
if (isByAddress)
optAddr = optInit->getAddressForInPlaceInitialization(*this, loc);
// Enter a cleanups scope.
FullExpr scope(Cleanups, CleanupLocation::get(loc));
// Inside of the cleanups scope, create a new initialization to
// emit into optAddr.
std::unique_ptr<TemporaryInitialization> normalInit;
if (isByAddress) {
normalInit = useBufferAsTemporary(optAddr, optTL);
}
// Install a new optional-failure destination just outside of the
// cleanups scope.
SILBasicBlock *failureBB = createBasicBlock();
RestoreOptionalFailureDest
restoreFailureDest(*this, JumpDest(failureBB, Cleanups.getCleanupsDepth(),
CleanupLocation::get(loc)));
generateNormalResults(results, SGFContext(normalInit.get()));
assert(results.size() >= 1 && "didn't include a normal result");
assert(results[0].isInContext() ||
results[0].getType().getObjectType()
== optTL.getLoweredType().getObjectType());
// If we're emitting into the context, make sure the normal value is there.
if (normalInit && !results[0].isInContext()) {
normalInit->copyOrInitValueInto(*this, loc, results[0], /*init*/ true);
normalInit->finishInitialization(*this);
results[0] = ManagedValue::forInContext();
}
// We fell out of the normal result, which generated a T? as either
// a scalar in normalArgument or directly into normalInit.
// If we're using by-address initialization, we must've emitted into
// normalInit. Forward its cleanup before popping the scope.
if (isByAddress) {
normalInit->getManagedAddress().forward(*this);
normalInit.reset(); // Make sure we don't use this anymore.
} else {
assert(!results[0].isInContext());
results[0].forward(*this);
}
// For all the secondary results, forward their cleanups and make sure
// they're of optional type so that we can inject nil into them in
// the failure path.
// (Should this be controllable by the client?)
for (auto &result : MutableArrayRef<ManagedValue>(results).slice(1)) {
assert(!result.isInContext() && "secondary result was in context");
auto resultTy = result.getType();
assert(resultTy.isObject() && "secondary result wasn't an object");
// Forward the cleanup.
SILValue value = result.forward(*this);
// If it's not already an optional type, make it optional.
if (!resultTy.getAnyOptionalObjectType()) {
resultTy = SILType::getOptionalType(resultTy);
value = B.createOptionalSome(loc, value, resultTy);
result = ManagedValue::forUnmanaged(value);
}
}
// This concludes the conditional scope.
scope.pop();
// In the usual case, the code will have emitted one or more branches to the
// failure block. However, if the body is simple enough, we can end up with
// no branches to the failureBB. Detect this and simplify the generated code
// if so.
if (failureBB->pred_empty()) {
// Remove the dead failureBB.
failureBB->eraseFromParent();
// Just re-manage all the secondary results.
for (auto &result : MutableArrayRef<ManagedValue>(results).slice(1)) {
result = emitManagedRValueWithCleanup(result.getValue());
}
// Just re-manage the main result if we're not using address-based IRGen.
if (!isByAddress) {
results[0] = emitManagedRValueWithCleanup(results[0].getValue(), optTL);
return;
}
// Otherwise, we must have emitted into normalInit, which means that,
// now that we're out of the cleanups scope, we need to finish optInit.
assert(results[0].isInContext());
optInit->finishInitialization(*this);
// If optInit came from the SGFContext, then we've successfully emitted
// into that.
if (usingProvidedContext) return;
// Otherwise, we must have emitted into optTemp.
assert(optTemp);
results[0] = optTemp->getManagedAddress();
return;
}
// Okay, we do have uses of the failure block, so we'll need to merge
// control paths.
SILBasicBlock *contBB = createBasicBlock();
// Branch to the continuation block.
SmallVector<SILValue, 4> bbArgs;
if (!isByAddress)
bbArgs.push_back(results[0].getValue());
for (const auto &result : llvm::makeArrayRef(results).slice(1))
bbArgs.push_back(result.getValue());
// Branch to the continuation block.
B.createBranch(loc, contBB, bbArgs);
// In the failure block, inject nil into the result.
B.emitBlock(failureBB);
// Note that none of the code here introduces any cleanups.
// If it did, we'd need to push a scope.
bbArgs.clear();
if (isByAddress) {
emitInjectOptionalNothingInto(loc, optAddr, optTL);
} else {
bbArgs.push_back(getOptionalNoneValue(loc, optTL));
}
for (const auto &result : llvm::makeArrayRef(results).slice(1)) {
auto resultTy = result.getType();
bbArgs.push_back(getOptionalNoneValue(loc, getTypeLowering(resultTy)));
}
B.createBranch(loc, contBB, bbArgs);
// Emit the continuation block.
B.emitBlock(contBB);
// Create a PHI for the optional result if desired.
if (isByAddress) {
assert(results[0].isInContext());
} else {
auto arg = contBB->createPHIArgument(optTL.getLoweredType(),
ValueOwnershipKind::Owned);
results[0] = emitManagedRValueWithCleanup(arg, optTL);
}
// Create PHIs for all the secondary results and manage them.
for (auto &result : MutableArrayRef<ManagedValue>(results).slice(1)) {
auto arg = contBB->createPHIArgument(result.getType(),
ValueOwnershipKind::Owned);
result = emitManagedRValueWithCleanup(arg);
}
// We may need to manage the value in optInit.
if (!isByAddress) return;
assert(results[0].isInContext());
optInit->finishInitialization(*this);
// If we didn't emit into the provided context, the primary result
// is really a temporary.
if (usingProvidedContext) return;
assert(optTemp);
results[0] = optTemp->getManagedAddress();
}
RValue RValueEmitter::visitForceValueExpr(ForceValueExpr *E, SGFContext C) {
return emitForceValue(E, E->getSubExpr(), 0, C);
}
/// Emit an expression in a forced context.
///
/// \param loc - the location that is causing the force
/// \param E - the forced expression
/// \param numOptionalEvaluations - the number of enclosing
/// OptionalEvaluationExprs that we've opened.
RValue RValueEmitter::emitForceValue(SILLocation loc, Expr *E,
unsigned numOptionalEvaluations,
SGFContext C) {
auto valueType = E->getType()->getAnyOptionalObjectType();
assert(valueType);
E = E->getSemanticsProvidingExpr();
// If the subexpression is a conditional checked cast, emit an unconditional
// cast, which drastically simplifies the generated SIL for something like:
//
// (x as? Foo)!
if (auto checkedCast = dyn_cast<ConditionalCheckedCastExpr>(E)) {
return emitUnconditionalCheckedCast(SGF, loc, checkedCast->getSubExpr(),
valueType, checkedCast->getCastKind(),
C);
}
// If the subexpression is a monadic optional operation, peephole
// the emission of the operation.
if (auto eval = dyn_cast<OptionalEvaluationExpr>(E)) {
CleanupLocation cleanupLoc = CleanupLocation::get(loc);
SILBasicBlock *failureBB;
JumpDest failureDest(cleanupLoc);
// Set up an optional-failure scope (which cannot actually return).
// We can just borrow the enclosing one if we're in a nested context.
if (numOptionalEvaluations) {
failureBB = nullptr; // remember that we did this
failureDest = SGF.BindOptionalFailureDests.back();
} else {
failureBB = SGF.createBasicBlock(FunctionSection::Postmatter);
failureDest = JumpDest(failureBB, SGF.Cleanups.getCleanupsDepth(),
cleanupLoc);
}
RestoreOptionalFailureDest restoreFailureDest(SGF, std::move(failureDest));
RValue result = emitForceValue(loc, eval->getSubExpr(),
numOptionalEvaluations + 1, C);
// Emit the failure destination, but only if actually used.
if (failureBB) {
if (failureBB->pred_empty()) {
SGF.eraseBasicBlock(failureBB);
} else {
SILGenBuilder failureBuilder(SGF, failureBB);
failureBuilder.setTrackingList(SGF.getBuilder().getTrackingList());
auto boolTy = SILType::getBuiltinIntegerType(1, SGF.getASTContext());
auto trueV = failureBuilder.createIntegerLiteral(loc, boolTy, 1);
failureBuilder.createCondFail(loc, trueV);
failureBuilder.createUnreachable(loc);
}
}
return result;
}
// Handle injections.
if (auto injection = dyn_cast<InjectIntoOptionalExpr>(E)) {
auto subexpr = injection->getSubExpr()->getSemanticsProvidingExpr();
// An injection of a bind is the idiom for a conversion between
// optional types (e.g. ImplicitlyUnwrappedOptional<T> -> Optional<T>).
// Handle it specially to avoid unnecessary control flow.
if (auto bindOptional = dyn_cast<BindOptionalExpr>(subexpr)) {
if (bindOptional->getDepth() < numOptionalEvaluations) {
return emitForceValue(loc, bindOptional->getSubExpr(),
numOptionalEvaluations, C);
}
}
// Otherwise, just emit the injected value directly into the result.
return SGF.emitRValue(injection->getSubExpr(), C);
}
// Otherwise, emit the optional and force its value out.
const TypeLowering &optTL = SGF.getTypeLowering(E->getType());
ManagedValue opt = SGF.emitRValueAsSingleValue(E);
ManagedValue V =
SGF.emitCheckedGetOptionalValueFrom(loc, opt, optTL, C);
return RValue(SGF, loc, valueType->getCanonicalType(), V);
}
void SILGenFunction::emitOpenExistentialExprImpl(
OpenExistentialExpr *E,
llvm::function_ref<void(Expr *)> emitSubExpr) {
Optional<FormalEvaluationScope> writebackScope;
// Emit the existential value.
ManagedValue existentialValue;
AccessKind accessKind;
if (E->getExistentialValue()->getType()->is<LValueType>()) {
// Create a writeback scope for the access to the existential lvalue.
writebackScope.emplace(*this);
accessKind = E->getExistentialValue()->getLValueAccessKind();
existentialValue = emitAddressOfLValue(
E->getExistentialValue(),
emitLValue(E->getExistentialValue(), accessKind),
accessKind);
} else {
accessKind = AccessKind::Read;
existentialValue = emitRValueAsSingleValue(
E->getExistentialValue(),
SGFContext::AllowGuaranteedPlusZero);
}
Type opaqueValueType = E->getOpaqueValue()->getType()->getRValueType();
SILGenFunction::OpaqueValueState state = emitOpenExistential(
E, existentialValue, E->getOpenedArchetype(),
getLoweredType(opaqueValueType), accessKind);
// Register the opaque value for the projected existential.
SILGenFunction::OpaqueValueRAII opaqueValueRAII(
*this, E->getOpaqueValue(), state);
emitSubExpr(E->getSubExpr());
}
RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E,
SGFContext C) {
return SGF.emitOpenExistentialExpr<RValue>(E,
[&](Expr *subExpr) -> RValue {
return visit(subExpr, C);
});
}
RValue RValueEmitter::visitMakeTemporarilyEscapableExpr(
MakeTemporarilyEscapableExpr *E,
SGFContext C) {
// TODO: Some day we want to specialize the representation of nonescaping
// closures to be POD and allow an arbitrary payload in their context word.
// At that point, this operation would need to wrap the nonescaping closure
// in an escaping stub, which we could dynamically check at the end of the
// expression to verify it did not in fact escape at runtime. For now, to
// get the syntax for withoutActuallyEscaping in place, this is a no-op.
// Emit the closure and bind it to an opaque value for use in the
// subexpression.
auto closure = visit(E->getNonescapingClosureValue());
SILGenFunction::OpaqueValueState opaqueValue{
std::move(closure).getAsSingleValue(SGF, E),
/*consumable*/ true,
/*hasBeenConsumed*/ false,
};
SILGenFunction::OpaqueValueRAII pushOpaqueValue(SGF, E->getOpaqueValue(),
opaqueValue);
return visit(E->getSubExpr(), C);
}
RValue RValueEmitter::visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C) {
assert(SGF.OpaqueValues.count(E) && "Didn't bind OpaqueValueExpr");
auto &entry = SGF.OpaqueValues[E];
return RValue(SGF, E, SGF.manageOpaqueValue(entry, E, C));
}
ProtocolDecl *SILGenFunction::getPointerProtocol() {
if (SGM.PointerProtocol)
return *SGM.PointerProtocol;
SmallVector<ValueDecl*, 1> lookup;
getASTContext().lookupInSwiftModule("_Pointer", lookup);
// FIXME: Should check for protocol in Sema
assert(lookup.size() == 1 && "no _Pointer protocol");
assert(isa<ProtocolDecl>(lookup[0]) && "_Pointer is not a protocol");
SGM.PointerProtocol = cast<ProtocolDecl>(lookup[0]);
return cast<ProtocolDecl>(lookup[0]);
}
namespace {
class AutoreleasingWritebackComponent : public LogicalPathComponent {
public:
AutoreleasingWritebackComponent(LValueTypeData typeData)
: LogicalPathComponent(typeData, AutoreleasingWritebackKind)
{}
std::unique_ptr<LogicalPathComponent>
clone(SILGenFunction &gen, SILLocation l) const override {
return std::unique_ptr<LogicalPathComponent>(
new AutoreleasingWritebackComponent(getTypeData()));
}
AccessKind getBaseAccessKind(SILGenFunction &gen,
AccessKind kind) const override {
return kind;
}
void set(SILGenFunction &gen, SILLocation loc,
RValue &&value, ManagedValue base) && override {
// Convert the value back to a +1 strong reference.
auto unowned = std::move(value).getAsSingleValue(gen, loc).getUnmanagedValue();
auto strongType = SILType::getPrimitiveObjectType(
unowned->getType().castTo<UnmanagedStorageType>().getReferentType());
auto owned = gen.B.createUnmanagedToRef(loc, unowned, strongType);
auto ownedMV = gen.emitManagedRetain(loc, owned);
// Reassign the +1 storage with it.
ownedMV.assignInto(gen, loc, base.getUnmanagedValue());
}
RValue get(SILGenFunction &gen, SILLocation loc,
ManagedValue base, SGFContext c) && override {
FullExpr TightBorrowScope(gen.Cleanups, CleanupLocation::get(loc));
// Load the value at +0.
ManagedValue loadedBase = gen.B.createLoadBorrow(loc, base);
// Convert it to unowned.
auto refType = loadedBase.getType().getSwiftRValueType();
auto unownedType = SILType::getPrimitiveObjectType(
CanUnmanagedStorageType::get(refType));
SILValue unowned = gen.B.createRefToUnmanaged(
loc, loadedBase.getUnmanagedValue(), unownedType);
// A reference type should never be exploded.
return RValue::withPreExplodedElements(ManagedValue::forUnmanaged(unowned),
refType);
}
/// Compare 'this' lvalue and the 'rhs' lvalue (which is guaranteed to have
/// the same dynamic PathComponent type as the receiver) to see if they are
/// identical. If so, there is a conflicting writeback happening, so emit a
/// diagnostic.
void diagnoseWritebackConflict(LogicalPathComponent *RHS,
SILLocation loc1, SILLocation loc2,
SILGenFunction &gen) override {
// auto &rhs = (GetterSetterComponent&)*RHS;
}
void print(raw_ostream &OS) const override {
OS << "AutoreleasingWritebackComponent()\n";
}
};
} // end anonymous namespace
SILGenFunction::PointerAccessInfo
SILGenFunction::getPointerAccessInfo(Type type) {
PointerTypeKind pointerKind;
Type elt = type->getAnyPointerElementType(pointerKind);
assert(elt && "not a pointer");
(void)elt;
AccessKind accessKind =
((pointerKind == PTK_UnsafePointer || pointerKind == PTK_UnsafeRawPointer)
? AccessKind::Read : AccessKind::ReadWrite);
return { type->getCanonicalType(), pointerKind, accessKind };
}
RValue RValueEmitter::visitInOutToPointerExpr(InOutToPointerExpr *E,
SGFContext C) {
// If we're converting on the behalf of an
// AutoreleasingUnsafeMutablePointer, convert the lvalue to
// unowned(unsafe), so we can point at +0 storage.
auto accessInfo = SGF.getPointerAccessInfo(E->getType());
// Get the original lvalue.
LValue lv = SGF.emitLValue(E->getSubExpr(), accessInfo.AccessKind);
auto ptr = SGF.emitLValueToPointer(E, std::move(lv), accessInfo);
return RValue(SGF, E, ptr);
}
/// Convert an l-value to a pointer type: unsafe, unsafe-mutable, or
/// autoreleasing-unsafe-mutable.
ManagedValue SILGenFunction::emitLValueToPointer(SILLocation loc, LValue &&lv,
PointerAccessInfo pointerInfo) {
// The incoming lvalue should be at the abstraction level of T in
// Unsafe*Pointer<T>. Reabstract it if necessary.
auto opaqueTy = AbstractionPattern::getOpaque();
auto loweredTy = getLoweredType(opaqueTy, lv.getSubstFormalType());
if (lv.getTypeOfRValue().getSwiftRValueType()
!= loweredTy.getSwiftRValueType()) {
lv.addSubstToOrigComponent(opaqueTy, loweredTy);
}
switch (pointerInfo.PointerKind) {
case PTK_UnsafeMutablePointer:
case PTK_UnsafePointer:
case PTK_UnsafeMutableRawPointer:
case PTK_UnsafeRawPointer:
// +1 is fine.
break;
case PTK_AutoreleasingUnsafeMutablePointer: {
// Set up a writeback through a +0 buffer.
LValueTypeData typeData = lv.getTypeData();
SILType rvalueType = SILType::getPrimitiveObjectType(
CanUnmanagedStorageType::get(typeData.TypeOfRValue.getSwiftRValueType()));
LValueTypeData unownedTypeData(
AbstractionPattern(
typeData.OrigFormalType.getGenericSignature(),
CanUnmanagedStorageType::get(typeData.OrigFormalType.getType())),
CanUnmanagedStorageType::get(typeData.SubstFormalType),
rvalueType);
lv.add<AutoreleasingWritebackComponent>(unownedTypeData);
break;
}
}
// Get the lvalue address as a raw pointer.
auto accessKind = pointerInfo.AccessKind;
SILValue address =
emitAddressOfLValue(loc, std::move(lv), accessKind).getUnmanagedValue();
address = B.createAddressToPointer(loc, address,
SILType::getRawPointerType(getASTContext()));
// Disable nested writeback scopes for any calls evaluated during the
// conversion intrinsic.
InOutConversionScope scope(*this);
// Invoke the conversion intrinsic.
FuncDecl *converter =
getASTContext().getConvertInOutToPointerArgument(nullptr);
auto pointerType = pointerInfo.PointerType;
auto subMap = pointerType->getContextSubstitutionMap(SGM.M.getSwiftModule(),
getPointerProtocol());
return emitApplyOfLibraryIntrinsic(loc, converter, subMap,
ManagedValue::forUnmanaged(address),
SGFContext())
.getAsSingleValue(*this, loc);
}
static std::pair<ManagedValue, ManagedValue>
emitArrayToPointer(SILGenFunction &SGF, SILLocation loc, ManagedValue array,
SILGenFunction::ArrayAccessInfo accessInfo) {
auto &ctx = SGF.getASTContext();
FuncDecl *converter;
if (accessInfo.AccessKind == AccessKind::Read) {
converter = ctx.getConvertConstArrayToPointerArgument(nullptr);
if (array.isLValue())
array = SGF.B.createLoadCopy(loc, array);
} else {
converter = ctx.getConvertMutableArrayToPointerArgument(nullptr);
assert(array.isLValue());
}
// Invoke the conversion intrinsic, which will produce an owner-pointer pair.
auto *M = SGF.SGM.M.getSwiftModule();
auto firstSubMap =
accessInfo.ArrayType->getContextSubstitutionMap(M, ctx.getArrayDecl());
auto secondSubMap =
accessInfo.PointerType->getContextSubstitutionMap(M,
SGF.getPointerProtocol());
auto *genericSig = converter->getGenericSignature();
auto subMap =
SubstitutionMap::combineSubstitutionMaps(firstSubMap,
secondSubMap,
CombineSubstitutionMaps::AtIndex,
1, 0,
genericSig);
SmallVector<ManagedValue, 2> resultScalars;
SGF.emitApplyOfLibraryIntrinsic(loc, converter, subMap, array, SGFContext())
.getAll(resultScalars);
assert(resultScalars.size() == 2);
// Mark the dependence of the pointer on the owner value.
auto owner = resultScalars[0];
auto pointer = resultScalars[1].forward(SGF);
pointer = SGF.B.createMarkDependence(loc, pointer, owner.getValue());
// The owner's already in its own cleanup. Return the pointer.
return {ManagedValue::forTrivialObjectRValue(pointer), owner};
}
RValue RValueEmitter::visitArrayToPointerExpr(ArrayToPointerExpr *E,
SGFContext C) {
FormalEvaluationScope writeback(SGF);
auto subExpr = E->getSubExpr();
auto accessInfo = SGF.getArrayAccessInfo(E->getType(),
subExpr->getType()->getInOutObjectType());
// Convert the array mutably if it's being passed inout.
ManagedValue array;
if (accessInfo.AccessKind != AccessKind::Read) {
array = SGF.emitAddressOfLValue(subExpr,
SGF.emitLValue(subExpr, AccessKind::ReadWrite),
AccessKind::ReadWrite);
} else {
array = SGF.emitRValueAsSingleValue(subExpr);
}
auto pointer = ::emitArrayToPointer(SGF, E, array, accessInfo).first;
return RValue(SGF, E, pointer);
}
SILGenFunction::ArrayAccessInfo
SILGenFunction::getArrayAccessInfo(Type pointerType, Type arrayType) {
auto pointerAccessInfo = getPointerAccessInfo(pointerType);
return { pointerType, arrayType, pointerAccessInfo.AccessKind };
}
std::pair<ManagedValue, ManagedValue>
SILGenFunction::emitArrayToPointer(SILLocation loc, LValue &&lv,
ArrayAccessInfo accessInfo) {
auto array =
emitAddressOfLValue(loc, std::move(lv), accessInfo.AccessKind);
return ::emitArrayToPointer(*this, loc, array, accessInfo);
}
std::pair<ManagedValue, ManagedValue>
SILGenFunction::emitArrayToPointer(SILLocation loc, ManagedValue array,
ArrayAccessInfo accessInfo) {
return ::emitArrayToPointer(*this, loc, array, accessInfo);
}
RValue RValueEmitter::visitStringToPointerExpr(StringToPointerExpr *E,
SGFContext C) {
// Get the original value.
ManagedValue orig = SGF.emitRValueAsSingleValue(E->getSubExpr());
// Perform the conversion.
auto results = SGF.emitStringToPointer(E, orig, E->getType());
// Implicitly leave the owner managed and return the pointer.
return RValue(SGF, E, results.first);
}
std::pair<ManagedValue, ManagedValue>
SILGenFunction::emitStringToPointer(SILLocation loc, ManagedValue stringValue,
Type pointerType) {
auto &Ctx = getASTContext();
FuncDecl *converter = Ctx.getConvertConstStringToUTF8PointerArgument(nullptr);
// Invoke the conversion intrinsic, which will produce an owner-pointer pair.
auto subMap = pointerType->getContextSubstitutionMap(SGM.M.getSwiftModule(),
getPointerProtocol());
SmallVector<ManagedValue, 2> results;
emitApplyOfLibraryIntrinsic(loc, converter, subMap, stringValue, SGFContext())
.getAll(results);
assert(results.size() == 2);
// Mark the dependence of the pointer on the owner value.
auto owner = results[0];
auto pointer = results[1].forward(*this);
pointer = B.createMarkDependence(loc, pointer, owner.getValue());
return {ManagedValue::forTrivialObjectRValue(pointer), owner};
}
RValue RValueEmitter::visitPointerToPointerExpr(PointerToPointerExpr *E,
SGFContext C) {
auto &Ctx = SGF.getASTContext();
auto converter = Ctx.getConvertPointerToPointerArgument(nullptr);
// Get the original pointer value, abstracted to the converter function's
// expected level.
AbstractionPattern origTy(converter->getInterfaceType());
origTy = origTy.getFunctionInputType();
CanType inputTy = E->getSubExpr()->getType()->getCanonicalType();
auto &origTL = SGF.getTypeLowering(origTy, inputTy);
ManagedValue orig = SGF.emitRValueAsOrig(E->getSubExpr(), origTy, origTL);
CanType outputTy = E->getType()->getCanonicalType();
return SGF.emitPointerToPointer(E, orig, inputTy, outputTy, C);
}
RValue RValueEmitter::visitForeignObjectConversionExpr(
ForeignObjectConversionExpr *E,
SGFContext C) {
// Get the original value.
ManagedValue orig = SGF.emitRValueAsSingleValue(E->getSubExpr());
ManagedValue result(SGF.B.createUncheckedRefCast(
E, orig.getValue(),
SGF.getLoweredType(E->getType())),
orig.getCleanup());
return RValue(SGF, E, E->getType()->getCanonicalType(), result);
}
RValue RValueEmitter::visitUnevaluatedInstanceExpr(UnevaluatedInstanceExpr *E,
SGFContext C) {
llvm_unreachable("unevaluated_instance expression can never be evaluated");
}
RValue SILGenFunction::emitRValue(Expr *E, SGFContext C) {
assert(E->getType()->isMaterializable() &&
"l-values must be emitted with emitLValue");
return RValueEmitter(*this).visit(E, C);
}
// Evaluate the expression as an lvalue or rvalue, discarding the result.
void SILGenFunction::emitIgnoredExpr(Expr *E) {
// If this is a tuple expression, recursively ignore its elements.
// This may let us recursively avoid work.
if (auto *TE = dyn_cast<TupleExpr>(E)) {
for (auto *elt : TE->getElements())
emitIgnoredExpr(elt);
return;
}
// TODO: Could look through arbitrary implicit conversions that don't have
// side effects, or through tuple shuffles, by emitting ignored default
// arguments.
FullExpr scope(Cleanups, CleanupLocation(E));
if (!E->getType()->isMaterializable()) {
// Emit the l-value, but don't perform an access.
FormalEvaluationScope scope(*this);
emitLValue(E, AccessKind::Read);
return;
}
// If this is a load expression, we try hard not to actually do the load
// (which could materialize a potentially expensive value with cleanups).
if (auto *LE = dyn_cast<LoadExpr>(E)) {
FormalEvaluationScope scope(*this);
LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
// If the lvalue is purely physical, then it won't have any side effects,
// and we don't need to drill into it.
if (lv.isPhysical())
return;
// If the last component is physical, then we just need to drill through
// side effects in the lvalue, but don't need to perform the final load.
if (lv.isLastComponentPhysical()) {
emitAddressOfLValue(E, std::move(lv), AccessKind::Read);
return;
}
// Otherwise, we must call the ultimate getter to get its potential side
// effect.
emitLoadOfLValue(E, std::move(lv), SGFContext::AllowImmediatePlusZero);
return;
}
// Otherwise, emit the result (to get any side effects), but produce it at +0
// if that allows simplification.
emitRValue(E, SGFContext::AllowImmediatePlusZero);
}
/// Emit the given expression as an r-value, then (if it is a tuple), combine
/// it together into a single ManagedValue.
ManagedValue SILGenFunction::emitRValueAsSingleValue(Expr *E, SGFContext C) {
RValue &&rv = emitRValue(E, C);
if (rv.isUsed()) return ManagedValue::forInContext();
return std::move(rv).getAsSingleValue(*this, E);
}
RValue SILGenFunction::emitUndefRValue(SILLocation loc, Type type) {
return RValue(*this, loc, type->getCanonicalType(),
emitUndef(loc, getLoweredType(type)));
}
ManagedValue SILGenFunction::emitUndef(SILLocation loc, Type type) {
return emitUndef(loc, getLoweredType(type));
}
ManagedValue SILGenFunction::emitUndef(SILLocation loc, SILType type) {
SILValue undef = SILUndef::get(type, SGM.M);
return ManagedValue::forUnmanaged(undef);
}