blob: 19b362bfaf43bcdd67cdf54d24fb2eaf034e4746 [file] [log] [blame]
//===--- Bridging.cpp - Bridging imported Clang types to Swift ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines routines relating to bridging Swift types to C types,
// working in concert with the Clang importer.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "libsil"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILModule.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/Module.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
using namespace swift;
using namespace swift::Lowering;
CanType TypeConverter::getLoweredTypeOfGlobal(VarDecl *var) {
AbstractionPattern origType = getAbstractionPattern(var);
assert(!origType.isTypeParameter());
return getLoweredRValueType(origType, origType.getType());
}
AnyFunctionType::Param
TypeConverter::getBridgedParam(SILFunctionTypeRepresentation rep,
AbstractionPattern pattern,
AnyFunctionType::Param param,
Bridgeability bridging) {
assert(!param.getParameterFlags().isInOut() &&
!param.getParameterFlags().isVariadic());
auto bridged = getLoweredBridgedType(pattern, param.getPlainType(), bridging,
rep, TypeConverter::ForArgument);
if (!bridged) {
Context.Diags.diagnose(SourceLoc(), diag::could_not_find_bridge_type,
param.getPlainType());
llvm::report_fatal_error("unable to set up the ObjC bridge!");
}
return AnyFunctionType::Param(bridged->getCanonicalType(),
param.getLabel(),
param.getParameterFlags());
}
void TypeConverter::
getBridgedParams(SILFunctionTypeRepresentation rep,
AbstractionPattern pattern,
ArrayRef<AnyFunctionType::Param> params,
SmallVectorImpl<AnyFunctionType::Param> &bridgedParams,
Bridgeability bridging) {
for (unsigned i : indices(params)) {
auto paramPattern = pattern.getFunctionParamType(i);
auto bridgedParam = getBridgedParam(rep, paramPattern, params[i], bridging);
bridgedParams.push_back(bridgedParam);
}
}
/// Bridge a result type.
CanType TypeConverter::getBridgedResultType(SILFunctionTypeRepresentation rep,
AbstractionPattern pattern,
CanType result,
Bridgeability bridging,
bool suppressOptional) {
auto loweredType =
getLoweredBridgedType(pattern, result, bridging, rep,
suppressOptional
? TypeConverter::ForNonOptionalResult
: TypeConverter::ForResult);
if (!loweredType) {
Context.Diags.diagnose(SourceLoc(), diag::could_not_find_bridge_type,
result);
llvm::report_fatal_error("unable to set up the ObjC bridge!");
}
return loweredType->getCanonicalType();
}
Type TypeConverter::getLoweredBridgedType(AbstractionPattern pattern,
Type t,
Bridgeability bridging,
SILFunctionTypeRepresentation rep,
BridgedTypePurpose purpose) {
switch (rep) {
case SILFunctionTypeRepresentation::Thick:
case SILFunctionTypeRepresentation::Thin:
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::WitnessMethod:
case SILFunctionTypeRepresentation::Closure:
// No bridging needed for native CCs.
return t;
case SILFunctionTypeRepresentation::CFunctionPointer:
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::Block:
// Map native types back to bridged types.
// Look through optional types.
if (auto valueTy = t->getOptionalObjectType()) {
pattern = pattern.getOptionalObjectType();
auto ty = getLoweredCBridgedType(pattern, valueTy, bridging, rep,
BridgedTypePurpose::ForNonOptionalResult);
return ty ? OptionalType::get(ty) : ty;
}
return getLoweredCBridgedType(pattern, t, bridging, rep, purpose);
}
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
};
Type TypeConverter::getLoweredCBridgedType(AbstractionPattern pattern,
Type t, Bridgeability bridging,
SILFunctionTypeRepresentation rep,
BridgedTypePurpose purpose) {
auto clangTy = pattern.isClangType() ? pattern.getClangType() : nullptr;
// Bridge Bool back to ObjC bool, unless the original Clang type was _Bool
// or the Darwin Boolean type.
auto nativeBoolTy = getBoolType();
if (nativeBoolTy && t->isEqual(nativeBoolTy)) {
// If we have a Clang type that was imported as Bool, it had better be
// one of a small set of types.
if (clangTy) {
auto builtinTy = clangTy->castAs<clang::BuiltinType>();
if (builtinTy->getKind() == clang::BuiltinType::Bool)
return t;
if (builtinTy->getKind() == clang::BuiltinType::UChar)
return getDarwinBooleanType();
assert(builtinTy->getKind() == clang::BuiltinType::SChar);
return getObjCBoolType();
}
// Otherwise, always assume ObjC methods should use ObjCBool.
if (bridging != Bridgeability::None &&
rep == SILFunctionTypeRepresentation::ObjCMethod)
return getObjCBoolType();
return t;
}
// Class metatypes bridge to ObjC metatypes.
if (auto metaTy = t->getAs<MetatypeType>()) {
if (metaTy->getInstanceType()->getClassOrBoundGenericClass()
// Self argument of an ObjC protocol
|| metaTy->getInstanceType()->is<GenericTypeParamType>()) {
return MetatypeType::get(metaTy->getInstanceType(),
MetatypeRepresentation::ObjC);
}
}
// ObjC-compatible existential metatypes.
if (auto metaTy = t->getAs<ExistentialMetatypeType>()) {
if (metaTy->getInstanceType()->isObjCExistentialType()) {
return ExistentialMetatypeType::get(metaTy->getInstanceType(),
MetatypeRepresentation::ObjC);
}
}
// `Any` can bridge to `AnyObject` (`id` in ObjC).
if (t->isAny())
return Context.getAnyObjectType();
if (auto funTy = t->getAs<FunctionType>()) {
switch (funTy->getExtInfo().getSILRepresentation()) {
// Functions that are already represented as blocks or C function pointers
// don't need bridging.
case SILFunctionType::Representation::Block:
case SILFunctionType::Representation::CFunctionPointer:
case SILFunctionType::Representation::Thin:
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::WitnessMethod:
case SILFunctionType::Representation::Closure:
return t;
case SILFunctionType::Representation::Thick: {
// Thick functions (TODO: conditionally) get bridged to blocks.
// This bridging is more powerful than usual block bridging, however,
// so we use the ObjCMethod representation.
SmallVector<AnyFunctionType::Param, 8> newParams;
getBridgedParams(SILFunctionType::Representation::ObjCMethod,
pattern, funTy->getParams(), newParams, bridging);
Type newResult =
getBridgedResultType(SILFunctionType::Representation::ObjCMethod,
pattern.getFunctionResultType(),
funTy->getResult()->getCanonicalType(),
bridging,
/*non-optional*/false);
return FunctionType::get(newParams, newResult,
funTy->getExtInfo().withSILRepresentation(
SILFunctionType::Representation::Block));
}
}
}
auto foreignRepresentation =
t->getForeignRepresentableIn(ForeignLanguage::ObjectiveC, M.TheSwiftModule);
switch (foreignRepresentation.first) {
case ForeignRepresentableKind::None:
case ForeignRepresentableKind::Trivial:
case ForeignRepresentableKind::Object:
return t;
case ForeignRepresentableKind::Bridged:
case ForeignRepresentableKind::StaticBridged: {
auto conformance = foreignRepresentation.second;
assert(conformance && "Missing conformance?");
Type bridgedTy =
ProtocolConformanceRef::getTypeWitnessByName(
t, ProtocolConformanceRef(conformance),
M.getASTContext().Id_ObjectiveCType,
nullptr);
assert(bridgedTy && "Missing _ObjectiveCType witness?");
if (purpose == BridgedTypePurpose::ForResult && clangTy)
bridgedTy = OptionalType::get(bridgedTy);
return bridgedTy;
}
case ForeignRepresentableKind::BridgedError: {
auto nsErrorDecl = M.getASTContext().getNSErrorDecl();
assert(nsErrorDecl && "Cannot bridge when NSError isn't available");
return nsErrorDecl->getDeclaredInterfaceType();
}
}
return t;
}