Files
swift-mirror/lib/SILGen/SILGenApply.cpp
Ted Kremenek a4f8afc3e6 Using an optional for 'SILDeclRef::Kind' value (-Wconditional-uninitialized).
This looks like this may always be initialized, but the logic is
a bit harder to follow and this simple extra checking doesn't
really cost us.

Swift SVN r17615
2014-05-07 07:34:50 +00:00

3178 lines
126 KiB
C++

//===--- SILGenApply.cpp - Constructs call sites for SILGen ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "LValue.h"
#include "RValue.h"
#include "Scope.h"
#include "Initialization.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/Module.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/PrettyStackTrace.h"
using namespace swift;
using namespace Lowering;
/// Retrieve the type to use for a method found via dynamic lookup.
static CanAnyFunctionType getDynamicMethodFormalType(SILGenModule &SGM,
SILValue proto,
ValueDecl *member,
SILDeclRef methodName,
Type memberType) {
auto &ctx = SGM.getASTContext();
CanType selfTy;
if (member->isInstanceMember()) {
selfTy = ctx.TheUnknownObjectType;
} else {
selfTy = proto.getType().getSwiftType();
}
auto extInfo = FunctionType::ExtInfo()
.withCallingConv(SGM.getConstantCC(methodName))
.withRepresentation(FunctionType::Representation::Thin);
return CanFunctionType::get(selfTy, memberType->getCanonicalType(),
extInfo);
}
/// Replace the 'self' parameter in the given type.
static CanSILFunctionType
replaceSelfTypeForDynamicLookup(ASTContext &ctx,
CanSILFunctionType fnType,
CanType newSelfType,
SILDeclRef methodName) {
auto oldParams = fnType->getInterfaceParameters();
SmallVector<SILParameterInfo, 4> newParams;
newParams.append(oldParams.begin(), oldParams.end() - 1);
newParams.push_back({newSelfType, oldParams.back().getConvention()});
auto newResult = fnType->getInterfaceResult();
// If the method returns Self, substitute AnyObject for the result type.
if (auto fnDecl = dyn_cast<FuncDecl>(methodName.getDecl())) {
if (fnDecl->hasDynamicSelf()) {
auto anyObjectTy = ctx.getProtocol(KnownProtocolKind::AnyObject)
->getDeclaredType();
auto newResultTy
= newResult.getType()->replaceCovariantResultType(anyObjectTy, 0);
newResult = SILResultInfo(newResultTy->getCanonicalType(),
newResult.getConvention());
}
}
return SILFunctionType::get(nullptr,
fnType->getExtInfo(),
fnType->getCalleeConvention(),
newParams,
newResult,
ctx);
}
/// Retrieve the type to use for a method found via dynamic lookup.
static CanSILFunctionType getDynamicMethodLoweredType(SILGenModule &SGM,
SILValue proto,
SILDeclRef methodName) {
auto &ctx = SGM.getASTContext();
// Determine the opaque 'self' parameter type.
CanType selfTy;
if (methodName.getDecl()->isInstanceMember()) {
selfTy = ctx.TheUnknownObjectType;
} else {
selfTy = proto.getType().getSwiftType();
}
// Replace the 'self' parameter type in the method type with it.
auto methodTy = SGM.getConstantType(methodName).castTo<SILFunctionType>();
return replaceSelfTypeForDynamicLookup(ctx, methodTy, selfTy, methodName);
}
namespace {
/// Abstractly represents a callee, and knows how to emit the entry point
/// reference for a callee at any valid uncurry level.
class Callee {
public:
enum class Kind {
/// An indirect function value.
IndirectValue,
/// A direct standalone function call, referenceable by a FunctionRefInst.
StandaloneFunction,
VirtualMethod_First,
/// A method call using class method dispatch.
ClassMethod = VirtualMethod_First,
/// A method call using super method dispatch.
SuperMethod,
VirtualMethod_Last = SuperMethod,
GenericMethod_First,
/// A method call using archetype dispatch.
WitnessMethod = GenericMethod_First,
/// A method call using protocol dispatch.
ProtocolMethod,
/// A method call using dynamic lookup.
DynamicMethod,
GenericMethod_Last = DynamicMethod
};
const Kind kind;
using SpecializedEmitter = ManagedValue (*)(SILGenFunction &,
SILLocation,
ArrayRef<Substitution>,
ArrayRef<ManagedValue>,
SGFContext);
// Move, don't copy.
Callee(const Callee &) = delete;
Callee &operator=(const Callee &) = delete;
private:
union {
ManagedValue indirectValue;
SILDeclRef standaloneFunction;
struct {
SILValue selfValue;
SILDeclRef methodName;
} method;
};
ArrayRef<Substitution> substitutions;
CanType OrigFormalOldType, OrigFormalInterfaceType;
CanAnyFunctionType SubstFormalType;
Optional<SILLocation> specializeLoc;
bool isTransparent;
bool HasSubstitutions = false;
// The pointer back to the AST node that produced the callee.
SILLocation Loc;
static SpecializedEmitter getSpecializedEmitterForSILBuiltin(SILDeclRef c,
SILModule &M);
Callee(ManagedValue indirectValue,
CanType origFormalType,
CanAnyFunctionType substFormalType,
bool isTransparent, SILLocation L)
: kind(Kind::IndirectValue),
indirectValue(indirectValue),
OrigFormalOldType(origFormalType),
OrigFormalInterfaceType(origFormalType),
SubstFormalType(substFormalType),
isTransparent(isTransparent),
Loc(L)
{}
static CanAnyFunctionType getConstantFormalType(SILGenFunction &gen,
SILValue selfValue,
SILDeclRef fn)
SIL_FUNCTION_TYPE_DEPRECATED {
return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0)).FormalType;
}
static CanAnyFunctionType getConstantFormalInterfaceType(SILGenFunction &gen,
SILValue selfValue,
SILDeclRef fn) {
return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0))
.FormalInterfaceType;
}
Callee(SILGenFunction &gen, SILDeclRef standaloneFunction,
CanAnyFunctionType substFormalType,
SILLocation l)
: kind(Kind::StandaloneFunction), standaloneFunction(standaloneFunction),
OrigFormalOldType(getConstantFormalType(gen, SILValue(),
standaloneFunction)),
OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, SILValue(),
standaloneFunction)),
SubstFormalType(substFormalType),
isTransparent(standaloneFunction.isTransparent()),
Loc(l)
{
}
Callee(Kind methodKind,
SILGenFunction &gen,
SILValue selfValue,
SILDeclRef methodName,
CanAnyFunctionType substFormalType,
SILLocation l)
: kind(methodKind), method{selfValue, methodName},
OrigFormalOldType(getConstantFormalType(gen, selfValue, methodName)),
OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, selfValue,
methodName)),
SubstFormalType(substFormalType),
isTransparent(false),
Loc(l)
{
}
static CanArchetypeType getArchetypeForSelf(CanType selfType) {
if (auto mt = dyn_cast<MetatypeType>(selfType)) {
return cast<ArchetypeType>(mt.getInstanceType());
} else {
return cast<ArchetypeType>(selfType);
}
}
/// Build a clause that looks like 'origParamType' but uses 'selfType'
/// in place of the underlying archetype.
static CanType buildSubstSelfType(CanType origParamType, CanType selfType,
ASTContext &ctx) {
assert(!isa<LValueType>(origParamType) && "Self can't be @lvalue");
if (auto lv = dyn_cast<InOutType>(origParamType)) {
selfType = buildSubstSelfType(lv.getObjectType(), selfType, ctx);
return CanInOutType::get(selfType);
}
if (auto tuple = dyn_cast<TupleType>(origParamType)) {
assert(tuple->getNumElements() == 1);
selfType = buildSubstSelfType(tuple.getElementType(0), selfType, ctx);
auto field = tuple->getFields()[0].getWithType(selfType);
return CanType(TupleType::get(field, ctx));
}
// These first two asserts will crash before they return if
// they're actually wrong.
assert(getArchetypeForSelf(origParamType));
assert(getArchetypeForSelf(selfType));
assert(isa<MetatypeType>(origParamType) == isa<MetatypeType>(selfType));
return selfType;
}
CanSILFunctionType getSubstFunctionType(SILGenModule &SGM,
CanSILFunctionType origFnType,
CanAnyFunctionType origLoweredType,
unsigned uncurryLevel) const {
if (!HasSubstitutions) return origFnType;
assert(origLoweredType);
auto substLoweredType =
SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel,
origLoweredType->getExtInfo());
auto substLoweredInterfaceType =
SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel,
origLoweredType->getExtInfo());
return SGM.Types.substFunctionType(origFnType, origLoweredType,
substLoweredType,
substLoweredInterfaceType);
}
/// Return the value being passed as 'self' for this protocol callee.
CanType getProtocolSelfType(SILGenModule &SGM) const {
if (kind == Kind::ProtocolMethod) {
auto member = method.methodName.getDecl();
auto proto = cast<ProtocolDecl>(member->getDeclContext());
auto type = proto->getSelf()->getArchetype()->getCanonicalType();
if (!member->isInstanceMember())
type = CanMetatypeType::get(type);
return type;
} else if (kind == Kind::WitnessMethod) {
return method.selfValue.getType().getSwiftRValueType();
} else {
llvm_unreachable("bad callee kind for protocol method");
}
}
/// Add the 'self' clause back to the substituted formal type of
/// this protocol method.
void addProtocolSelfToFormalType(SILGenModule &SGM, SILDeclRef name) {
// The result types of the expressions yielding protocol values
// (reflected in SubstFormalType) reflect an implicit level of
// function application, including some extra polymorphic
// substitution.
HasSubstitutions = true;
auto &ctx = SGM.getASTContext();
// Add the 'self' parameter back. We want it to look like a
// substitution of the appropriate clause from the original type.
auto polyFormalType = cast<PolymorphicFunctionType>(OrigFormalOldType);
auto selfType = getProtocolSelfType(SGM);
auto substSelfType =
buildSubstSelfType(polyFormalType.getInput(), selfType, ctx);
// Existential witnesses are always "thick" with the polymorphic info,
// unless @objc.
auto rep = name.isForeign
? FunctionType::Representation::Thin
: FunctionType::Representation::Thick;
auto extInfo = FunctionType::ExtInfo(AbstractCC::Method, rep,
/*noreturn*/ false);
SubstFormalType = CanFunctionType::get(substSelfType, SubstFormalType,
extInfo);
}
SILType getProtocolClosureType(SILGenModule &SGM,
SILDeclRef constant,
SILConstantInfo &constantInfo,
CanArchetypeType &archetype) const {
auto &C = SGM.getASTContext();
CanType selfType = getProtocolSelfType(SGM);
// Find the archetype.
archetype = getArchetypeForSelf(selfType);
// addProtocolSelfToFormalType initializes SubstFormalType->isThin()
// appropriately for the archetype kind.
FunctionType::Representation rep = SubstFormalType->getRepresentation();
// We may need to make the OrigLoweredType thick so that
// computing the substFnType below preserves this information.
if (rep != FunctionType::Representation::Thin) {
constantInfo.LoweredType =
adjustFunctionType(constantInfo.LoweredType, rep);
constantInfo.LoweredInterfaceType =
adjustFunctionType(constantInfo.LoweredInterfaceType, rep);
}
// The expected result of witness_method is a partial application
// of the archetype method to the expected archetype.
CanAnyFunctionType partialSubstFormalType =
cast<FunctionType>(
cast<PolymorphicFunctionType>(OrigFormalOldType)
->substGenericArgs(SGM.SwiftModule, archetype)
->getCanonicalType());
// If the requirement is generic, sever its connection to the substituted
// outer parameter list.
if (auto polyMethod = dyn_cast<PolymorphicFunctionType>(
partialSubstFormalType.getResult())) {
auto origParams = &polyMethod->getGenericParams();
auto emptyOuterParams = GenericParamList::getEmpty(C);
auto params = origParams->cloneWithOuterParameters(C, emptyOuterParams);
polyMethod = CanPolymorphicFunctionType::get(polyMethod.getInput(),
polyMethod.getResult(),
params,
polyMethod->getExtInfo());
partialSubstFormalType
= CanFunctionType::get(partialSubstFormalType.getInput(), polyMethod);
}
// Same thing for the interface type.
auto partialSubstInterfaceType =
cast<AnyFunctionType>(
cast<GenericFunctionType>(OrigFormalInterfaceType)
->partialSubstGenericArgs(SGM.SwiftModule, archetype)
->getCanonicalType());
auto partialSubstUncurriedType =
SGM.Types.getConstantFunctionType(constant, partialSubstFormalType,
partialSubstInterfaceType,
rep);
return SILType::getPrimitiveObjectType(partialSubstUncurriedType);
}
/// Add the 'self' type to the substituted function type of this
/// dynamic callee.
void addDynamicCalleeSelfToFormalType(SILGenModule &SGM) {
assert(kind == Kind::DynamicMethod);
// Drop the original self clause.
CanType methodType = OrigFormalOldType;
methodType = cast<AnyFunctionType>(methodType).getResult();
// Replace it with the dynamic self type.
OrigFormalOldType = OrigFormalInterfaceType
= getDynamicMethodFormalType(SGM, method.selfValue,
method.methodName.getDecl(),
method.methodName, methodType);
// Add a self clause to the substituted type.
auto origFormalType = cast<AnyFunctionType>(OrigFormalOldType);
auto selfType = origFormalType.getInput();
SubstFormalType
= CanFunctionType::get(selfType, SubstFormalType,
origFormalType->getExtInfo());
}
public:
static Callee forIndirect(ManagedValue indirectValue,
CanType origFormalType,
CanAnyFunctionType substFormalType,
bool isTransparent,
SILLocation l) {
return Callee(indirectValue,
origFormalType,
substFormalType,
isTransparent, l);
}
static Callee forDirect(SILGenFunction &gen, SILDeclRef c,
CanAnyFunctionType substFormalType,
SILLocation l) {
return Callee(gen, c, substFormalType, l);
}
static Callee forClassMethod(SILGenFunction &gen, SILValue selfValue,
SILDeclRef name,
CanAnyFunctionType substFormalType,
SILLocation l) {
return Callee(Kind::ClassMethod, gen, selfValue, name,
substFormalType, l);
}
static Callee forSuperMethod(SILGenFunction &gen, SILValue selfValue,
SILDeclRef name,
CanAnyFunctionType substFormalType,
SILLocation l) {
return Callee(Kind::SuperMethod, gen, selfValue, name,
substFormalType, l);
}
static Callee forArchetype(SILGenFunction &gen, SILValue value,
SILDeclRef name,
CanAnyFunctionType substFormalType,
SILLocation l) {
Callee callee(Kind::WitnessMethod, gen, value, name,
substFormalType, l);
callee.addProtocolSelfToFormalType(gen.SGM, name);
return callee;
}
static Callee forProtocol(SILGenFunction &gen, SILValue proto,
SILDeclRef name, CanAnyFunctionType substFormalType,
SILLocation l) {
Callee callee(Kind::ProtocolMethod, gen, proto, name,
substFormalType, l);
callee.addProtocolSelfToFormalType(gen.SGM, name);
return callee;
}
static Callee forDynamic(SILGenFunction &gen, SILValue proto,
SILDeclRef name, CanAnyFunctionType substFormalType,
SILLocation l) {
Callee callee(Kind::DynamicMethod, gen, proto, name,
substFormalType, l);
callee.addDynamicCalleeSelfToFormalType(gen.SGM);
return callee;
}
Callee(Callee &&) = default;
Callee &operator=(Callee &&) = default;
void setSubstitutions(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> newSubs,
unsigned callDepth) {
// Currently generic methods of generic types are the deepest we should
// be able to stack specializations.
// FIXME: Generic local functions can add type parameters to arbitrary
// depth.
assert(callDepth < 2 && "specialization below 'self' or argument depth?!");
assert(substitutions.empty() && "Already have substitutions?");
substitutions = newSubs;
assert(getNaturalUncurryLevel() >= callDepth
&& "specializations below uncurry level?!");
specializeLoc = loc;
HasSubstitutions = true;
}
CanType getOrigFormalType() const {
return OrigFormalOldType;
}
CanAnyFunctionType getSubstFormalType() const {
return SubstFormalType;
}
unsigned getNaturalUncurryLevel() const {
switch (kind) {
case Kind::IndirectValue:
return 0;
case Kind::StandaloneFunction:
return standaloneFunction.uncurryLevel;
case Kind::ClassMethod:
case Kind::SuperMethod:
case Kind::WitnessMethod:
case Kind::ProtocolMethod:
case Kind::DynamicMethod:
return method.methodName.uncurryLevel;
}
}
std::tuple<ManagedValue, CanSILFunctionType, bool>
getAtUncurryLevel(SILGenFunction &gen, unsigned level) const {
ManagedValue mv;
bool transparent = isTransparent;
SILConstantInfo constantInfo = {};
switch (kind) {
case Kind::IndirectValue:
assert(level == 0 && "can't curry indirect function");
mv = indirectValue;
assert(!HasSubstitutions);
break;
case Kind::StandaloneFunction: {
assert(level <= standaloneFunction.uncurryLevel
&& "uncurrying past natural uncurry level of standalone function");
if (level < standaloneFunction.uncurryLevel)
transparent = false;
auto constant = standaloneFunction.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
SILValue ref = gen.emitGlobalFunctionRef(Loc, constant, constantInfo);
mv = ManagedValue::forUnmanaged(ref);
break;
}
case Kind::ClassMethod: {
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
auto constant = method.methodName.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
// If the call is curried, emit a direct call to the curry thunk.
if (level < method.methodName.uncurryLevel) {
SILValue ref = gen.emitGlobalFunctionRef(Loc, constant, constantInfo);
mv = ManagedValue::forUnmanaged(ref);
transparent = false;
break;
}
// Otherwise, do the dynamic dispatch inline.
SILValue methodVal = gen.B.createClassMethod(Loc,
method.selfValue,
constant,
constantInfo.getSILType(),
/*volatile*/
constant.isForeign);
mv = ManagedValue::forUnmanaged(methodVal);
break;
}
case Kind::SuperMethod: {
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
assert(level >= 1
&& "currying 'self' of super method dispatch not yet supported");
auto constant = method.methodName.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
SILValue methodVal = gen.B.createSuperMethod(Loc,
method.selfValue,
constant,
constantInfo.getSILType(),
/*volatile*/
constant.isForeign);
mv = ManagedValue::forUnmanaged(methodVal);
break;
}
case Kind::WitnessMethod: {
assert(level >= 1
&& "currying 'self' of generic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
auto constant = method.methodName.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
// Look up the witness for the archetype.
auto selfType = getProtocolSelfType(gen.SGM);
auto archetype = getArchetypeForSelf(selfType);
SILValue fn = gen.B.createWitnessMethod(Loc,
SILType::getPrimitiveObjectType(archetype),
/*conformance*/ nullptr,
constant,
constantInfo.getSILType(),
constant.isForeign);
mv = ManagedValue::forUnmanaged(fn);
break;
}
case Kind::ProtocolMethod: {
assert(level >= 1
&& "currying 'self' of generic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
auto constant = method.methodName.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
CanArchetypeType archetype; // not used
SILType closureType =
getProtocolClosureType(gen.SGM, constant, constantInfo, archetype);
SILValue fn = gen.B.createProtocolMethod(Loc,
method.selfValue,
constant,
closureType,
/*volatile*/ constant.isForeign);
mv = ManagedValue::forUnmanaged(fn);
break;
}
case Kind::DynamicMethod: {
assert(level >= 1
&& "currying 'self' of dynamic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
auto constant = method.methodName.atUncurryLevel(level);
constantInfo = gen.getConstantInfo(constant);
auto closureType =
replaceSelfTypeForDynamicLookup(gen.getASTContext(),
constantInfo.SILFnType,
method.selfValue.getType().getSwiftRValueType(),
method.methodName);
SILValue fn = gen.B.createDynamicMethod(Loc,
method.selfValue,
constant,
SILType::getPrimitiveObjectType(closureType),
/*volatile*/ constant.isForeign);
mv = ManagedValue::forUnmanaged(fn);
break;
}
}
CanSILFunctionType substFnType =
getSubstFunctionType(gen.SGM, mv.getType().castTo<SILFunctionType>(),
constantInfo.LoweredType, level);
return std::make_tuple(mv, substFnType, transparent);
}
ArrayRef<Substitution> getSubstitutions() const {
return substitutions;
}
/// Return a specialized emission function if this is a function with a known
/// lowering, such as a builtin, or return null if there is no specialized
/// emitter.
Optional<SpecializedEmitter>
getSpecializedEmitter(SILGenModule &SGM, unsigned uncurryLevel) const {
// Currently we have no curried known functions.
if (uncurryLevel != 0)
return Nothing;
switch (kind) {
case Kind::StandaloneFunction: {
if (SpecializedEmitter e
= getSpecializedEmitterForSILBuiltin(standaloneFunction, SGM.M)) {
return e;
}
SWIFT_FALLTHROUGH;
}
case Kind::IndirectValue:
case Kind::ClassMethod:
case Kind::SuperMethod:
case Kind::WitnessMethod:
case Kind::ProtocolMethod:
case Kind::DynamicMethod:
return Nothing;
}
llvm_unreachable("bad callee kind");
}
};
/// Get the 'Self' type of a AnyObject operand to use as the result type of
/// projecting the object instance handle.
SILType getSelfTypeForDynamicLookup(SILGenFunction &gen,
SILValue existential) {
CanType ty = existential.getType().getSwiftRValueType();
ProtocolDecl *proto = cast<ProtocolType>(ty)->getDecl();
// AnyObject is a class protocol so its projection should be loadable.
return gen.getLoweredLoadableType(proto->getSelf()->getArchetype());
}
/// An ASTVisitor for building SIL function calls.
/// Nested ApplyExprs applied to an underlying curried function or method
/// reference are flattened into a single SIL apply to the most uncurried entry
/// point fitting the call site, avoiding pointless intermediate closure
/// construction.
class SILGenApply : public Lowering::ExprVisitor<SILGenApply>
{
public:
SILGenFunction &gen;
Optional<Callee> callee;
RValue selfParam;
Expr *SelfApplyExpr = nullptr;
std::vector<ApplyExpr*> callSites;
Expr *sideEffect = nullptr;
unsigned callDepth = 0;
SILGenApply(SILGenFunction &gen)
: gen(gen)
{}
void setCallee(Callee &&c) {
assert((selfParam ? callDepth == 1 : callDepth == 0)
&& "setting callee at non-zero call depth?!");
assert(!callee && "already set callee!");
callee.emplace(std::move(c));
}
void setSideEffect(Expr *sideEffectExpr) {
assert(!sideEffect && "already set side effect!");
sideEffect = sideEffectExpr;
}
void setSelfParam(RValue &&theSelfParam, Expr *theSelfApplyExpr) {
assert(!selfParam && "already set this!");
selfParam = std::move(theSelfParam);
SelfApplyExpr = theSelfApplyExpr;
++callDepth;
}
void decompose(Expr *e) {
visit(e);
}
/// Get the type of the function for substitution purposes.
///
/// \param otherCtorRefUsesAllocating If true, the OtherConstructorDeclRef
/// refers to the initializing
CanFunctionType getSubstFnType(bool otherCtorRefUsesAllocating = false) {
// TODO: optimize this if there are no specializes in play
auto getSiteType = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) {
if (otherCtorRefUsesAllocating) {
// We have a reference to an initializing constructor, but we will
// actually be using the allocating constructor. Update the type
// appropriately.
// FIXME: Re-derive the type from the declaration + substitutions?
auto ctorRef = cast<OtherConstructorDeclRefExpr>(
site->getFn()->getSemanticsProvidingExpr());
auto fnType = ctorRef->getType()->castTo<FunctionType>();
auto selfTy = MetatypeType::get(
fnType->getInput()->getInOutObjectType());
return CanFunctionType::get(selfTy->getCanonicalType(),
fnType->getResult()->getCanonicalType(),
fnType->getExtInfo());
}
return cast<FunctionType>(site->getFn()->getType()->getCanonicalType());
};
CanFunctionType fnType;
auto addSite = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) {
auto siteType = getSiteType(site, otherCtorRefUsesAllocating);
// If this is the first call site, use its formal type directly.
if (!fnType) {
fnType = siteType;
return;
}
fnType = CanFunctionType::get(siteType.getInput(), fnType,
siteType->getExtInfo());
};
for (auto callSite : callSites) {
addSite(callSite, false);
}
if (auto selfApply = dyn_cast_or_null<ApplyExpr>(SelfApplyExpr)) {
addSite(selfApply, otherCtorRefUsesAllocating);
}
assert(fnType && "found no call sites?");
return fnType;
}
/// Fall back to an unknown, indirect callee.
void visitExpr(Expr *e) {
// This marks all calls to auto closure typed variables as transparent.
// As of writing, local variable auto closures are currently allowed by
// the parser, but the plan is that they will be disallowed, so this will
// actually only apply to auto closure parameters, which is what we want
auto *t = e->getType()->castTo<AnyFunctionType>();
bool isTransparent = t->getExtInfo().isAutoClosure();
ManagedValue fn = gen.emitRValueAsSingleValue(e);
auto origType = cast<AnyFunctionType>(e->getType()->getCanonicalType());
setCallee(Callee::forIndirect(fn, origType, getSubstFnType(), isTransparent,
e));
}
void visitLoadExpr(LoadExpr *e) {
bool isTransparent = false;
if (DeclRefExpr *d = dyn_cast<DeclRefExpr>(e->getSubExpr())) {
// This marks all calls to auto closure typed variables as transparent.
// As of writing, local variable auto closures are currently allowed by
// the parser, but the plan is that they will be disallowed, so this will
// actually only apply to auto closure parameters, which is what we want
Type Ty = d->getDecl()->getType()->getInOutObjectType();
// If the decl type is a function type, figure out if it is an auto
// closure.
if (auto *AnyF = Ty->getAs<AnyFunctionType>()) {
isTransparent = AnyF->getExtInfo().isAutoClosure();
}
}
// TODO: preserve the function pointer at its original abstraction level
ManagedValue fn = gen.emitRValueAsSingleValue(e);
auto origType = cast<AnyFunctionType>(e->getType()->getCanonicalType());
setCallee(Callee::forIndirect(fn, origType, getSubstFnType(),
isTransparent, e));
}
/// Add a call site to the curry.
void visitApplyExpr(ApplyExpr *e) {
if (e->isSuper()) {
applySuper(e);
} else if (applyInitDelegation(e)) {
// Already done
} else {
callSites.push_back(e);
visit(e->getFn());
}
++callDepth;
}
/// Given a metatype value for the type, allocate an Objective-C
/// object (with alloc_ref_dynamic) of that type.
///
/// \returns the self object.
ManagedValue allocateObjCObject(ManagedValue selfMeta, SILLocation loc) {
auto metaType = selfMeta.getType().castTo<AnyMetatypeType>();
CanType type = metaType.getInstanceType();
// Convert to an Objective-C metatype representation, if needed.
ManagedValue selfMetaObjC;
if (metaType->getRepresentation() == MetatypeRepresentation::ObjC) {
selfMetaObjC = selfMeta;
} else {
CanAnyMetatypeType objcMetaType;
if (isa<MetatypeType>(metaType)) {
objcMetaType = CanMetatypeType::get(type, MetatypeRepresentation::ObjC);
} else {
objcMetaType = CanExistentialMetatypeType::get(type,
MetatypeRepresentation::ObjC);
}
selfMetaObjC = ManagedValue(
gen.B.emitThickToObjCMetatype(
loc, selfMeta.getValue(),
gen.SGM.getLoweredType(objcMetaType)),
selfMeta.getCleanup());
}
// Allocate the object.
return ManagedValue(gen.B.createAllocRefDynamic(
loc,
selfMetaObjC.getValue(),
gen.SGM.getLoweredType(type),
/*objc=*/true),
selfMetaObjC.getCleanup());
}
//
// Known callees.
//
void visitDeclRefExpr(DeclRefExpr *e) {
// If we need to perform dynamic dispatch for the given function,
// emit class_method to do so.
if (auto afd = dyn_cast<AbstractFunctionDecl>(e->getDecl())) {
Optional<SILDeclRef::Kind> kind;
bool isDynamicallyDispatched = false;
bool requiresAllocRefDynamic = false;
if (auto fd = dyn_cast<FuncDecl>(afd)) {
// If this declaration is in a class but not marked @final, then it is
// always dynamically dispatched.
if ((isa<ClassDecl>(fd->getDeclContext()) || fd->isObjC()) &&
!fd->isFinal()) {
isDynamicallyDispatched = true;
kind = SILDeclRef::Kind::Func;
}
}
// Abstract constructors are dynamically dispatched when the 'self' value
// is not statically derived.
else if (auto ctor = dyn_cast<ConstructorDecl>(afd)) {
ApplyExpr *thisCallSite = callSites.back();
if (ctor->isRequired() &&
thisCallSite->getArg()->getType()->is<AnyMetatypeType>() &&
!thisCallSite->getArg()->isStaticallyDerivedMetatype()) {
isDynamicallyDispatched = true;
if (gen.SGM.requiresObjCDispatch(afd)) {
// When we're performing Objective-C dispatch, we don't have an
// allocating constructor to call. So, perform an alloc_ref_dynamic
// and pass that along to the initializer.
requiresAllocRefDynamic = true;
kind = SILDeclRef::Kind::Initializer;
} else {
kind = SILDeclRef::Kind::Allocator;
}
}
}
if (isDynamicallyDispatched) {
ApplyExpr *thisCallSite = callSites.back();
callSites.pop_back();
RValue self = gen.emitRValue(thisCallSite->getArg());
// If we require a dynamic allocation of the object here, do so now.
if (requiresAllocRefDynamic) {
SILLocation loc = thisCallSite->getArg();
auto selfValue = allocateObjCObject(
std::move(self).getAsSingleValue(gen, loc),
loc);
self = RValue(gen, loc, selfValue.getType().getSwiftRValueType(),
selfValue);
}
setSelfParam(std::move(self), thisCallSite);
SILDeclRef constant(afd, kind.getValue(),
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCDispatch(afd));
setCallee(Callee::forClassMethod(gen, selfParam.peekScalarValue(),
constant, getSubstFnType(), e));
// setSelfParam bumps the callDepth, but we aren't really past the
// 'self' call depth in this case.
--callDepth;
// If there are substitutions, add them.
if (e->getDeclRef().isSpecialized()) {
callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(),
callDepth);
}
return;
}
}
// If this is a direct reference to a vardecl, it must be a let constant
// (which doesn't need to be loaded). Just emit its value directly.
if (auto *vd = dyn_cast<VarDecl>(e->getDecl())) {
(void)vd;
assert(vd->isLet() && "Direct reference to vardecl that isn't a let?");
visitExpr(e);
return;
}
// FIXME: Store context values for local funcs in a way that we can
// apply them directly as an added "call site" here.
SILDeclRef constant(e->getDecl(),
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCDispatch(e->getDecl()));
// Obtain a reference for a local closure.
if (gen.LocalFunctions.count(constant)) {
ManagedValue localFn =
gen.emitRValueForDecl(e, e->getDeclRef(), e->getType());
auto type = cast<AnyFunctionType>(e->getType()->getCanonicalType());
setCallee(Callee::forIndirect(localFn, type, type, false, e));
// Otherwise, stash the SILDeclRef.
} else {
setCallee(Callee::forDirect(gen, constant, getSubstFnType(), e));
}
// If there are substitutions, add them.
if (e->getDeclRef().isSpecialized()) {
callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(),
callDepth);
}
}
void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) {
// FIXME: We might need to go through ObjC dispatch for references to
// constructors imported from Clang (which won't have a direct entry point)
// or to delegate to a designated initializer.
setCallee(Callee::forDirect(gen,
SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer),
getSubstFnType(), e));
// If there are substitutions, add them.
if (e->getDeclRef().isSpecialized())
callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(),
callDepth);
}
void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) {
setSideEffect(e->getLHS());
visit(e->getRHS());
}
/// Skip over all of the 'Self'-related substitutions within the given set
/// of substitutions.
ArrayRef<Substitution> getNonSelfSubstitutions(ArrayRef<Substitution> subs) {
unsigned innerIdx = 0, n = subs.size();
for (; innerIdx != n; ++innerIdx) {
auto archetype = subs[innerIdx].Archetype;
while (archetype->getParent())
archetype = archetype->getParent();
if (!archetype->getSelfProtocol()) {
break;
}
}
return subs.slice(innerIdx);
}
void visitMemberRefExpr(MemberRefExpr *e) {
auto *fd = dyn_cast<AbstractFunctionDecl>(e->getMember().getDecl());
// If the base is a non-protocol, non-archetype type, then this is a load of
// a function pointer out of a vardecl. Just emit it as an rvalue.
if (!fd)
return visitExpr(e);
// We have four cases to deal with here:
//
// 1) for a "static" / "type" method, the base is a metatype.
// 2) for a classbound protocol, the base is a class-bound protocol rvalue,
// which is loadable.
// 3) for a mutating method, the base has inout type.
// 4) for a nonmutating method, the base is a general protocol/archetype
// rvalue, which is address-only. The base is passed at +0, so it isn't
// consumed.
//
// In the last case, the AST has this call typed as being applied to an
// rvalue, but the witness is actually expecting a pointer to the +0 value
// in memory. We access this with the project_existential instruction, or
// just pass in the address since archetypes are address-only.
auto baseVal = gen.emitRValueAsSingleValue(e->getBase(),
SGFContext::AllowPlusZero);
auto *proto = cast<ProtocolDecl>(fd->getDeclContext());
auto baseTy = e->getBase()->getType()->getLValueOrInOutObjectType();
// Figure out the kind of declaration reference we're working with.
SILDeclRef::Kind kind = SILDeclRef::Kind::Func;
if (isa<ConstructorDecl>(fd)) {
if (proto->isObjC()) {
// For Objective-C initializers, we only have an initializing
// initializer. We need to allocate the object ourselves.
kind = SILDeclRef::Kind::Initializer;
baseVal = allocateObjCObject(baseVal, e->getBase());
} else {
// For non-Objective-C initializers, we have an allocating
// initializer to call.
kind = SILDeclRef::Kind::Allocator;
}
}
if (!baseTy->isExistentialType()) {
setSelfParam(RValue(gen, e->getBase(), baseVal.getType().getSwiftType(),
baseVal), e);
} else if (fd->isInstanceMember()) {
// Attach the existential cleanup to the projection so that it gets
// consumed (or not) when the call is applied to it (or isn't).
ManagedValue proj;
SILType protoSelfTy
= gen.getLoweredType(proto->getSelf()->getArchetype());
if (baseVal.getType().isClassExistentialType()) {
SILValue val = gen.B.createProjectExistentialRef(e,
baseVal.getValue(), protoSelfTy);
proj = ManagedValue(val, baseVal.getCleanup());
} else {
assert(protoSelfTy.isAddress() && "Self should be address-only");
SILValue val = gen.B.createProjectExistential(e, baseVal.getValue(),
protoSelfTy);
proj = ManagedValue::forUnmanaged(val);
}
setSelfParam(RValue(gen, e, protoSelfTy.getSwiftType(), proj), e);
} else {
assert(baseVal.getType().is<ExistentialMetatypeType>() &&
"non-existential-metatype for existential static method?!");
// FIXME: It is impossible to invoke a class method on a protocol
// directly, it must be done through an archetype.
setSelfParam(RValue(gen, e, baseVal.getType().getSwiftRValueType(),
baseVal), e);
}
// Method calls through ObjC protocols require ObjC dispatch.
bool isObjC = proto->isObjC();
ArrayRef<Substitution> subs = e->getMember().getSubstitutions();
if (!baseTy->getRValueInstanceType()->isExistentialType()) {
setCallee(Callee::forArchetype(gen, selfParam.peekScalarValue(),
SILDeclRef(fd, kind).asForeign(isObjC),
getSubstFnType(), e));
} else {
// The declaration is always specialized (due to Self); ignore the
// substitutions related to Self. Skip the substitutions involving Self.
subs = getNonSelfSubstitutions(subs);
setCallee(Callee::forProtocol(gen, baseVal.getValue(),
SILDeclRef(fd, kind).asForeign(isObjC),
getSubstFnType(), e));
}
// If there are substitutions, add them now.
if (!subs.empty()) {
callee->setSubstitutions(gen, e, subs, callDepth);
}
}
void visitFunctionConversionExpr(FunctionConversionExpr *e) {
// FIXME: Check whether this function conversion requires us to build a
// thunk.
visit(e->getSubExpr());
}
void visitCovariantFunctionConversionExpr(CovariantFunctionConversionExpr *e){
// FIXME: These expressions merely adjust the result type for DynamicSelf
// in an unchecked, ABI-compatible manner. They shouldn't prevent us form
// forming a complete call.
visitExpr(e);
}
void visitIdentityExpr(IdentityExpr *e) {
visit(e->getSubExpr());
}
void applySuper(ApplyExpr *apply) {
// Load the 'super' argument.
Expr *arg = apply->getArg();
ManagedValue super = gen.emitRValueAsSingleValue(arg);
// The callee for a super call has to be either a method or constructor.
Expr *fn = apply->getFn();
ArrayRef<Substitution> substitutions;
SILDeclRef constant;
if (auto *ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(fn)) {
constant = SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCSuperDispatch(ctorRef->getDecl()));
if (ctorRef->getDeclRef().isSpecialized())
substitutions = ctorRef->getDeclRef().getSubstitutions();
} else if (auto *declRef = dyn_cast<DeclRefExpr>(fn)) {
assert(isa<FuncDecl>(declRef->getDecl()) && "non-function super call?!");
constant = SILDeclRef(declRef->getDecl(),
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCSuperDispatch(declRef->getDecl()));
if (declRef->getDeclRef().isSpecialized())
substitutions = declRef->getDeclRef().getSubstitutions();
} else
llvm_unreachable("invalid super callee");
CanType superFormalType = arg->getType()->getCanonicalType();
setSelfParam(RValue(gen, apply, superFormalType, super), apply);
SILValue superMethod;
if (constant.isForeign) {
SILValue Input = super.getValue();
while (auto *UI = dyn_cast<UpcastInst>(Input))
Input = UI->getOperand();
// ObjC super calls require dynamic dispatch.
setCallee(Callee::forSuperMethod(gen, Input, constant,
getSubstFnType(), fn));
} else {
// Native Swift super calls are direct.
setCallee(Callee::forDirect(gen, constant, getSubstFnType(), fn));
}
// If there are any substitutions for the callee, apply them now.
if (!substitutions.empty())
callee->setSubstitutions(gen, fn, substitutions, callDepth-1);
}
/// Try to emit the given application as initializer delegation.
bool applyInitDelegation(ApplyExpr *expr) {
// Dig out the constructor we're delegating to.
Expr *fn = expr->getFn();
auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(
fn->getSemanticsProvidingExpr());
if (!ctorRef)
return false;
// Determine whether we'll need to use an allocating constructor (vs. the
// initializing constructor).
auto nominal = ctorRef->getDecl()->getDeclContext()
->getDeclaredTypeOfContext()->getAnyNominal();
bool useAllocatingCtor = isa<StructDecl>(nominal) || isa<EnumDecl>(nominal);
// Load the 'self' argument.
Expr *arg = expr->getArg();
ManagedValue self = gen.emitRValueAsSingleValue(arg);
// If we're using the allocating constructor, we need to pass along the
// metatype.
if (useAllocatingCtor) {
auto cleanup = self.getCleanup();
SILValue selfMeta = gen.emitMetatypeOfValue(expr, self.forward(gen));
self = ManagedValue(selfMeta, cleanup);
}
CanType selfFormalType = arg->getType()->getCanonicalType();
setSelfParam(RValue(gen, expr, selfFormalType, self), expr);
// Determine the callee. For structs and enums, this is the allocating
// constructor (because there is no initializing constructor). For classes,
// this is the initializing constructor, to which we will dynamically
// dispatch.
if (isa<ClassDecl>(nominal)) {
// If the constructor is a convenience initializer, use
// dynamic dispatch to the initializing constructor.
setCallee(Callee::forClassMethod(
gen,
self.getValue(),
SILDeclRef(ctorRef->getDecl(),
SILDeclRef::Kind::Initializer,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCDispatch(ctorRef->getDecl())),
getSubstFnType(), fn));
} else {
// Directly call the peer constructor.
setCallee(Callee::forDirect(gen,
SILDeclRef(ctorRef->getDecl(),
useAllocatingCtor
? SILDeclRef::Kind::Allocator
: SILDeclRef::Kind::Initializer,
SILDeclRef::ConstructAtBestResilienceExpansion),
getSubstFnType(useAllocatingCtor), fn));
}
// Set up the substitutions, if we have any.
if (ctorRef->getDeclRef().isSpecialized())
callee->setSubstitutions(gen, fn,
ctorRef->getDeclRef().getSubstitutions(),
callDepth-1);
return true;
}
Callee getCallee() {
assert(callee && "did not find callee?!");
return *std::move(callee);
}
/// Ignore parentheses and implicit conversions.
static Expr *ignoreParensAndImpConversions(Expr *expr) {
while (true) {
if (auto ice = dyn_cast<ImplicitConversionExpr>(expr)) {
expr = ice->getSubExpr();
continue;
}
// Simple optional-to-optional conversions. This doesn't work
// for the full generality of OptionalEvaluationExpr, but it
// works given that we check the result for certain forms.
if (auto eval = dyn_cast<OptionalEvaluationExpr>(expr)) {
if (auto inject = dyn_cast<InjectIntoOptionalExpr>(eval->getSubExpr())) {
if (auto bind = dyn_cast<BindOptionalExpr>(inject->getSubExpr())) {
if (bind->getDepth() == 0)
return bind->getSubExpr();
}
}
}
auto valueProviding = expr->getValueProvidingExpr();
if (valueProviding != expr) {
expr = valueProviding;
continue;
}
return expr;
}
}
void visitForceValueExpr(ForceValueExpr *e) {
// If this application is a dynamic member reference that is forced to
// succeed with the '!' operator, emit it as a direct invocation of the
// method we found.
if (emitForcedDynamicMemberRef(e))
return;
visitExpr(e);
}
/// If this application forces a dynamic member reference with !, emit
/// a direct reference to the member.
bool emitForcedDynamicMemberRef(ForceValueExpr *e) {
// Check whether the argument is a dynamic member reference.
auto arg = ignoreParensAndImpConversions(e->getSubExpr());
auto dynamicMemberRef = dyn_cast<DynamicMemberRefExpr>(arg);
if (!dynamicMemberRef)
return false;
// objc_msgSend() already contains the dynamic method lookup check, which
// allows us to avoid emitting a specific test for the dynamic method.
// Bail out early if we aren't using Objective-C dispatch.
if (!gen.SGM.requiresObjCDispatch(dynamicMemberRef->getMember().getDecl()))
return false;
// Since we'll be collapsing this call site, make sure there's another
// call site that will actually perform the invocation.
if (callSites.empty())
return false;
// Only methods can be forced.
auto *fd = dyn_cast<FuncDecl>(dynamicMemberRef->getMember().getDecl());
if (!fd)
return false;
// We found it. Emit the base.
ManagedValue existential =
gen.emitRValueAsSingleValue(dynamicMemberRef->getBase());
assert(fd->isObjC() && "Dynamic member references require @objc");
SILValue val;
if (fd->isInstanceMember()) {
assert(fd->isInstanceMember() && "Non-instance dynamic member reference");
// Attach the existential cleanup to the projection so that it gets
// consumed (or not) when the call is applied to it (or isn't).
val = gen.B.createProjectExistentialRef(dynamicMemberRef,
existential.getValue(),
getSelfTypeForDynamicLookup(gen, existential.getValue()));
val = gen.B.createUncheckedRefCast(dynamicMemberRef, val,
SILType::getUnknownObjectType(gen.getASTContext()));
ManagedValue proj(val, existential.getCleanup());
setSelfParam(RValue(gen, dynamicMemberRef,
proj.getType().getSwiftRValueType(), proj),
dynamicMemberRef);
} else {
assert(existential.getType().is<ExistentialMetatypeType>() &&
"non-dynamic-lookup-metatype for static method?!");
val = existential.getValue();
ManagedValue proj(val, existential.getCleanup());
setSelfParam(RValue(gen, dynamicMemberRef,
existential.getType().getSwiftRValueType(),
existential),
dynamicMemberRef);
}
// Determine the type of the method we referenced, by replacing the
// class type of the 'Self' parameter with Builtin.UnknownObject.
SILDeclRef member(fd, SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
/*isObjC=*/true);
setCallee(Callee::forDynamic(gen, val, member, getSubstFnType(), e));
return true;
}
};
} // end anonymous namespace
#ifndef NDEBUG
static bool areOnlyAbstractionDifferent(CanType type1, CanType type2) {
assert(type1->isLegalSILType());
assert(type2->isLegalSILType());
// Exact equality is fine.
if (type1 == type2) return true;
// Either both types should be tuples or neither should be.
if (auto tuple1 = dyn_cast<TupleType>(type1)) {
auto tuple2 = dyn_cast<TupleType>(type2);
if (!tuple2) return false;
if (tuple1->getNumElements() != tuple2->getNumElements()) return false;
for (auto i : indices(tuple2->getElementTypes()))
if (!areOnlyAbstractionDifferent(tuple1.getElementType(i),
tuple2.getElementType(i)))
return false;
return true;
}
if (isa<TupleType>(type2)) return false;
// Either both types should be metatypes or neither should be.
if (auto meta1 = dyn_cast<AnyMetatypeType>(type1)) {
auto meta2 = dyn_cast<AnyMetatypeType>(type2);
if (!meta2) return false;
if (meta1.getInstanceType() != meta2.getInstanceType()) return false;
return true;
}
// Either both types should be functions or neither should be.
if (auto fn1 = dyn_cast<SILFunctionType>(type1)) {
auto fn2 = dyn_cast<SILFunctionType>(type2);
if (!fn2) return false;
// TODO: maybe there are checks we can do here?
(void) fn1; (void) fn2;
return true;
}
if (isa<SILFunctionType>(type2)) return false;
llvm_unreachable("no other types should differ by abstraction");
}
#endif
static bool isNative(AbstractCC cc) {
switch (cc) {
case AbstractCC::C:
case AbstractCC::ObjCMethod:
return false;
case AbstractCC::Freestanding:
case AbstractCC::Method:
case AbstractCC::WitnessMethod:
return true;
}
llvm_unreachable("bad CC");
}
/// Given two SIL types which are representations of the same type,
/// check whether they have an abstraction difference.
static bool hasAbstractionDifference(AbstractCC cc,
CanType type1, CanType type2) {
assert(!isNative(cc) || areOnlyAbstractionDifferent(type1, type2));
// Assuming that we've applied the same substitutions to both types,
// abstraction equality should equal type equality.
return (type1 != type2);
}
/// Emit a raw apply operation, performing no additional lowering of
/// either the arguments or the result.
static SILValue emitRawApply(SILGenFunction &gen,
SILLocation loc,
ManagedValue fn,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
bool transparent,
SILValue resultAddr) {
// Get the callee value.
SILValue fnValue = substFnType->isCalleeConsumed()
? fn.forward(gen)
: fn.getValue();
SmallVector<SILValue, 4> argValues;
// Add the buffer for the indirect return if needed.
assert(bool(resultAddr) == substFnType->hasIndirectResult());
if (substFnType->hasIndirectResult()) {
assert(resultAddr.getType() ==
substFnType->getIndirectInterfaceResult().getSILType().getAddressType());
argValues.push_back(resultAddr);
}
auto inputTypes = substFnType->getInterfaceParametersWithoutIndirectResult();
assert(inputTypes.size() == args.size());
// Gather the arguments.
for (auto i : indices(args)) {
auto argValue = (inputTypes[i].isConsumed() ? args[i].forward(gen)
: args[i].getValue());
#ifndef NDEBUG
if (argValue.getType() != inputTypes[i].getSILType()) {
auto &out = llvm::errs();
out << "TYPE MISMATCH IN ARGUMENT " << i << " OF APPLY AT ";
printSILLocationDescription(out, loc, gen.getASTContext());
out << " argument value: ";
argValue.print(out);
out << " parameter type: ";
inputTypes[i].print(out);
out << "\n";
abort();
}
#endif
argValues.push_back(argValue);
}
auto resultType = substFnType->getInterfaceResult().getSILType();
auto calleeType = SILType::getPrimitiveObjectType(substFnType);
SILValue result = gen.B.createApply(loc, fnValue, calleeType,
resultType, subs, argValues,
transparent);
return result;
}
/// Emit a function application, assuming that the arguments have been
/// lowered appropriately for the abstraction level but that the
/// result does need to be turned back into something matching a
/// formal type.
static ManagedValue emitApply(SILGenFunction &gen,
SILLocation loc,
ManagedValue fn,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
AbstractionPattern origResultType,
CanType substResultType,
bool transparent,
Optional<AbstractCC> overrideCC,
SGFContext evalContext) {
auto &formalResultTL = gen.getTypeLowering(substResultType);
auto loweredFormalResultType = formalResultTL.getLoweredType();
AbstractCC cc = overrideCC ? *overrideCC : substFnType->getAbstractCC();
SILType actualResultType = substFnType->getSemanticInterfaceResultSILType();
// Check whether there are abstraction differences (beyond just
// direct vs. indirect) between the lowered formal result type and
// the actual result type we got back. Note that this will also
// include bridging differences.
bool hasAbsDiffs =
hasAbstractionDifference(cc,
loweredFormalResultType.getSwiftRValueType(),
actualResultType.getSwiftRValueType());
// Prepare a result address if necessary.
SILValue resultAddr;
bool emittedIntoContext = false;
if (substFnType->hasIndirectResult()) {
// Get the result type with the abstraction prescribed by the
// function we're calling.
assert(actualResultType.isAddress());
// The context will expect the natural representation of the
// result type. If there's no abstraction difference between that
// and the actual form of the result, then we can emit directly
// into the context.
emittedIntoContext = !hasAbsDiffs;
if (emittedIntoContext) {
resultAddr = gen.getBufferForExprResult(loc, actualResultType,
evalContext);
// Otherwise, we need a temporary of the right abstraction.
} else {
resultAddr =
gen.emitTemporaryAllocation(loc, actualResultType.getObjectType());
}
}
// If the function returns an inner pointer, we'll need to lifetime-extend
// the 'self' parameter.
SILValue lifetimeExtendedSelf;
if (substFnType->getInterfaceResult().getConvention()
== ResultConvention::UnownedInnerPointer) {
lifetimeExtendedSelf = args.back().getValue();
switch (substFnType->getInterfaceParameters().back().getConvention()) {
case swift::ParameterConvention::Direct_Owned:
// If the callee will consume the 'self' parameter, let's retain it so we
// can keep it alive.
gen.B.emitRetainValueOperation(loc, lifetimeExtendedSelf);
break;
case swift::ParameterConvention::Direct_Guaranteed:
case swift::ParameterConvention::Direct_Unowned:
// We'll manually manage the argument's lifetime after the call. Disable
// its cleanup.
args.back().forwardCleanup(gen);
break;
case swift::ParameterConvention::Indirect_In:
case swift::ParameterConvention::Indirect_Inout:
case swift::ParameterConvention::Indirect_Out:
// We may need to support this at some point, but currently only imported
// objc methods are returns_inner_pointer.
llvm_unreachable("indirect self argument to method that returns_inner_pointer?!");
}
}
// Emit the raw application.
SILValue scalarResult = emitRawApply(gen, loc, fn, subs, args,
substFnType, transparent, resultAddr);
// If we emitted into the eval context, then it's because there was
// no abstraction difference *or* bridging to do. But our caller
// might not expect to get a result indirectly.
if (emittedIntoContext) {
assert(substFnType->hasIndirectResult());
assert(!hasAbsDiffs);
auto managedBuffer =
gen.manageBufferForExprResult(resultAddr, formalResultTL, evalContext);
// managedBuffer will be null here to indicate that we satisfied
// the evalContext. If so, we're done.
// We are also done if the expected type is address-only.
if (managedBuffer.isInContext() || formalResultTL.isAddressOnly())
return managedBuffer;
// Otherwise, deactivate the cleanup we just entered; we're about
// to take from the address.
resultAddr = managedBuffer.forward(gen);
}
// Get the type lowering for the actual result representation.
// This is very likely to be the same as that for the formal result.
auto &actualResultTL
= (actualResultType == loweredFormalResultType
? formalResultTL : gen.getTypeLowering(actualResultType));
// If the expected result is an address, manage the result address.
if (formalResultTL.isAddressOnly()) {
assert(resultAddr);
auto managedActualResult =
gen.emitManagedBufferWithCleanup(resultAddr, actualResultTL);
if (!hasAbsDiffs) return managedActualResult;
return gen.emitOrigToSubstValue(loc, managedActualResult,
origResultType, substResultType,
evalContext);
}
// Okay, we want a scalar result.
assert(!actualResultTL.isAddressOnly() &&
"actual result is address-only when formal result is not?");
ManagedValue managedScalar;
// If we got an indirect result, emit a take out of the result address.
if (substFnType->hasIndirectResult()) {
managedScalar = gen.emitLoad(loc, resultAddr, actualResultTL,
SGFContext(), IsTake);
// Otherwise, manage the direct result.
} else {
switch (substFnType->getInterfaceResult().getConvention()) {
case ResultConvention::Owned:
// Already retained.
break;
case ResultConvention::Autoreleased:
// Autoreleased. Retain using retain_autoreleased.
gen.B.createStrongRetainAutoreleased(loc, scalarResult);
break;
case ResultConvention::UnownedInnerPointer:
// Autorelease the 'self' value to lifetime-extend it.
assert(lifetimeExtendedSelf.isValid()
&& "did not save lifetime-extended self param");
gen.B.createAutoreleaseValue(loc, lifetimeExtendedSelf);
SWIFT_FALLTHROUGH;
case ResultConvention::Unowned:
// Unretained. Retain the value.
actualResultTL.emitRetainValue(gen.B, loc, scalarResult);
break;
}
managedScalar = gen.emitManagedRValueWithCleanup(scalarResult,
actualResultTL);
}
// Fast path: no abstraction differences or bridging.
if (!hasAbsDiffs) return managedScalar;
// Remove abstraction differences.
if (origResultType.getAsType() != substResultType) {
managedScalar = gen.emitOrigToSubstValue(loc, managedScalar,
origResultType,
substResultType,
SGFContext());
}
// Convert the result to a native value.
return gen.emitBridgedToNativeValue(loc, managedScalar, cc,
substResultType);
}
ManagedValue SILGenFunction::emitMonomorphicApply(SILLocation loc,
ManagedValue fn,
ArrayRef<ManagedValue> args,
CanType resultType,
bool transparent,
Optional<AbstractCC> overrideCC) {
auto fnType = fn.getType().castTo<SILFunctionType>();
assert(!fnType->isPolymorphic());
return emitApply(*this, loc, fn, {}, args, fnType,
AbstractionPattern(resultType), resultType,
transparent, overrideCC, SGFContext());
}
/// Count the number of SILParameterInfos that are needed in order to
/// pass the given argument. This wouldn't be necessary if we uncurried
/// left-to-right.
static unsigned getFlattenedValueCount(AbstractionPattern origType,
CanType substType) {
if (auto origTuple = dyn_cast<TupleType>(origType.getAsType())) {
auto substTuple = cast<TupleType>(substType);
unsigned count = 0;
assert(origTuple->getNumElements() == substTuple->getNumElements());
for (auto i : indices(origTuple.getElementTypes())) {
count += getFlattenedValueCount(origType.getTupleElementType(i),
substTuple.getElementType(i));
}
return count;
}
// Most general form of an unmaterializable type.
if (auto substTuple = dyn_cast<TupleType>(substType)) {
assert(origType.isOpaque());
if (!substTuple->isMaterializable()) {
unsigned count = 0;
for (auto substElt : substTuple.getElementTypes()) {
count += getFlattenedValueCount(origType, substElt);
}
return count;
}
}
return 1;
}
static AbstractionPattern claimNextParamClause(AbstractionPattern &type) {
auto result = type.getFunctionInputType();
type = type.getFunctionResultType();
return result;
}
static CanType claimNextParamClause(CanAnyFunctionType &type) {
auto result = type.getInput();
type = dyn_cast<AnyFunctionType>(type.getResult());
return result;
}
namespace {
class ArgEmitter {
SILGenFunction &SGF;
AbstractCC CC;
ArrayRef<SILParameterInfo> ParamInfos;
SmallVectorImpl<ManagedValue> &Args;
public:
ArgEmitter(SILGenFunction &SGF, AbstractCC cc,
ArrayRef<SILParameterInfo> paramInfos,
SmallVectorImpl<ManagedValue> &args)
: SGF(SGF), CC(cc), ParamInfos(paramInfos), Args(args) {}
void emit(RValueSource &&arg, AbstractionPattern origParamType) {
// If it was a tuple in the original type, the parameters will
// have been exploded.
if (isa<TupleType>(origParamType.getAsType())) {
emitExpanded(std::move(arg), origParamType);
return;
}
auto substArgType = arg.getSubstType();
// Otherwise, if the substituted type is a tuple, then we should
// emit the tuple in its most general form, because there's a
// substitution of an opaque archetype to a tuple or function
// type in play. The most general convention is generally to
// pass the entire tuple indirectly, but if it's not
// materializable, the convention is actually to break it up
// into materializable chunks. See the comment in SILType.cpp.
if (isUnmaterializableTupleType(substArgType)) {
assert(origParamType.isOpaque());
emitExpanded(std::move(arg), origParamType);
return;
}
// Okay, everything else will be passed as a single value, one
// way or another.
// The substituted parameter type. Might be different from the
// substituted argument type by abstraction and/or bridging.
auto param = claimNextParameter();
auto loweredSubstArgType =
SGF.getLoweredType(substArgType).getSwiftRValueType();
// If the caller takes the argument indirectly, the argument has an
// inout type.
if (param.isIndirectInOut()) {
assert(isa<InOutType>(substArgType));
emitInOut(std::move(arg), loweredSubstArgType, param.getType(),
origParamType, substArgType);
return;
}
// If the original type is passed indirectly, copy to memory if
// it's not already there. (Note that this potentially includes
// conventions which pass indirectly without transferring
// ownership, like Itanium C++.)
if (param.isIndirect()) {
assert(!param.isIndirectResult());
auto value = std::move(arg).materialize(SGF, origParamType,
param.getSILType());
Args.push_back(value);
return;
}
// Okay, if the original parameter is passed directly, then we
// just need to handle abstraction differences and bridging.
emitDirect(std::move(arg), origParamType, param);
}
private:
SILParameterInfo claimNextParameter() {
assert(!ParamInfos.empty());
auto param = ParamInfos.front();
ParamInfos = ParamInfos.slice(1);
return param;
}
bool isUnmaterializableTupleType(CanType type) {
if (auto tuple = dyn_cast<TupleType>(type))
if (!tuple->isMaterializable())
return true;
return false;
}
/// Emit an argument as an expanded tuple.
void emitExpanded(RValueSource &&arg, AbstractionPattern origParamType) {
CanTupleType substArgType = cast<TupleType>(arg.getSubstType());
// The original type isn't necessarily a tuple.
assert(origParamType.matchesTuple(substArgType));
// If we're working with an r-value, just expand it out and emit
// all the elements individually.
if (arg.isRValue()) {
auto loc = arg.getKnownRValueLocation();
SmallVector<RValue, 4> elts;
std::move(arg).asKnownRValue().extractElements(elts);
for (auto i : indices(substArgType.getElementTypes())) {
emit({ loc, std::move(elts[i]) },
origParamType.getTupleElementType(i));
}
return;
}
// Otherwise, we're working with an expression.
Expr *e = std::move(arg).asKnownExpr();
e = e->getSemanticsProvidingExpr();
// If the source expression is a tuple literal, we can break it
// up directly.
if (auto tuple = dyn_cast<TupleExpr>(e)) {
for (auto i : indices(tuple->getElements())) {
emit(tuple->getElements()[i],
origParamType.getTupleElementType(i));
}
return;
}
// TODO: tuple shuffles, etc.
// Fall back to the r-value case.
emitExpanded({ e, SGF.emitRValue(e) }, origParamType);
}
void emitInOut(RValueSource &&arg,
CanType loweredSubstArgType, CanType loweredSubstParamType,
AbstractionPattern origType, CanType substType) {
if (arg.isRValue()) {
emitInOut(arg.getKnownRValueLocation(), std::move(arg).asKnownRValue(),
loweredSubstArgType, loweredSubstParamType,
origType, substType);
} else {
Expr *e = std::move(arg).asKnownExpr();
emitInOut(e, SGF.emitRValue(e),
loweredSubstArgType, loweredSubstParamType,
origType, substType);
}
}
void emitInOut(SILLocation loc, RValue &&rvalue,
CanType loweredSubstArgType, CanType loweredSubstParamType,
AbstractionPattern origType, CanType substType) {
if (hasAbstractionDifference(CC, loweredSubstParamType,
loweredSubstArgType)) {
// This could actually just be type-bridging. In any case,
// it can be dealt with with writeback.
llvm::errs() << "Unimplemented: abstraction difference in l-value\n";
llvm::errs() << "\n "; loweredSubstParamType.dump();
llvm::errs() << "\n "; loweredSubstArgType.dump();
abort();
}
std::move(rvalue).getAll(Args);
return;
}
void emitDirect(RValueSource &&arg, AbstractionPattern origParamType,
SILParameterInfo param) {
if (arg.isRValue()) {
emitDirect(arg.getKnownRValueLocation(), std::move(arg).asKnownRValue(),
origParamType, param);
} else {
Expr *e = std::move(arg).asKnownExpr();
emitDirect(e, SGF.emitRValue(e), origParamType, param);
}
}
void emitDirect(SILLocation loc, RValue &&arg,
AbstractionPattern origParamType,
SILParameterInfo param) {
auto value = std::move(arg).getScalarValue();
if (isNative(CC)) {
value = SGF.emitSubstToOrigValue(loc, value, origParamType,
arg.getType());
} else {
value = SGF.emitNativeToBridgedValue(loc, value, CC,
origParamType.getAsType(),
arg.getType(), param.getType());
}
Args.push_back(value);
}
};
/// A structure for conveniently claiming sets of uncurried parameters.
struct ParamLowering {
ArrayRef<SILParameterInfo> Params;
AbstractCC CC;
ParamLowering(CanSILFunctionType fnType) :
Params(fnType->getInterfaceParametersWithoutIndirectResult()),
CC(fnType->getAbstractCC()) {}
ArrayRef<SILParameterInfo>
claimParams(AbstractionPattern origParamType, CanType substParamType) {
unsigned count = getFlattenedValueCount(origParamType, substParamType);
assert(count <= Params.size());
auto result = Params.slice(Params.size() - count, count);
Params = Params.slice(0, Params.size() - count);
return result;
}
~ParamLowering() {
assert(Params.empty() && "didn't consume all the parameters");
}
};
class CallSite {
public:
SILLocation Loc;
CanType SubstResultType;
private:
RValueSource ArgValue;
public:
CallSite(ApplyExpr *apply)
: Loc(apply), SubstResultType(apply->getType()->getCanonicalType()),
ArgValue(apply->getArg()) {
}
CallSite(SILLocation loc, Expr *expr, Type resultType)
: Loc(loc), SubstResultType(resultType->getCanonicalType()),
ArgValue(expr) {
}
CallSite(SILLocation loc, RValueSource &&value, Type resultType)
: Loc(loc), SubstResultType(resultType->getCanonicalType()),
ArgValue(std::move(value)) {
}
/// Return the substituted, unlowered AST type of the argument.
CanType getSubstArgType() const {
return ArgValue.getSubstType();
}
/// Return the substituted, unlowered AST type of the result of
/// this application.
CanType getSubstResultType() const {
return SubstResultType;
}
void emit(SILGenFunction &gen,
AbstractionPattern origParamType,
ParamLowering &lowering,
SmallVectorImpl<ManagedValue> &args) && {
auto params = lowering.claimParams(origParamType, getSubstArgType());
ArgEmitter emitter(gen, lowering.CC, params, args);
emitter.emit(std::move(ArgValue), origParamType);
}
};
class CallEmission {
SILGenFunction &gen;
std::vector<CallSite> uncurriedSites;
std::vector<CallSite> extraSites;
Callee callee;
Optional<WritebackScope> initialWritebackScope;
unsigned uncurries;
bool applied;
public:
CallEmission(SILGenFunction &gen, Callee &&callee)
: gen(gen),
callee(std::move(callee)),
uncurries(callee.getNaturalUncurryLevel() + 1),
applied(false)
{}
CallEmission(SILGenFunction &gen, Callee &&callee,
WritebackScope &&writebackScope)
: CallEmission(gen, std::move(callee))
{
initialWritebackScope.emplace(std::move(writebackScope));
}
void addCallSite(CallSite &&site) {
assert(!applied && "already applied!");
// Append to the main argument list if we have uncurry levels remaining.
if (uncurries > 0) {
--uncurries;
uncurriedSites.push_back(std::move(site));
return;
}
// Otherwise, apply these arguments to the result of the previous call.
extraSites.push_back(std::move(site));
}
template<typename...T>
void addCallSite(T &&...args) {
addCallSite(CallSite{std::forward<T>(args)...});
}
ManagedValue apply(SGFContext C = SGFContext()) {
assert(!applied && "already applied!");
applied = true;
// Get the callee value at the needed uncurry level.
unsigned uncurryLevel = callee.getNaturalUncurryLevel() - uncurries;
// Get either the specialized emitter for a known function, or the
// function value for a normal callee.
Callee::SpecializedEmitter specializedEmitter = nullptr;
CanSILFunctionType substFnType;
ManagedValue mv;
bool transparent;
AbstractionPattern origFormalType(callee.getOrigFormalType());
CanAnyFunctionType formalType = callee.getSubstFormalType();
// Check for a specialized emitter.
auto maybeEmitter = callee.getSpecializedEmitter(gen.SGM, uncurryLevel);
if (maybeEmitter) {
specializedEmitter = maybeEmitter.getValue();
// We want to emit the arguments as fully-substituted values
// because that's what the specialized emitters expect.
origFormalType = AbstractionPattern(formalType);
substFnType = gen.getLoweredType(formalType, uncurryLevel)
.castTo<SILFunctionType>();
transparent = false; // irrelevant
} else {
std::tie(mv, substFnType, transparent) =
callee.getAtUncurryLevel(gen, uncurryLevel);
}
// Emit the arguments.
Optional<SILLocation> uncurriedLoc;
SmallVector<SmallVector<ManagedValue, 4>, 2> args;
args.reserve(uncurriedSites.size());
{
ParamLowering paramLowering(substFnType);
// Collect the arguments to the uncurried call.
for (auto &site : uncurriedSites) {
AbstractionPattern origParamType =
claimNextParamClause(origFormalType);
uncurriedLoc = site.Loc;
args.push_back({});
std::move(site).emit(gen, origParamType, paramLowering, args.back());
}
}
assert(uncurriedLoc);
// Uncurry the arguments in calling convention order.
SmallVector<ManagedValue, 4> uncurriedArgs;
for (auto &argSet : reversed(args))
uncurriedArgs.append(argSet.begin(), argSet.end());
args = {};
// We use the context emit-into initialization only for the outermost
// call.
SGFContext uncurriedContext =
(extraSites.empty() ? C : SGFContext());
// Emit the uncurried call.
ManagedValue result;
if (specializedEmitter)
result = specializedEmitter(gen,
uncurriedLoc.getValue(),
callee.getSubstitutions(),
uncurriedArgs,
uncurriedContext);
else
result = emitApply(gen, uncurriedLoc.getValue(), mv,
callee.getSubstitutions(),
uncurriedArgs,
substFnType,
origFormalType,
uncurriedSites.back().getSubstResultType(),
transparent, Nothing,
uncurriedContext);
// End the initial writeback scope, if any.
initialWritebackScope.reset();
// If there are remaining call sites, apply them to the result function.
// Each chained call gets its own writeback scope.
claimNextParamClause(formalType);
for (unsigned i = 0, size = extraSites.size(); i < size; ++i) {
WritebackScope scope(gen);
auto substFnType = result.getType().castTo<SILFunctionType>();
ParamLowering paramLowering(substFnType);
uncurriedArgs.clear();
// The result function has already been reabstracted to the substituted
// type.
AbstractionPattern origParamType(claimNextParamClause(formalType));
std::move(extraSites[i]).emit(gen, origParamType, paramLowering,
uncurriedArgs);
SGFContext context = i == size - 1 ? C : SGFContext();
SILLocation loc = extraSites[i].Loc;
result = emitApply(gen, loc, result, {}, uncurriedArgs,
substFnType,
origFormalType,
extraSites[i].getSubstResultType(),
false, Nothing, context);
}
return result;
}
~CallEmission() { assert(applied && "never applied!"); }
// Movable, but not copyable.
CallEmission(CallEmission &&e)
: gen(e.gen),
uncurriedSites(std::move(e.uncurriedSites)),
extraSites(std::move(e.extraSites)),
callee(std::move(e.callee)),
uncurries(e.uncurries),
applied(e.applied) {
e.applied = true;
}
private:
CallEmission(const CallEmission &) = delete;
CallEmission &operator=(const CallEmission &) = delete;
};
static ManagedValue emitBuiltinRetain(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
// The value was produced at +1; we can produce an unbalanced
// retain simply by disabling the cleanup.
args[0].forward(gen);
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
static ManagedValue emitBuiltinRelease(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
// The value was produced at +1, so to produce an unbalanced
// release we need to leave the cleanup intact and then do a *second*
// release.
gen.B.createReleaseValue(loc, args[0].getValue());
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
static ManagedValue emitBuiltinAutorelease(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
// The value was produced at +1, so to produce an unbalanced
// autorelease we need to leave the cleanup intact.
gen.B.createAutoreleaseValue(loc, args[0].getValue());
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
/// Specialized emitter for Builtin.load and Builtin.take.
static ManagedValue emitBuiltinLoadOrTake(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C,
IsTake_t isTake) {
assert(substitutions.size() == 1 && "load should have single substitution");
assert(args.size() == 1 && "load should have a single argument");
// The substitution gives the type of the load. This is always a
// first-class type; there is no way to e.g. produce a @weak load
// with this builtin.
auto &rvalueTL = gen.getTypeLowering(substitutions[0].Replacement);
SILType loadedType = rvalueTL.getLoweredType();
// Convert the pointer argument to a SIL address.
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
loadedType.getAddressType());
// Perform the load.
return gen.emitLoad(loc, addr, rvalueTL, C, isTake);
}
static ManagedValue emitBuiltinLoad(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
return emitBuiltinLoadOrTake(gen, loc, substitutions, args, C, IsNotTake);
}
static ManagedValue emitBuiltinTake(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
return emitBuiltinLoadOrTake(gen, loc, substitutions, args, C, IsTake);
}
/// Specialized emitter for Builtin.destroy.
static ManagedValue emitBuiltinDestroy(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 2 && "destroy should have two arguments");
assert(substitutions.size() == 1 &&
"destroy should have a single substitution");
// The substitution determines the type of the thing we're destroying.
auto &ti = gen.getTypeLowering(substitutions[0].Replacement);
// Destroy is a no-op for trivial types.
if (ti.isTrivial())
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
SILType destroyType = ti.getLoweredType();
// Convert the pointer argument to a SIL address.
SILValue addr =
gen.B.createPointerToAddress(loc, args[1].getUnmanagedValue(),
destroyType.getAddressType());
// Destroy the value indirectly. Canonicalization will promote to loads
// and releases if appropriate.
gen.B.emitDestroyAddr(loc, addr);
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
/// Specialized emitter for Builtin.assign and Builtin.init.
static ManagedValue emitBuiltinAssignOrInit(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C,
bool isInitialization) {
assert(args.size() >= 2 && "assign should have two arguments");
assert(substitutions.size() == 1 &&
"assign should have a single substitution");
// The substitution determines the type of the thing we're destroying.
CanType assignFormalType = substitutions[0].Replacement->getCanonicalType();
SILType assignType = gen.getLoweredType(assignFormalType);
// Convert the destination pointer argument to a SIL address.
SILValue addr = gen.B.createPointerToAddress(loc,
args.back().getUnmanagedValue(),
assignType.getAddressType());
// Build the value to be assigned, reconstructing tuples if needed.
ManagedValue src = RValue(args.slice(0, args.size() - 1), assignFormalType)
.getAsSingleValue(gen, loc);
if (isInitialization)
src.forwardInto(gen, loc, addr);
else
src.assignInto(gen, loc, addr);
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
static ManagedValue emitBuiltinAssign(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
return emitBuiltinAssignOrInit(gen, loc, substitutions, args, C,
/*isInitialization*/ false);
}
static ManagedValue emitBuiltinInit(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
return emitBuiltinAssignOrInit(gen, loc, substitutions, args, C,
/*isInitialization*/ true);
}
/// Specialized emitter for Builtin.fixLifetime.
static ManagedValue emitBuiltinFixLifetime(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
for (auto arg : args) {
gen.B.createFixLifetime(loc, arg.getValue());
}
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
/// Specialized emitter for Builtin.castToNativeObject.
static ManagedValue emitBuiltinCastToNativeObject(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "cast should have a single argument");
assert(substitutions.size() == 1 && "cast should have a type substitution");
// Bail if the source type is not a class reference of some kind.
if (!substitutions[0].Replacement->mayHaveSuperclass() &&
!substitutions[0].Replacement->isClassExistentialType()) {
gen.SGM.diagnose(loc, diag::invalid_sil_builtin,
"castToNativeObject source must be a class");
// FIXME: Recovery?
llvm::report_fatal_error("unable to set up the ObjC bridge!");
}
// Save the cleanup on the argument so we can forward it onto the cast
// result.
auto cleanup = args[0].getCleanup();
// Take the reference type argument and cast it to NativeObject.
SILType objPointerType = SILType::getNativeObjectType(gen.F.getASTContext());
SILValue arg = args[0].getValue();
// If the argument is existential, project it.
if (substitutions[0].Replacement->isClassExistentialType()) {
SmallVector<ProtocolDecl *, 4> protocols;
substitutions[0].Replacement->getAnyExistentialTypeProtocols(protocols);
ProtocolDecl *proto = *std::find_if(protocols.begin(), protocols.end(),
[](ProtocolDecl *proto) {
return proto->requiresClass();
});
SILType protoSelfTy = gen.getLoweredType(
proto->getSelf()->getArchetype());
arg = gen.B.createProjectExistentialRef(loc, arg, protoSelfTy);
}
SILValue result = gen.B.createUncheckedRefCast(loc, arg, objPointerType);
// Return the cast result with the original cleanup.
return ManagedValue(result, cleanup);
}
/// Specialized emitter for Builtin.castFromNativeObject.
static ManagedValue emitBuiltinCastFromNativeObject(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "cast should have a single argument");
assert(substitutions.size() == 1 &&
"cast should have a single substitution");
// Bail if the source type is not a class reference of some kind.
if (!substitutions[0].Replacement->mayHaveSuperclass()) {
gen.SGM.diagnose(loc, diag::invalid_sil_builtin,
"castFromNativeObject dest must be a class");
// FIXME: Recovery?
llvm::report_fatal_error("unable to set up the ObjC bridge!");
}
// Save the cleanup on the argument so we can forward it onto the cast
// result.
auto cleanup = args[0].getCleanup();
// The substitution determines the destination type.
// FIXME: Archetype destination type?
SILType destType = gen.getLoweredLoadableType(substitutions[0].Replacement);
// Take the reference type argument and cast it.
SILValue result = gen.B.createUncheckedRefCast(loc, args[0].getValue(),
destType);
// Return the cast result with the original cleanup.
return ManagedValue(result, cleanup);
}
/// Specialized emitter for Builtin.bridgeToRawPointer.
static ManagedValue emitBuiltinBridgeToRawPointer(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "bridge should have a single argument");
// Take the reference type argument and cast it to RawPointer.
// RawPointers do not have ownership semantics, so the cleanup on the
// argument remains.
SILType rawPointerType = SILType::getRawPointerType(gen.F.getASTContext());
SILValue result = gen.B.createRefToRawPointer(loc, args[0].getValue(),
rawPointerType);
return ManagedValue::forUnmanaged(result);
}
/// Specialized emitter for Builtin.bridgeFromRawPointer.
static ManagedValue emitBuiltinBridgeFromRawPointer(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(substitutions.size() == 1 &&
"bridge should have a single substitution");
assert(args.size() == 1 && "bridge should have a single argument");
// The substitution determines the destination type.
// FIXME: Archetype destination type?
auto &destLowering = gen.getTypeLowering(substitutions[0].Replacement);
assert(destLowering.isLoadable());
SILType destType = destLowering.getLoweredType();
// Take the raw pointer argument and cast it to the destination type.
SILValue result = gen.B.createRawPointerToRef(loc, args[0].getUnmanagedValue(),
destType);
// The result has ownership semantics, so retain it with a cleanup.
return gen.emitManagedRetain(loc, result, destLowering);
}
/// Specialized emitter for Builtin.addressof.
static ManagedValue emitBuiltinAddressOf(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "addressof should have a single argument");
// Take the address argument and cast it to RawPointer.
SILType rawPointerType = SILType::getRawPointerType(gen.F.getASTContext());
SILValue result = gen.B.createAddressToPointer(loc,
args[0].getUnmanagedValue(),
rawPointerType);
return ManagedValue::forUnmanaged(result);
}
/// Specialized emitter for Builtin.typeof.
static ManagedValue emitBuiltinTypeOf(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "typeof should have a single argument");
// Get the metatype of the argument.
SILValue metaTy = gen.emitMetatypeOfValue(loc, args[0].getValue());
return ManagedValue::forUnmanaged(metaTy);
}
/// Specialized emitter for Builtin.gep.
static ManagedValue emitBuiltinGep(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 2 && "gep should be given two arguments");
SILValue offsetPtr = gen.B.createIndexRawPointer(loc,
args[0].getUnmanagedValue(),
args[1].getUnmanagedValue());
return ManagedValue::forUnmanaged(offsetPtr);
}
/// Specialized emitter for Builtin.condfail.
static ManagedValue emitBuiltinCondFail(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(args.size() == 1 && "condfail should be given one argument");
gen.B.createCondFail(loc, args[0].getUnmanagedValue());
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
/// The type of trait builtins.
static SILType getTypeTraitSILType(ASTContext &C) {
auto param = CanGenericTypeParamType::get(0, 0, C);
auto reqt = Requirement(RequirementKind::WitnessMarker,
param, param);
auto metaTy = CanMetatypeType::get(param, MetatypeRepresentation::Thick);
auto sig = GenericSignature::get(param.getPointer(), reqt)
->getCanonicalSignature();
auto boolTy = BuiltinIntegerType::get(1, C)
->getCanonicalType();
auto fnTy = SILFunctionType::get(sig,
AnyFunctionType::ExtInfo()
.withRepresentation(FunctionType::Representation::Thin),
ParameterConvention::Direct_Unowned,
SILParameterInfo(metaTy, ParameterConvention::Direct_Unowned),
SILResultInfo(boolTy, ResultConvention::Unowned), C);
return SILType::getPrimitiveObjectType(fnTy);
}
/// Specialized emitter for type traits.
template<TypeTraitResult (TypeBase::*Trait)(),
BuiltinValueKind Kind>
static ManagedValue emitBuiltinTypeTrait(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(substitutions.size() == 1
&& "type trait should take a single type parameter");
assert(args.size() == 1
&& "type trait should take a single argument");
bool result;
auto traitTy = substitutions[0].Replacement->getCanonicalType();
switch ((traitTy.getPointer()->*Trait)()) {
// If the type obviously has or lacks the trait, emit a constant result.
case TypeTraitResult::IsNot:
result = false;
break;
case TypeTraitResult::Is:
result = true;
break;
// If not, emit the builtin call normally. Specialization may be able to
// eliminate it later, or we'll lower it away at IRGen time.
case TypeTraitResult::CanBe: {
auto &C = gen.getASTContext();
auto builtin = gen.B.createBuiltinFunctionRef(loc,
C.getIdentifier(getBuiltinName(Kind)),
getTypeTraitSILType(C));
auto builtinTy = builtin->getType().castTo<SILFunctionType>();
auto substTy = builtinTy->substInterfaceGenericArgs(gen.SGM.M,
gen.SGM.M.getSwiftModule(), substitutions);
auto apply = gen.B.createApply(loc, builtin,
SILType::getPrimitiveObjectType(substTy),
builtinTy->getInterfaceResult().getSILType(),
substitutions, args[0].getValue());
return ManagedValue::forUnmanaged(apply);
}
}
// Produce the result as an integer literal constant.
auto val = gen.B.createIntegerLiteral(loc,
SILType::getBuiltinIntegerType(1, gen.getASTContext()),
(uintmax_t)result);
return ManagedValue::forUnmanaged(val);
}
Callee::SpecializedEmitter
Callee::getSpecializedEmitterForSILBuiltin(SILDeclRef function,
SILModule &SILM) {
// Filter out non-function members and non-builtin modules.
if (function.kind != SILDeclRef::Kind::Func)
return nullptr;
if (!function.hasDecl())
return nullptr;
ValueDecl *decl = function.getDecl();
if (!isa<BuiltinUnit>(decl->getDeclContext()))
return nullptr;
const BuiltinInfo &Builtin = SILM.getBuiltinInfo(decl->getName());
// Match SIL builtins to their emitters.
#define BUILTIN(Id, Name, Attrs)
#define BUILTIN_SIL_OPERATION(Id, Name, Overload) \
if (Builtin.ID == BuiltinValueKind::Id) \
return &emitBuiltin##Id;
// Lower away type trait builtins when they're trivially solvable.
#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \
if (Builtin.ID == BuiltinValueKind::Id) \
return &emitBuiltinTypeTrait<&TypeBase::Name, BuiltinValueKind::Id>;
#include "swift/AST/Builtins.def"
return nullptr;
}
} // end anonymous namespace
static CallEmission prepareApplyExpr(SILGenFunction &gen, Expr *e) {
// Set up writebacks for the call(s).
WritebackScope writebacks(gen);
SILGenApply apply(gen);
// Decompose the call site.
apply.decompose(e);
// Evaluate and discard the side effect if present.
if (apply.sideEffect)
gen.emitRValue(apply.sideEffect);
// Build the call.
// Pass the writeback scope on to CallEmission so it can thread scopes through
// nested calls.
CallEmission emission(gen, apply.getCallee(), std::move(writebacks));
// Apply 'self' if provided.
if (apply.selfParam)
emission.addCallSite(RegularLocation(e),
RValueSource(apply.SelfApplyExpr,
std::move(apply.selfParam)),
apply.SelfApplyExpr->getType());
// Apply arguments from call sites, innermost to outermost.
for (auto site = apply.callSites.rbegin(), end = apply.callSites.rend();
site != end;
++site) {
emission.addCallSite(*site);
}
return emission;
}
RValue SILGenFunction::emitApplyExpr(ApplyExpr *e, SGFContext c) {
return RValue(*this, e, prepareApplyExpr(*this, e).apply(c));
}
ManagedValue
SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc,
FuncDecl *fn,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
SGFContext ctx) {
auto origFormalType =
cast<AnyFunctionType>(fn->getType()->getCanonicalType());
auto substFormalType = origFormalType;
if (!subs.empty()) {
auto polyFnType = cast<PolymorphicFunctionType>(substFormalType);
auto applied = polyFnType->substGenericArgs(SGM.SwiftModule, subs);
substFormalType = cast<FunctionType>(applied->getCanonicalType());
}
auto callee = Callee::forDirect(*this, SILDeclRef(fn), substFormalType, loc);
callee.setSubstitutions(*this, loc, subs, 0);
ManagedValue mv;
CanSILFunctionType substFnType;
bool transparent;
std::tie(mv, substFnType, transparent) = callee.getAtUncurryLevel(*this, 0);
assert(substFnType->getAbstractCC() == AbstractCC::Freestanding);
return emitApply(*this, loc, mv, subs, args, substFnType,
AbstractionPattern(origFormalType.getResult()),
substFormalType.getResult(),
transparent, Nothing, ctx);
}
/// emitArrayInjectionCall - Form an array "Array" out of an NativeObject
/// (which represents the retain count), a base pointer to some elements, and a
/// length.
ManagedValue SILGenFunction::emitArrayInjectionCall(ManagedValue ObjectPtr,
SILValue BasePtr,
SILValue Length,
Expr *ArrayInjectionFunction,
SILLocation Loc) {
// Bitcast the BasePtr (an lvalue) to Builtin.RawPointer if it isn't already.
if (BasePtr.getType() != SILType::getRawPointerType(F.getASTContext()))
BasePtr = B.createAddressToPointer(Loc,
BasePtr,
SILType::getRawPointerType(F.getASTContext()));
// Construct a call to the injection function.
CallEmission emission = prepareApplyExpr(*this, ArrayInjectionFunction);
auto *injectionFnTy
= ArrayInjectionFunction->getType()->getAs<FunctionType>();
auto injectionArgsTy = cast<TupleType>(injectionFnTy->getInput()->getCanonicalType());
RValue InjectionArgs(injectionArgsTy);
InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(0),
ManagedValue::forUnmanaged(BasePtr)));
InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(1),
ObjectPtr));
InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(2),
ManagedValue::forUnmanaged(Length)));
emission.addCallSite(Loc, RValueSource(Loc, std::move(InjectionArgs)),
injectionFnTy->getResult());
return emission.apply();
}
static Callee getBaseAccessorFunctionRef(SILGenFunction &gen,
SILLocation loc,
SILDeclRef constant,
RValueSource &selfValue,
bool isSuper,
CanAnyFunctionType substAccessorType,
ArrayRef<Substitution> &substitutions){
auto *decl = cast<AbstractFunctionDecl>(constant.getDecl());
// If this is a method in a protocol, generate it as a protocol call.
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl->getDeclContext())) {
// Method calls through ObjC protocols require ObjC dispatch.
constant = constant.asForeign(protoDecl->isObjC());
// The protocol self is implicitly decurried.
substAccessorType = CanAnyFunctionType(substAccessorType->getResult()
->castTo<AnyFunctionType>());
// If this is an archetype case, construct an archetype call.
if (!selfValue.getSubstType()->getInOutObjectType()->isAnyExistentialType()) {
SILValue baseVal =
selfValue.forceAndPeekRValue(gen).peekScalarValue();
return Callee::forArchetype(gen, baseVal, constant,
substAccessorType, loc);
}
// If this is a protocol (not archetype) use, project out the underlying
// existential.
ManagedValue baseVal =
std::move(selfValue).getAsSingleValue(gen, SGFContext::AllowPlusZero);
SILType protoSelfTy =
gen.getLoweredType(protoDecl->getSelf()->getArchetype());
auto selfLoc = selfValue.getLocation();
ManagedValue projVal;
if (baseVal.getType().isClassExistentialType()) {
// Attach the existential cleanup to the projection so that it gets
// consumed (or not) when the call is applied to it (or isn't).
SILValue val = gen.B.createProjectExistentialRef(loc,
baseVal.getValue(),
protoSelfTy);
projVal = ManagedValue(val, baseVal.getCleanup());
} else {
assert(protoSelfTy.isAddress() && "Self should be address-only");
SILValue val = gen.B.createProjectExistential(selfLoc,
baseVal.getValue(),
protoSelfTy);
projVal = ManagedValue::forUnmanaged(val);
}
// Update the self value to use the projection.
selfValue = RValueSource(selfLoc, RValue(gen, selfLoc,
protoSelfTy.getSwiftType(),
projVal));
assert(substitutions.size() >= 1);
substitutions = substitutions.slice(1);
return Callee::forProtocol(gen, baseVal.getValue(), constant,
substAccessorType, loc);
}
bool isClassDispatch = false;
if (auto ctx = decl->getDeclContext()->getDeclaredTypeOfContext())
isClassDispatch = ctx->getClassOrBoundGenericClass();
// Dispatch in a struct/enum or to an @final method is always direct.
if (!isClassDispatch || decl->isFinal())
return Callee::forDirect(gen, constant, substAccessorType, loc);
// Otherwise, if we have a non-final class dispatch to a normal method,
// perform a dynamic dispatch.
auto self = selfValue.forceAndPeekRValue(gen).peekScalarValue();
if (!isSuper)
return Callee::forClassMethod(gen, self, constant, substAccessorType,
loc);
// If this is a "super." dispatch, we either do a direct dispatch in the case
// of swift classes or an objc super call.
while (auto *upcast = dyn_cast<UpcastInst>(self))
self = upcast->getOperand();
if (constant.isForeign)
return Callee::forSuperMethod(gen, self, constant, substAccessorType,loc);
return Callee::forDirect(gen, constant, substAccessorType, loc);
}
static Callee
emitSpecializedAccessorFunctionRef(SILGenFunction &gen,
SILLocation loc,
SILDeclRef constant,
ArrayRef<Substitution> substitutions,
RValueSource &selfValue,
bool isSuper)
{
// If the accessor is a local constant, use it.
// FIXME: Can local properties ever be generic?
if (gen.LocalFunctions.count(constant)) {
SILValue v = gen.LocalFunctions[constant];
auto formalType =
gen.SGM.Types.getConstantFormalTypeWithoutCaptures(constant);
return Callee::forIndirect(gen.emitManagedRetain(loc, v),
formalType, formalType, false, loc);
}
SILConstantInfo constantInfo = gen.getConstantInfo(constant);
// Apply substitutions to the callee type.
CanAnyFunctionType substAccessorType = constantInfo.FormalType;
if (!substitutions.empty()) {
auto polyFn = cast<PolymorphicFunctionType>(substAccessorType);
auto substFn = polyFn->substGenericArgs(gen.SGM.SwiftModule, substitutions);
substAccessorType = cast<FunctionType>(substFn->getCanonicalType());
}
// Get the accessor function. The type will be a polymorphic function if
// the Self type is generic.
// FIXME: Dynamic dispatch for archetype/existential methods.
Callee callee = getBaseAccessorFunctionRef(gen, loc, constant, selfValue,
isSuper, substAccessorType,
substitutions);
// If there are substitutions, specialize the generic accessor.
// FIXME: Generic subscript operator could add another layer of
// substitutions.
if (!substitutions.empty()) {
callee.setSubstitutions(gen, loc, substitutions, 0);
}
return callee;
}
RValueSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc,
ManagedValue base,
AbstractFunctionDecl *decl){
if (base.isLValue()) {
// inout bases get passed by their address.
if (decl->getImplicitSelfDecl()->getType()->is<InOutType>())
return RValueSource(loc, RValue(*this, loc,
base.getType().getSwiftType(),
base));
// When calling an accessor, the base may be provided as an inout value,
// even though we only need an rvalue. In this case, load the value out of
// the address.
// TODO: this causes us to materialize stuff (at the SIL level) that will
// just be loaded - unnecessarily dumping stuff in memory.
base = emitLoad(loc, base.getValue(),
getTypeLowering(base.getType().getObjectType()),
SGFContext(), IsNotTake);
}
return RValueSource(loc, RValue(*this, loc,
base.getType().getSwiftType(), base));
}
/// Emit a call to a getter.
ManagedValue SILGenFunction::
emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
ArrayRef<Substitution> substitutions, RValueSource &&selfValue,
bool isSuper, RValue &&subscripts, SGFContext c) {
SILDeclRef get(decl->getGetter(), SILDeclRef::Kind::Func,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
decl->usesObjCGetterAndSetter());
Callee getter = emitSpecializedAccessorFunctionRef(*this, loc, get,
substitutions, selfValue,
isSuper);
CanAnyFunctionType accessType = getter.getSubstFormalType();
CallEmission emission(*this, std::move(getter));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
accessType = cast<AnyFunctionType>(accessType.getResult());
}
// Index or () if none.
if (!subscripts)
subscripts = emitEmptyTupleRValue(loc);
emission.addCallSite(loc, RValueSource(loc, std::move(subscripts)),
accessType.getResult());
// T
return emission.apply(c);
}
void SILGenFunction::emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl,
ArrayRef<Substitution> substitutions,
RValueSource &&selfValue,
bool isSuper,
RValue &&subscripts, RValue &&setValue) {
SILDeclRef set(decl->getSetter(), SILDeclRef::Kind::Func,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
decl->usesObjCGetterAndSetter());
Callee setter = emitSpecializedAccessorFunctionRef(*this, loc, set,
substitutions, selfValue,
isSuper);
CanAnyFunctionType accessType = setter.getSubstFormalType();
CallEmission emission(*this, std::move(setter));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
accessType = cast<AnyFunctionType>(accessType.getResult());
}
// (value) or (value, indices)
if (subscripts) {
// If we have a value and index list, create a new rvalue to represent the
// both of them together. The value goes first.
SmallVector<ManagedValue, 4> Elts;
std::move(setValue).getAll(Elts);
std::move(subscripts).getAll(Elts);
setValue = RValue(Elts, accessType.getInput());
} else {
setValue.rewriteType(accessType.getInput());
}
emission.addCallSite(loc, RValueSource(loc, std::move(setValue)),
accessType.getResult());
// ()
emission.apply();
}
ManagedValue SILGenFunction::emitApplyConversionFunction(SILLocation loc,
Expr *funcExpr,
Type resultType,
RValue &&operand) {
// Walk the function expression, which should produce a reference to the
// callee, leaving the final curry level unapplied.
CallEmission emission = prepareApplyExpr(*this, funcExpr);
// Rewrite the operand type to the expected argument type, to handle tuple
// conversions etc.
operand.rewriteType(funcExpr->getType()->castTo<FunctionType>()->getInput()
->getCanonicalType());
// Add the operand as the final callsite.
emission.addCallSite(loc, RValueSource(loc, std::move(operand)), resultType);
return emission.apply();
}
// Create a partial application of a dynamic method, applying bridging thunks
// if necessary.
static SILValue emitDynamicPartialApply(SILGenFunction &gen,
SILLocation loc,
SILValue method,
SILValue self,
CanFunctionType methodTy) {
// Pop the self type off of the function type.
// Just to be weird, partially applying an objc method produces a native
// function (?!)
auto fnTy = method.getType().castTo<SILFunctionType>();
// If the original method has an @unowned_inner_pointer return, the partial
// application thunk will lifetime-extend 'self' for us.
auto resultInfo = fnTy->getInterfaceResult();
if (resultInfo.getConvention() == ResultConvention::UnownedInnerPointer)
resultInfo = SILResultInfo(resultInfo.getType(), ResultConvention::Unowned);
auto partialApplyTy = SILFunctionType::get(fnTy->getGenericSignature(),
fnTy->getExtInfo()
.withCallingConv(AbstractCC::Freestanding)
.withRepresentation(FunctionType::Representation::Thick),
ParameterConvention::Direct_Owned,
fnTy->getInterfaceParameters()
.slice(0, fnTy->getInterfaceParameters().size() - 1),
resultInfo, gen.getASTContext());
// Retain 'self' because the partial apply will take ownership.
// We can't simply forward 'self' because the partial apply is conditional.
gen.B.emitRetainValueOperation(loc, self);
SILValue result = gen.B.createPartialApply(loc, method, method.getType(), {},
self, SILType::getPrimitiveObjectType(partialApplyTy));
// If necessary, thunk to the native ownership conventions and bridged types.
auto nativeTy = gen.getLoweredLoadableType(methodTy).castTo<SILFunctionType>();
if (nativeTy != partialApplyTy) {
result = gen.emitBlockToFunc(loc, ManagedValue::forUnmanaged(result),
nativeTy).forward(gen);
}
return result;
}
RValue SILGenFunction::emitDynamicMemberRefExpr(DynamicMemberRefExpr *e,
SGFContext c) {
// Emit the operand.
ManagedValue existential = emitRValueAsSingleValue(e->getBase());
SILValue operand = existential.getValue();
if (e->getMember().getDecl()->isInstanceMember()) {
operand = B.createProjectExistentialRef(e, operand,
getSelfTypeForDynamicLookup(*this, operand));
operand = B.createUncheckedRefCast(e, operand,
SILType::getUnknownObjectType(getASTContext()));
} else {
auto metatype = operand.getType().castTo<ExistentialMetatypeType>();
assert(metatype->getRepresentation() == MetatypeRepresentation::Thick);
metatype = CanExistentialMetatypeType::get(metatype.getInstanceType(),
MetatypeRepresentation::ObjC);
operand = B.createThickToObjCMetatype(e, operand,
SILType::getPrimitiveObjectType(metatype));
}
// Create the has-member block.
SILBasicBlock *hasMemberBB = new (F.getModule()) SILBasicBlock(&F);
// Create the no-member block.
SILBasicBlock *noMemberBB = new (F.getModule()) SILBasicBlock(&F);
// Create the continuation block.
SILBasicBlock *contBB = new (F.getModule()) SILBasicBlock(&F);
// The continuation block
const TypeLowering &optTL = getTypeLowering(e->getType());
auto loweredOptTy = optTL.getLoweredType();
SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy);
// Create the branch.
FuncDecl *memberFunc;
if (auto *VD = dyn_cast<VarDecl>(e->getMember().getDecl()))
memberFunc = VD->getGetter();
else
memberFunc = cast<FuncDecl>(e->getMember().getDecl());
SILDeclRef member(memberFunc, SILDeclRef::Kind::Func,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
/*isObjC=*/true);
B.createDynamicMethodBranch(e, operand, member, hasMemberBB, noMemberBB);
// Create the has-member branch.
{
B.emitBlock(hasMemberBB);
FullExpr hasMemberScope(Cleanups, CleanupLocation(e));
// The argument to the has-member block is the uncurried method.
auto valueTy = e->getType()->getCanonicalType().getAnyOptionalObjectType();
auto methodTy = valueTy;
// For a computed variable, we want the getter.
if (isa<VarDecl>(e->getMember().getDecl()))
methodTy = CanFunctionType::get(TupleType::getEmpty(getASTContext()),
methodTy);
auto dynamicMethodTy = getDynamicMethodLoweredType(SGM, operand, member);
auto loweredMethodTy = SILType::getPrimitiveObjectType(dynamicMethodTy);
SILValue memberArg = new (F.getModule()) SILArgument(loweredMethodTy,
hasMemberBB);
// Create the result value.
SILValue result = emitDynamicPartialApply(*this, e, memberArg, operand,
cast<FunctionType>(methodTy));
if (isa<VarDecl>(e->getMember().getDecl())) {
result = B.createApply(e, result, result.getType(),
getLoweredType(valueTy), {}, {});
}
// Package up the result in an optional.
RValue resultRV = RValue(*this, e, valueTy,
emitManagedRValueWithCleanup(result));
emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL);
// Branch to the continuation block.
B.createBranch(e, contBB);
}
// Create the no-member branch.
{
B.emitBlock(noMemberBB);
emitInjectOptionalNothingInto(e, optTemp, optTL);
// Branch to the continuation block.
B.createBranch(e, contBB);
}
// Emit the continuation block.
B.emitBlock(contBB);
// Package up the result.
auto optResult = B.createLoad(e, optTemp);
return RValue(*this, e, emitManagedRValueWithCleanup(optResult, optTL));
}
RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e,
SGFContext c) {
// Emit the base operand.
ManagedValue existential = emitRValueAsSingleValue(e->getBase());
SILValue base = existential.getValue();
base = B.createProjectExistentialRef(e, base,
getSelfTypeForDynamicLookup(*this, base));
base = B.createUncheckedRefCast(e, base,
SILType::getUnknownObjectType(getASTContext()));
// Emit the index.
RValue index = emitRValue(e->getIndex());
// Create the has-member block.
SILBasicBlock *hasMemberBB = new (F.getModule()) SILBasicBlock(&F);
// Create the no-member block.
SILBasicBlock *noMemberBB = new (F.getModule()) SILBasicBlock(&F);
// Create the continuation block.
SILBasicBlock *contBB = new (F.getModule()) SILBasicBlock(&F);
// The continuation block
const TypeLowering &optTL = getTypeLowering(e->getType());
auto loweredOptTy = optTL.getLoweredType();
SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy);
// Create the branch.
auto subscriptDecl = cast<SubscriptDecl>(e->getMember().getDecl());
SILDeclRef member(subscriptDecl->getGetter(),
SILDeclRef::Kind::Func,
SILDeclRef::ConstructAtBestResilienceExpansion,
SILDeclRef::ConstructAtNaturalUncurryLevel,
/*isObjC=*/true);
B.createDynamicMethodBranch(e, base, member, hasMemberBB, noMemberBB);
// Create the has-member branch.
{
B.emitBlock(hasMemberBB);
FullExpr hasMemberScope(Cleanups, CleanupLocation(e));
// The argument to the has-member block is the uncurried method.
auto valueTy = e->getType()->getCanonicalType().getAnyOptionalObjectType();
auto methodTy =
subscriptDecl->getGetter()->getType()->castTo<AnyFunctionType>()
->getResult()->getCanonicalType();
auto dynamicMethodTy = getDynamicMethodLoweredType(SGM, base, member);
auto loweredMethodTy = SILType::getPrimitiveObjectType(dynamicMethodTy);
SILValue memberArg = new (F.getModule()) SILArgument(loweredMethodTy,
hasMemberBB);
// Emit the application of 'self'.
SILValue result = emitDynamicPartialApply(*this, e, memberArg, base,
cast<FunctionType>(methodTy));
// Emit the index.
llvm::SmallVector<SILValue, 1> indexArgs;
std::move(index).forwardAll(*this, indexArgs);
auto &valueTL = getTypeLowering(valueTy);
result = B.createApply(e, result, result.getType(),
valueTL.getLoweredType(), {}, indexArgs);
// Package up the result in an optional.
RValue resultRV =
RValue(*this, e, valueTy, emitManagedRValueWithCleanup(result, valueTL));
emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL);
// Branch to the continuation block.
B.createBranch(e, contBB);
}
// Create the no-member branch.
{
B.emitBlock(noMemberBB);
emitInjectOptionalNothingInto(e, optTemp, optTL);
// Branch to the continuation block.
B.createBranch(e, contBB);
}
// Emit the continuation block.
B.emitBlock(contBB);
// Package up the result.
auto optValue = B.createLoad(e, optTemp);
return RValue(*this, e, emitManagedRValueWithCleanup(optValue, optTL));
}