mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Using `#function` in a `defer` block should return the enclosing function name rather than the string `$defer()`. Fixes SR-819.
918 lines
37 KiB
C++
918 lines
37 KiB
C++
//===--- SILGenFunction.cpp - Top-level lowering for functions ------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the primary routines for creating and emitting
|
|
// functions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SILGenFunction.h"
|
|
#include "RValue.h"
|
|
#include "Scope.h"
|
|
#include "swift/Basic/Fallthrough.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/SIL/SILArgument.h"
|
|
#include "swift/SIL/SILUndef.h"
|
|
|
|
#include "swift/AST/DiagnosticsSIL.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILGenFunction Class implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F)
|
|
: SGM(SGM), F(F),
|
|
B(*this, createBasicBlock()),
|
|
CurrentSILLoc(F.getLocation()),
|
|
Cleanups(*this)
|
|
{
|
|
B.setCurrentDebugScope(F.getDebugScope());
|
|
}
|
|
|
|
/// SILGenFunction destructor - called after the entire function's AST has been
|
|
/// visited. This handles "falling off the end of the function" logic.
|
|
SILGenFunction::~SILGenFunction() {
|
|
// If the end of the function isn't terminated, we screwed up somewhere.
|
|
assert(!B.hasValidInsertionPoint() &&
|
|
"SILGenFunction did not terminate function?!");
|
|
|
|
// If we didn't clean up the rethrow destination, we screwed up somewhere.
|
|
assert(!ThrowDest.isValid() &&
|
|
"SILGenFunction did not emit throw destination");
|
|
|
|
freeWritebackStack();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Function emission
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Get the #function name for a declaration.
|
|
DeclName SILGenModule::getMagicFunctionName(DeclContext *dc) {
|
|
// For closures, use the parent name.
|
|
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
|
|
return getMagicFunctionName(closure->getParent());
|
|
}
|
|
if (auto absFunc = dyn_cast<AbstractFunctionDecl>(dc)) {
|
|
if (auto func = dyn_cast<FuncDecl>(absFunc)) {
|
|
// If this is an accessor, use the name of the storage.
|
|
if (auto storage = func->getAccessorStorageDecl()) {
|
|
return storage->getFullName();
|
|
}
|
|
// If this is a defer body, use the parent name.
|
|
if (func->isDeferBody()) {
|
|
return getMagicFunctionName(func->getParent());
|
|
}
|
|
}
|
|
|
|
return absFunc->getFullName();
|
|
}
|
|
if (auto init = dyn_cast<Initializer>(dc)) {
|
|
return getMagicFunctionName(init->getParent());
|
|
}
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {
|
|
return nominal->getName();
|
|
}
|
|
if (auto tl = dyn_cast<TopLevelCodeDecl>(dc)) {
|
|
return tl->getModuleContext()->getName();
|
|
}
|
|
if (auto fu = dyn_cast<FileUnit>(dc)) {
|
|
return fu->getParentModule()->getName();
|
|
}
|
|
if (auto m = dyn_cast<Module>(dc)) {
|
|
return m->getName();
|
|
}
|
|
if (auto e = dyn_cast<ExtensionDecl>(dc)) {
|
|
assert(e->getExtendedType()->getAnyNominal() && "extension for nonnominal");
|
|
return e->getExtendedType()->getAnyNominal()->getName();
|
|
}
|
|
llvm_unreachable("unexpected #function context");
|
|
}
|
|
|
|
DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
|
|
switch (ref.kind) {
|
|
case SILDeclRef::Kind::Func:
|
|
if (auto closure = ref.getAbstractClosureExpr())
|
|
return getMagicFunctionName(closure);
|
|
return getMagicFunctionName(cast<FuncDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::Initializer:
|
|
case SILDeclRef::Kind::Allocator:
|
|
return getMagicFunctionName(cast<ConstructorDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::Deallocator:
|
|
case SILDeclRef::Kind::Destroyer:
|
|
return getMagicFunctionName(cast<DestructorDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::GlobalAccessor:
|
|
case SILDeclRef::Kind::GlobalGetter:
|
|
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
|
|
case SILDeclRef::Kind::DefaultArgGenerator:
|
|
return getMagicFunctionName(cast<AbstractFunctionDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::IVarInitializer:
|
|
return getMagicFunctionName(cast<ClassDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::IVarDestroyer:
|
|
return getMagicFunctionName(cast<ClassDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::EnumElement:
|
|
return getMagicFunctionName(cast<EnumElementDecl>(ref.getDecl())
|
|
->getDeclContext());
|
|
}
|
|
}
|
|
|
|
SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc,
|
|
SILDeclRef constant,
|
|
SILConstantInfo constantInfo) {
|
|
assert(constantInfo == getConstantInfo(constant));
|
|
|
|
// Builtins must be fully applied at the point of reference.
|
|
if (constant.hasDecl() &&
|
|
isa<BuiltinUnit>(constant.getDecl()->getDeclContext())) {
|
|
SGM.diagnose(loc.getSourceLoc(), diag::not_implemented,
|
|
"delayed application of builtin");
|
|
return SILUndef::get(constantInfo.getSILType(), SGM.M);
|
|
}
|
|
|
|
// If the constant is a thunk we haven't emitted yet, emit it.
|
|
if (!SGM.hasFunction(constant)) {
|
|
if (constant.isCurried) {
|
|
auto vd = constant.getDecl();
|
|
// Reference the next uncurrying level of the function.
|
|
SILDeclRef next = SILDeclRef(vd, constant.kind,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
constant.uncurryLevel + 1);
|
|
// If the function is fully uncurried and natively foreign, reference its
|
|
// foreign entry point.
|
|
if (!next.isCurried) {
|
|
if (requiresForeignToNativeThunk(vd))
|
|
next = next.asForeign();
|
|
}
|
|
|
|
// Preserve whether the curry thunks lead to a direct reference to the
|
|
// method implementation.
|
|
next = next.asDirectReference(constant.isDirectReference);
|
|
|
|
SGM.emitCurryThunk(vd, constant, next);
|
|
}
|
|
// Otherwise, if this is a calling convention thunk we haven't emitted yet,
|
|
// emit it.
|
|
else if (constant.isForeignToNativeThunk()) {
|
|
SGM.emitForeignToNativeThunk(constant);
|
|
} else if (constant.isNativeToForeignThunk()) {
|
|
SGM.emitNativeToForeignThunk(constant);
|
|
} else if (constant.kind == SILDeclRef::Kind::EnumElement) {
|
|
SGM.emitEnumConstructor(cast<EnumElementDecl>(constant.getDecl()));
|
|
}
|
|
}
|
|
|
|
auto f = SGM.getFunction(constant, NotForDefinition);
|
|
assert(f->getLoweredFunctionType() == constantInfo.SILFnType);
|
|
return B.createFunctionRef(loc, f);
|
|
}
|
|
|
|
std::tuple<ManagedValue, SILType, ArrayRef<Substitution>>
|
|
SILGenFunction::emitSiblingMethodRef(SILLocation loc,
|
|
SILValue selfValue,
|
|
SILDeclRef methodConstant,
|
|
ArrayRef<Substitution> subs) {
|
|
SILValue methodValue;
|
|
|
|
// If the method is dynamic, access it through runtime-hookable virtual
|
|
// dispatch (viz. objc_msgSend for now).
|
|
if (methodConstant.hasDecl()
|
|
&& methodConstant.getDecl()->getAttrs().hasAttribute<DynamicAttr>())
|
|
methodValue = emitDynamicMethodRef(loc, methodConstant,
|
|
SGM.Types.getConstantInfo(methodConstant));
|
|
else
|
|
methodValue = emitGlobalFunctionRef(loc, methodConstant);
|
|
|
|
SILType methodTy = methodValue->getType();
|
|
|
|
if (!subs.empty()) {
|
|
// Specialize the generic method.
|
|
methodTy = getLoweredLoadableType(
|
|
methodTy.castTo<SILFunctionType>()
|
|
->substGenericArgs(SGM.M, SGM.SwiftModule, subs));
|
|
}
|
|
|
|
return std::make_tuple(ManagedValue::forUnmanaged(methodValue),
|
|
methodTy, subs);
|
|
}
|
|
|
|
ManagedValue SILGenFunction::emitFunctionRef(SILLocation loc,
|
|
SILDeclRef constant,
|
|
SILConstantInfo constantInfo) {
|
|
// If the function has captures, apply them.
|
|
if (auto fn = constant.getAnyFunctionRef()) {
|
|
if (fn->getCaptureInfo().hasLocalCaptures() ||
|
|
fn->getCaptureInfo().hasGenericParamCaptures()) {
|
|
return emitClosureValue(loc, constant, *fn);
|
|
}
|
|
}
|
|
|
|
// Otherwise, use a global FunctionRefInst.
|
|
SILValue c = emitGlobalFunctionRef(loc, constant, constantInfo);
|
|
return ManagedValue::forUnmanaged(c);
|
|
}
|
|
|
|
void SILGenFunction::emitCaptures(SILLocation loc,
|
|
AnyFunctionRef TheClosure,
|
|
CaptureEmission purpose,
|
|
SmallVectorImpl<ManagedValue> &capturedArgs) {
|
|
auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure);
|
|
// For boxed captures, we need to mark the contained variables as having
|
|
// escaped for DI diagnostics.
|
|
SmallVector<SILValue, 2> escapesToMark;
|
|
|
|
// Partial applications take ownership of the context parameters, so we'll
|
|
// need to pass ownership rather than merely guaranteeing parameters.
|
|
bool canGuarantee;
|
|
switch (purpose) {
|
|
case CaptureEmission::PartialApplication:
|
|
canGuarantee = false;
|
|
break;
|
|
case CaptureEmission::ImmediateApplication:
|
|
canGuarantee = true;
|
|
break;
|
|
}
|
|
// TODO: Or we always retain them when guaranteed contexts aren't enabled.
|
|
if (!SGM.M.getOptions().EnableGuaranteedClosureContexts)
|
|
canGuarantee = false;
|
|
|
|
for (auto capture : captureInfo.getCaptures()) {
|
|
auto *vd = capture.getDecl();
|
|
|
|
switch (SGM.Types.getDeclCaptureKind(capture)) {
|
|
case CaptureKind::None:
|
|
break;
|
|
|
|
case CaptureKind::Constant: {
|
|
// let declarations.
|
|
auto Entry = VarLocs[vd];
|
|
|
|
auto &tl = getTypeLowering(vd->getType()->getReferenceStorageReferent());
|
|
SILValue Val = Entry.value;
|
|
|
|
if (!Val->getType().isAddress()) {
|
|
// Our 'let' binding can guarantee the lifetime for the callee,
|
|
// if we don't need to do anything more to it.
|
|
if (canGuarantee && !vd->getType()->is<ReferenceStorageType>()) {
|
|
auto guaranteed = ManagedValue::forUnmanaged(Val);
|
|
capturedArgs.push_back(guaranteed);
|
|
break;
|
|
}
|
|
|
|
// Just retain a by-val let.
|
|
B.emitRetainValueOperation(loc, Val);
|
|
} else {
|
|
// If we have a mutable binding for a 'let', such as 'self' in an
|
|
// 'init' method, load it.
|
|
Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this);
|
|
}
|
|
|
|
// If we're capturing an unowned pointer by value, we will have just
|
|
// loaded it into a normal retained class pointer, but we capture it as
|
|
// an unowned pointer. Convert back now.
|
|
if (vd->getType()->is<ReferenceStorageType>()) {
|
|
auto type = getTypeLowering(vd->getType()).getLoweredType();
|
|
Val = emitConversionFromSemanticValue(loc, Val, type);
|
|
}
|
|
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(Val));
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::StorageAddress: {
|
|
// No-escaping stored declarations are captured as the
|
|
// address of the value.
|
|
assert(VarLocs.count(vd) && "no location for captured var!");
|
|
VarLoc vl = VarLocs[vd];
|
|
assert(vl.value->getType().isAddress() && "no address for captured var!");
|
|
capturedArgs.push_back(ManagedValue::forLValue(vl.value));
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::Box: {
|
|
// LValues are captured as both the box owning the value and the
|
|
// address of the value.
|
|
assert(VarLocs.count(vd) && "no location for captured var!");
|
|
VarLoc vl = VarLocs[vd];
|
|
assert(vl.value->getType().isAddress() && "no address for captured var!");
|
|
|
|
// If this is a boxed variable, we can use it directly.
|
|
if (vl.box) {
|
|
// We can guarantee our own box to the callee.
|
|
if (canGuarantee) {
|
|
capturedArgs.push_back(ManagedValue::forUnmanaged(vl.box));
|
|
} else {
|
|
B.createStrongRetain(loc, vl.box);
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(vl.box));
|
|
}
|
|
escapesToMark.push_back(vl.value);
|
|
} else {
|
|
// Address only 'let' values are passed by box. This isn't great, in
|
|
// that a variable captured by multiple closures will be boxed for each
|
|
// one. This could be improved by doing an "isCaptured" analysis when
|
|
// emitting address-only let constants, and emit them into an alloc_box
|
|
// like a variable instead of into an alloc_stack.
|
|
//
|
|
// TODO: This might not be profitable anymore with guaranteed captures,
|
|
// since we could conceivably forward the copied value into the
|
|
// closure context and pass it down to the partially applied function
|
|
// in-place.
|
|
AllocBoxInst *allocBox =
|
|
B.createAllocBox(loc, vl.value->getType().getObjectType());
|
|
ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox);
|
|
B.createCopyAddr(loc, vl.value, boxAddress, IsNotTake,IsInitialization);
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mark box addresses as captured for DI purposes. The values must have
|
|
// been fully initialized before we close over them.
|
|
if (!escapesToMark.empty()) {
|
|
B.createMarkFunctionEscape(loc, escapesToMark);
|
|
}
|
|
}
|
|
|
|
ManagedValue
|
|
SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
|
|
AnyFunctionRef TheClosure) {
|
|
assert(((constant.uncurryLevel == 1 &&
|
|
TheClosure.getCaptureInfo().hasLocalCaptures()) ||
|
|
(constant.uncurryLevel == 0 &&
|
|
!TheClosure.getCaptureInfo().hasLocalCaptures())) &&
|
|
"curried local functions not yet supported");
|
|
|
|
auto constantInfo = getConstantInfo(constant);
|
|
SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo);
|
|
SILType functionTy = functionRef->getType();
|
|
|
|
auto expectedType =
|
|
cast<FunctionType>(TheClosure.getType()->getCanonicalType());
|
|
|
|
// Forward substitutions from the outer scope.
|
|
|
|
auto pft = constantInfo.SILFnType;
|
|
|
|
auto forwardSubs = constantInfo.getForwardingSubstitutions(getASTContext());
|
|
|
|
bool wasSpecialized = false;
|
|
if (pft->isPolymorphic() && !forwardSubs.empty()) {
|
|
auto specialized = pft->substGenericArgs(F.getModule(),
|
|
F.getModule().getSwiftModule(),
|
|
forwardSubs);
|
|
functionTy = SILType::getPrimitiveObjectType(specialized);
|
|
wasSpecialized = true;
|
|
}
|
|
|
|
if (!TheClosure.getCaptureInfo().hasLocalCaptures() && !wasSpecialized) {
|
|
auto result = ManagedValue::forUnmanaged(functionRef);
|
|
return emitOrigToSubstValue(loc, result,
|
|
AbstractionPattern(expectedType),
|
|
expectedType);
|
|
}
|
|
|
|
SmallVector<ManagedValue, 4> capturedArgs;
|
|
emitCaptures(loc, TheClosure, CaptureEmission::PartialApplication,
|
|
capturedArgs);
|
|
|
|
// The partial application takes ownership of the context parameters.
|
|
SmallVector<SILValue, 4> forwardedArgs;
|
|
for (auto capture : capturedArgs)
|
|
forwardedArgs.push_back(capture.forward(*this));
|
|
|
|
SILType closureTy =
|
|
SILGenBuilder::getPartialApplyResultType(functionRef->getType(),
|
|
capturedArgs.size(), SGM.M,
|
|
forwardSubs);
|
|
auto toClosure =
|
|
B.createPartialApply(loc, functionRef, functionTy,
|
|
forwardSubs, forwardedArgs, closureTy);
|
|
auto result = emitManagedRValueWithCleanup(toClosure);
|
|
|
|
return emitOrigToSubstValue(loc, result,
|
|
AbstractionPattern(expectedType),
|
|
expectedType);
|
|
}
|
|
|
|
void SILGenFunction::emitFunction(FuncDecl *fd) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(fd);
|
|
|
|
Type resultTy = fd->getResultType();
|
|
emitProlog(fd, fd->getParameterLists(), resultTy);
|
|
prepareEpilog(resultTy, fd->isBodyThrowing(), CleanupLocation(fd));
|
|
|
|
emitProfilerIncrement(fd->getBody());
|
|
emitStmt(fd->getBody());
|
|
|
|
emitEpilog(fd);
|
|
}
|
|
|
|
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(ace);
|
|
|
|
emitProlog(ace, ace->getParameters(), ace->getResultType());
|
|
prepareEpilog(ace->getResultType(), ace->isBodyThrowing(),
|
|
CleanupLocation(ace));
|
|
if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
|
|
emitProfilerIncrement(ce);
|
|
emitStmt(ce->getBody());
|
|
} else {
|
|
auto *autoclosure = cast<AutoClosureExpr>(ace);
|
|
// Closure expressions implicitly return the result of their body
|
|
// expression.
|
|
emitProfilerIncrement(autoclosure);
|
|
emitReturnExpr(ImplicitReturnLocation(ace),
|
|
autoclosure->getSingleExpressionBody());
|
|
}
|
|
emitEpilog(ace);
|
|
}
|
|
|
|
void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) {
|
|
// Load argc and argv from the entry point arguments.
|
|
SILValue argc = F.begin()->getBBArg(0);
|
|
SILValue argv = F.begin()->getBBArg(1);
|
|
|
|
switch (mainClass->getArtificialMainKind()) {
|
|
case ArtificialMainKind::UIApplicationMain: {
|
|
// Emit a UIKit main.
|
|
// return UIApplicationMain(C_ARGC, C_ARGV, nil, ClassName);
|
|
|
|
CanType NSStringTy = SGM.Types.getNSStringType();
|
|
CanType OptNSStringTy
|
|
= OptionalType::get(NSStringTy)->getCanonicalType();
|
|
CanType IUOptNSStringTy
|
|
= ImplicitlyUnwrappedOptionalType::get(NSStringTy)->getCanonicalType();
|
|
|
|
// Get the class name as a string using NSStringFromClass.
|
|
CanType mainClassTy = mainClass->getDeclaredTypeInContext()->getCanonicalType();
|
|
CanType mainClassMetaty = CanMetatypeType::get(mainClassTy,
|
|
MetatypeRepresentation::ObjC);
|
|
ProtocolDecl *anyObjectProtocol =
|
|
getASTContext().getProtocol(KnownProtocolKind::AnyObject);
|
|
auto mainClassAnyObjectConformance = ProtocolConformanceRef(
|
|
SGM.M.getSwiftModule()->lookupConformance(mainClassTy, anyObjectProtocol,
|
|
nullptr)
|
|
.getPointer());
|
|
CanType anyObjectTy = anyObjectProtocol
|
|
->getDeclaredTypeInContext()
|
|
->getCanonicalType();
|
|
CanType anyObjectMetaTy = CanExistentialMetatypeType::get(anyObjectTy,
|
|
MetatypeRepresentation::ObjC);
|
|
|
|
auto NSStringFromClassType = SILFunctionType::get(nullptr,
|
|
SILFunctionType::ExtInfo()
|
|
.withRepresentation(SILFunctionType::Representation::
|
|
CFunctionPointer),
|
|
ParameterConvention::Direct_Unowned,
|
|
SILParameterInfo(anyObjectMetaTy,
|
|
ParameterConvention::Direct_Unowned),
|
|
SILResultInfo(OptNSStringTy,
|
|
ResultConvention::Autoreleased),
|
|
/*error result*/ None,
|
|
getASTContext());
|
|
auto NSStringFromClassFn
|
|
= SGM.M.getOrCreateFunction(mainClass, "NSStringFromClass",
|
|
SILLinkage::PublicExternal,
|
|
NSStringFromClassType,
|
|
IsBare, IsTransparent, IsNotFragile);
|
|
auto NSStringFromClass = B.createFunctionRef(mainClass, NSStringFromClassFn);
|
|
SILValue metaTy = B.createMetatype(mainClass,
|
|
SILType::getPrimitiveObjectType(mainClassMetaty));
|
|
metaTy = B.createInitExistentialMetatype(mainClass, metaTy,
|
|
SILType::getPrimitiveObjectType(anyObjectMetaTy),
|
|
getASTContext().AllocateCopy(
|
|
llvm::makeArrayRef(mainClassAnyObjectConformance)));
|
|
SILValue optName = B.createApply(mainClass,
|
|
NSStringFromClass,
|
|
NSStringFromClass->getType(),
|
|
SILType::getPrimitiveObjectType(OptNSStringTy),
|
|
{}, metaTy);
|
|
SILValue iuoptName = B.createUncheckedBitCast(mainClass, optName,
|
|
SILType::getPrimitiveObjectType(IUOptNSStringTy));
|
|
|
|
// Call UIApplicationMain.
|
|
SILParameterInfo argTypes[] = {
|
|
SILParameterInfo(argc->getType().getSwiftRValueType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(argv->getType().getSwiftRValueType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(IUOptNSStringTy, ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(IUOptNSStringTy, ParameterConvention::Direct_Unowned),
|
|
};
|
|
auto UIApplicationMainType = SILFunctionType::get(nullptr,
|
|
SILFunctionType::ExtInfo()
|
|
.withRepresentation(SILFunctionType::Representation::
|
|
CFunctionPointer),
|
|
ParameterConvention::Direct_Unowned,
|
|
argTypes,
|
|
SILResultInfo(argc->getType().getSwiftRValueType(),
|
|
ResultConvention::Unowned),
|
|
/*error result*/ None,
|
|
getASTContext());
|
|
|
|
auto UIApplicationMainFn
|
|
= SGM.M.getOrCreateFunction(mainClass, "UIApplicationMain",
|
|
SILLinkage::PublicExternal,
|
|
UIApplicationMainType,
|
|
IsBare, IsTransparent, IsNotFragile);
|
|
|
|
auto UIApplicationMain = B.createFunctionRef(mainClass, UIApplicationMainFn);
|
|
auto nil = B.createEnum(mainClass, SILValue(),
|
|
getASTContext().getImplicitlyUnwrappedOptionalNoneDecl(),
|
|
SILType::getPrimitiveObjectType(IUOptNSStringTy));
|
|
|
|
SILValue args[] = { argc, argv, nil, iuoptName };
|
|
|
|
B.createApply(mainClass, UIApplicationMain,
|
|
UIApplicationMain->getType(),
|
|
argc->getType(), {}, args);
|
|
SILValue r = B.createIntegerLiteral(mainClass,
|
|
SILType::getBuiltinIntegerType(32, getASTContext()), 0);
|
|
auto rType = F.getLoweredFunctionType()->getSingleResult().getSILType();
|
|
if (r->getType() != rType)
|
|
r = B.createStruct(mainClass, rType, r);
|
|
|
|
B.createReturn(mainClass, r);
|
|
return;
|
|
}
|
|
|
|
case ArtificialMainKind::NSApplicationMain: {
|
|
// Emit an AppKit main.
|
|
// return NSApplicationMain(C_ARGC, C_ARGV);
|
|
|
|
SILParameterInfo argTypes[] = {
|
|
SILParameterInfo(argc->getType().getSwiftRValueType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(argv->getType().getSwiftRValueType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
};
|
|
auto NSApplicationMainType = SILFunctionType::get(nullptr,
|
|
SILFunctionType::ExtInfo()
|
|
// Should be C calling convention, but NSApplicationMain
|
|
// has an overlay to fix the type of argv.
|
|
.withRepresentation(SILFunctionType::Representation::Thin),
|
|
ParameterConvention::Direct_Unowned,
|
|
argTypes,
|
|
SILResultInfo(argc->getType().getSwiftRValueType(),
|
|
ResultConvention::Unowned),
|
|
/*error result*/ None,
|
|
getASTContext());
|
|
|
|
auto NSApplicationMainFn
|
|
= SGM.M.getOrCreateFunction(mainClass, "NSApplicationMain",
|
|
SILLinkage::PublicExternal,
|
|
NSApplicationMainType,
|
|
IsBare, IsTransparent, IsNotFragile);
|
|
|
|
auto NSApplicationMain = B.createFunctionRef(mainClass, NSApplicationMainFn);
|
|
SILValue args[] = { argc, argv };
|
|
|
|
B.createApply(mainClass, NSApplicationMain,
|
|
NSApplicationMain->getType(),
|
|
argc->getType(), {}, args);
|
|
SILValue r = B.createIntegerLiteral(mainClass,
|
|
SILType::getBuiltinIntegerType(32, getASTContext()), 0);
|
|
auto rType = F.getLoweredFunctionType()->getSingleResult().getSILType();
|
|
if (r->getType() != rType)
|
|
r = B.createStruct(mainClass, rType, r);
|
|
B.createReturn(mainClass, r);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void forwardCaptureArgs(SILGenFunction &gen,
|
|
SmallVectorImpl<SILValue> &args,
|
|
CapturedValue capture) {
|
|
auto addSILArgument = [&](SILType t, ValueDecl *d) {
|
|
args.push_back(new (gen.SGM.M) SILArgument(gen.F.begin(), t, d));
|
|
};
|
|
|
|
auto *vd = capture.getDecl();
|
|
|
|
switch (gen.SGM.Types.getDeclCaptureKind(capture)) {
|
|
case CaptureKind::None:
|
|
break;
|
|
|
|
case CaptureKind::Constant:
|
|
addSILArgument(gen.getLoweredType(vd->getType()), vd);
|
|
break;
|
|
|
|
case CaptureKind::Box: {
|
|
SILType ty = gen.getLoweredType(vd->getType()->getRValueType())
|
|
.getAddressType();
|
|
// Forward the captured owning box.
|
|
SILType boxTy = SILType::getPrimitiveObjectType(
|
|
SILBoxType::get(ty.getSwiftRValueType()));
|
|
addSILArgument(boxTy, vd);
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::StorageAddress: {
|
|
SILType ty = gen.getLoweredType(vd->getType()->getRValueType())
|
|
.getAddressType();
|
|
// Forward the captured value address.
|
|
addSILArgument(ty, vd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static SILValue getNextUncurryLevelRef(SILGenFunction &gen,
|
|
SILLocation loc,
|
|
SILDeclRef next,
|
|
bool direct,
|
|
ArrayRef<SILValue> curriedArgs,
|
|
ArrayRef<Substitution> curriedSubs) {
|
|
if (next.isForeign || next.isCurried || !next.hasDecl() || direct)
|
|
return gen.emitGlobalFunctionRef(loc, next.asForeign(false));
|
|
|
|
auto constantInfo = gen.SGM.Types.getConstantInfo(next);
|
|
SILValue thisArg;
|
|
if (!curriedArgs.empty())
|
|
thisArg = curriedArgs.back();
|
|
|
|
if (isa<AbstractFunctionDecl>(next.getDecl()) &&
|
|
getMethodDispatch(cast<AbstractFunctionDecl>(next.getDecl()))
|
|
== MethodDispatch::Class) {
|
|
SILValue thisArg = curriedArgs.back();
|
|
|
|
// Use the dynamic thunk if dynamic.
|
|
if (next.getDecl()->isDynamic()) {
|
|
auto dynamicThunk = gen.SGM.getDynamicThunk(next, constantInfo);
|
|
return gen.B.createFunctionRef(loc, dynamicThunk);
|
|
}
|
|
|
|
return gen.B.createClassMethod(loc, thisArg, next);
|
|
}
|
|
|
|
// If the fully-uncurried reference is to a generic method, look up the
|
|
// witness.
|
|
if (constantInfo.SILFnType->getRepresentation()
|
|
== SILFunctionTypeRepresentation::WitnessMethod) {
|
|
auto thisType = curriedSubs[0].getReplacement()->getCanonicalType();
|
|
assert(isa<ArchetypeType>(thisType) && "no archetype for witness?!");
|
|
SILValue OpenedExistential;
|
|
if (!cast<ArchetypeType>(thisType)->getOpenedExistentialType().isNull())
|
|
OpenedExistential = thisArg;
|
|
auto protocol =
|
|
next.getDecl()->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
|
|
auto conformance = ProtocolConformanceRef(protocol);
|
|
return gen.B.createWitnessMethod(loc, thisType, conformance, next,
|
|
constantInfo.getSILType(),
|
|
OpenedExistential);
|
|
}
|
|
|
|
// Otherwise, emit a direct call.
|
|
return gen.emitGlobalFunctionRef(loc, next);
|
|
}
|
|
|
|
void SILGenFunction::emitCurryThunk(ValueDecl *vd,
|
|
SILDeclRef from, SILDeclRef to) {
|
|
SmallVector<SILValue, 8> curriedArgs;
|
|
|
|
unsigned paramCount = from.uncurryLevel + 1;
|
|
|
|
if (isa<ConstructorDecl>(vd) || isa<EnumElementDecl>(vd)) {
|
|
// The first body parameter pattern for a constructor specifies the
|
|
// "self" instance, but the constructor is invoked from outside on a
|
|
// metatype.
|
|
assert(from.uncurryLevel == 0 && to.uncurryLevel == 1
|
|
&& "currying constructor at level other than one?!");
|
|
F.setBare(IsBare);
|
|
auto selfMetaTy = vd->getType()->getAs<AnyFunctionType>()->getInput();
|
|
auto metatypeVal = new (F.getModule()) SILArgument(F.begin(),
|
|
getLoweredLoadableType(selfMetaTy));
|
|
curriedArgs.push_back(metatypeVal);
|
|
|
|
} else if (auto fd = dyn_cast<AbstractFunctionDecl>(vd)) {
|
|
// Forward implicit closure context arguments.
|
|
bool hasCaptures = fd->getCaptureInfo().hasLocalCaptures();
|
|
if (hasCaptures)
|
|
--paramCount;
|
|
|
|
// Forward the curried formal arguments.
|
|
auto forwardedPatterns = fd->getParameterLists().slice(0, paramCount);
|
|
for (auto *paramPattern : reversed(forwardedPatterns))
|
|
bindParametersForForwarding(paramPattern, curriedArgs);
|
|
|
|
// Forward captures.
|
|
if (hasCaptures) {
|
|
auto captureInfo = SGM.Types.getLoweredLocalCaptures(fd);
|
|
for (auto capture : captureInfo.getCaptures())
|
|
forwardCaptureArgs(*this, curriedArgs, capture);
|
|
}
|
|
} else {
|
|
llvm_unreachable("don't know how to curry this decl");
|
|
}
|
|
|
|
// Forward substitutions.
|
|
ArrayRef<Substitution> subs;
|
|
if (auto gp = getConstantInfo(to).ContextGenericParams) {
|
|
subs = gp->getForwardingSubstitutions(getASTContext());
|
|
}
|
|
|
|
SILValue toFn = getNextUncurryLevelRef(*this, vd, to, from.isDirectReference,
|
|
curriedArgs, subs);
|
|
SILType resultTy
|
|
= SGM.getConstantType(from).castTo<SILFunctionType>()
|
|
->getSingleResult().getSILType();
|
|
resultTy = F.mapTypeIntoContext(resultTy);
|
|
auto toTy = toFn->getType();
|
|
|
|
// Forward archetypes and specialize if the function is generic.
|
|
if (!subs.empty()) {
|
|
auto toFnTy = toFn->getType().castTo<SILFunctionType>();
|
|
toTy = getLoweredLoadableType(
|
|
toFnTy->substGenericArgs(SGM.M, SGM.SwiftModule, subs));
|
|
}
|
|
|
|
// Partially apply the next uncurry level and return the result closure.
|
|
auto closureTy =
|
|
SILGenBuilder::getPartialApplyResultType(toFn->getType(), curriedArgs.size(),
|
|
SGM.M, subs);
|
|
SILInstruction *toClosure =
|
|
B.createPartialApply(vd, toFn, toTy, subs, curriedArgs, closureTy);
|
|
if (resultTy != closureTy)
|
|
toClosure = B.createConvertFunction(vd, toClosure, resultTy);
|
|
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(vd), toClosure);
|
|
}
|
|
|
|
void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(function);
|
|
|
|
RegularLocation Loc(value);
|
|
Loc.markAutoGenerated();
|
|
|
|
// Override location for #file, #line etc. to an invalid one so that we
|
|
// don't put extra strings into the default argument generator function that
|
|
// is not going to be ever used anyway.
|
|
overrideLocationForMagicIdentifiers = SourceLoc();
|
|
|
|
emitProlog({ }, value->getType(), function.getDecl()->getDeclContext());
|
|
prepareEpilog(value->getType(), false, CleanupLocation::get(Loc));
|
|
emitReturnExpr(Loc, value);
|
|
emitEpilog(Loc);
|
|
}
|
|
|
|
SILGenBuilder::SILGenBuilder(SILGenFunction &gen)
|
|
: SILBuilder(gen.F), SGM(gen.SGM) {}
|
|
SILGenBuilder::SILGenBuilder(SILGenFunction &gen, SILBasicBlock *insertBB)
|
|
: SILBuilder(insertBB), SGM(gen.SGM) {}
|
|
SILGenBuilder::SILGenBuilder(SILGenFunction &gen, SILBasicBlock *insertBB,
|
|
SmallVectorImpl<SILInstruction *> *insertedInsts)
|
|
: SILBuilder(insertBB, insertedInsts), SGM(gen.SGM) {}
|
|
SILGenBuilder::SILGenBuilder(SILGenFunction &gen, SILBasicBlock *insertBB,
|
|
SILInstruction *insertInst)
|
|
: SILBuilder(insertBB, insertInst->getIterator()), SGM(gen.SGM) {}
|
|
|
|
MetatypeInst *SILGenBuilder::createMetatype(SILLocation loc, SILType metatype) {
|
|
auto theMetatype = metatype.castTo<MetatypeType>();
|
|
// Getting a nontrivial metatype requires forcing any conformances necessary
|
|
// to instantiate the type.
|
|
switch (theMetatype->getRepresentation()) {
|
|
case MetatypeRepresentation::Thin:
|
|
break;
|
|
case MetatypeRepresentation::Thick:
|
|
case MetatypeRepresentation::ObjC: {
|
|
// Walk the type recursively to look for substitutions we may need.
|
|
SmallVector<Substitution, 2> subsBuf;
|
|
theMetatype.getInstanceType().findIf([&](Type t) -> bool {
|
|
if (!t->getAnyNominal())
|
|
return false;
|
|
|
|
auto subs = t->gatherAllSubstitutions(SGM.SwiftModule, subsBuf, nullptr);
|
|
SGM.useConformancesFromSubstitutions(subs);
|
|
return false;
|
|
});
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return SILBuilder::createMetatype(loc, metatype);
|
|
}
|
|
|
|
ApplyInst *SILGenBuilder::createApply(SILLocation Loc, SILValue Fn,
|
|
SILType SubstFnTy,
|
|
SILType Result,
|
|
ArrayRef<Substitution> Subs,
|
|
ArrayRef<SILValue> Args) {
|
|
SGM.useConformancesFromSubstitutions(Subs);
|
|
return SILBuilder::createApply(Loc, Fn, SubstFnTy, Result, Subs, Args, false);
|
|
}
|
|
|
|
TryApplyInst *SILGenBuilder::createTryApply(SILLocation loc, SILValue Fn,
|
|
SILType substFnTy,
|
|
ArrayRef<Substitution> subs,
|
|
ArrayRef<SILValue> args,
|
|
SILBasicBlock *normalBB,
|
|
SILBasicBlock *errorBB) {
|
|
SGM.useConformancesFromSubstitutions(subs);
|
|
return SILBuilder::createTryApply(loc, Fn, substFnTy, subs, args, normalBB,
|
|
errorBB);
|
|
}
|
|
|
|
PartialApplyInst *SILGenBuilder::createPartialApply(SILLocation Loc,
|
|
SILValue Fn,
|
|
SILType SubstFnTy,
|
|
ArrayRef<Substitution> Subs,
|
|
ArrayRef<SILValue> Args,
|
|
SILType ClosureTy) {
|
|
SGM.useConformancesFromSubstitutions(Subs);
|
|
return SILBuilder::createPartialApply(Loc, Fn, SubstFnTy, Subs, Args,
|
|
ClosureTy);
|
|
}
|
|
|
|
BuiltinInst *SILGenBuilder::createBuiltin(SILLocation Loc, Identifier Name,
|
|
SILType ResultTy,
|
|
ArrayRef<Substitution> Subs,
|
|
ArrayRef<SILValue> Args) {
|
|
SGM.useConformancesFromSubstitutions(Subs);
|
|
return SILBuilder::createBuiltin(Loc, Name, ResultTy, Subs, Args);
|
|
}
|
|
|
|
InitExistentialAddrInst *
|
|
SILGenBuilder::createInitExistentialAddr(SILLocation Loc,
|
|
SILValue Existential,
|
|
CanType FormalConcreteType,
|
|
SILType LoweredConcreteType,
|
|
ArrayRef<ProtocolConformanceRef> Conformances) {
|
|
for (auto conformance : Conformances)
|
|
SGM.useConformance(conformance);
|
|
|
|
return SILBuilder::createInitExistentialAddr(Loc, Existential,
|
|
FormalConcreteType,
|
|
LoweredConcreteType,
|
|
Conformances);
|
|
}
|
|
|
|
InitExistentialMetatypeInst *
|
|
SILGenBuilder::createInitExistentialMetatype(SILLocation loc,
|
|
SILValue metatype,
|
|
SILType existentialType,
|
|
ArrayRef<ProtocolConformanceRef> conformances) {
|
|
for (auto conformance : conformances)
|
|
SGM.useConformance(conformance);
|
|
|
|
return SILBuilder::createInitExistentialMetatype(loc, metatype,
|
|
existentialType,
|
|
conformances);
|
|
}
|
|
|
|
InitExistentialRefInst *
|
|
SILGenBuilder::createInitExistentialRef(SILLocation Loc,
|
|
SILType ExistentialType,
|
|
CanType FormalConcreteType,
|
|
SILValue Concrete,
|
|
ArrayRef<ProtocolConformanceRef> Conformances) {
|
|
for (auto conformance : Conformances)
|
|
SGM.useConformance(conformance);
|
|
|
|
return SILBuilder::createInitExistentialRef(Loc, ExistentialType,
|
|
FormalConcreteType, Concrete,
|
|
Conformances);
|
|
}
|
|
|
|
AllocExistentialBoxInst *
|
|
SILGenBuilder::createAllocExistentialBox(SILLocation Loc,
|
|
SILType ExistentialType,
|
|
CanType ConcreteType,
|
|
ArrayRef<ProtocolConformanceRef> Conformances) {
|
|
for (auto conformance : Conformances)
|
|
SGM.useConformance(conformance);
|
|
|
|
return SILBuilder::createAllocExistentialBox(Loc, ExistentialType,
|
|
ConcreteType,
|
|
Conformances);
|
|
}
|
|
|
|
void SILGenFunction::checkForImportedUsedConformances(Type type) {
|
|
// Recognize _BridgedNSError, which must pull in its witness table for
|
|
// dynamic casts to work
|
|
if (auto bridgedNSErrorProtocol =
|
|
getASTContext().getProtocol(KnownProtocolKind::BridgedNSError)) {
|
|
if (auto nominalDecl = type->getAnyNominal()) {
|
|
SmallVector<ProtocolConformance *, 4> conformances;
|
|
if (nominalDecl->lookupConformance(
|
|
SGM.SwiftModule, bridgedNSErrorProtocol, conformances)) {
|
|
SGM.useConformance(ProtocolConformanceRef(conformances.front()));
|
|
}
|
|
}
|
|
}
|
|
}
|