mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When the Clang importer imports the components of a C function pointer type, it generally translates foreign types into their native equivalents, just for the convenience of Swift code working with those functions. However, this translation must be unambiguously reversible, so (among other things) it cannot do this when the native type is also a valid foreign type. Specifically, this means that the Clang importer cannot import ObjCBool as Swift.Bool in these positions because Swift.Bool corresponds directly to the C type _Bool. SIL type lowering manually reverses the type-import process using a combination of duplicated logic and an abstraction pattern which includes information about the original Clang type that was imported. This abstraction pattern is generally able to tell SIL type lowering exactly what type to reverse to. However, @convention(c) function types may appear in positions from which it is impossible to recover the original Clang function type; therefore the reversal must be faithful to the proper rules. To do this we must propagate bridgeability just as the imported would. This reversal system is absolutely crazy, and we should really just - record an unbridged function type for imported declarations and - record an unbridged function type and Clang function type for @convention (c) function types whenever we create them. But for now, it's what we've got. rdar://43656704
243 lines
9.6 KiB
C++
243 lines
9.6 KiB
C++
//===--- 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;
|
|
|
|
|
|
SILType TypeConverter::getLoweredTypeOfGlobal(VarDecl *var) {
|
|
AbstractionPattern origType = getAbstractionPattern(var);
|
|
assert(!origType.isTypeParameter());
|
|
return getLoweredType(origType, origType.getType()).getObjectType();
|
|
}
|
|
|
|
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;
|
|
}
|