mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SILGen: Basic code generation for C functions imported as methods.
Introduce abstraction patterns for curried C-functions-as-methods for type lowering, and plumb the "foreign self parameter index" through call emission so that we emit the "self" parameter in the right position. This gets us handling C functions imported as methods with explicit swift_name attributes in simple, fully-applied cases. There's still more work to be done for properties, partial applications, and initializers introduced by extensions.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "swift/AST/ForeignErrorConvention.h"
|
||||
#include "swift/Basic/Fallthrough.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
@@ -122,6 +123,15 @@ AbstractionPattern::getCurriedObjCMethod(CanType origType,
|
||||
return getCurriedObjCMethod(origType, method, errorInfo);
|
||||
}
|
||||
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getCurriedCFunctionAsMethod(CanType origType,
|
||||
const AbstractFunctionDecl *function) {
|
||||
auto clangFn = cast<clang::ValueDecl>(function->getClangDecl());
|
||||
return getCurriedCFunctionAsMethod(origType,
|
||||
clangFn->getType().getTypePtr(),
|
||||
*function->getForeignFunctionAsMethodSelfParameterIndex());
|
||||
}
|
||||
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getOptional(AbstractionPattern object,
|
||||
OptionalTypeKind optionalKind) {
|
||||
@@ -131,9 +141,12 @@ AbstractionPattern::getOptional(AbstractionPattern object,
|
||||
case Kind::Tuple:
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
llvm_unreachable("cannot add optionality to non-type abstraction");
|
||||
case Kind::Opaque:
|
||||
@@ -147,6 +160,10 @@ AbstractionPattern::getOptional(AbstractionPattern object,
|
||||
return AbstractionPattern(object.getGenericSignature(),
|
||||
OptionalType::get(optionalKind, object.getType())
|
||||
->getCanonicalType());
|
||||
case Kind::Discard:
|
||||
return AbstractionPattern::getDiscard(object.getGenericSignature(),
|
||||
OptionalType::get(optionalKind, object.getType())
|
||||
->getCanonicalType());
|
||||
}
|
||||
llvm_unreachable("bad kind");
|
||||
}
|
||||
@@ -157,6 +174,8 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) {
|
||||
llvm_unreachable("querying invalid abstraction pattern!");
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
return false;
|
||||
case Kind::Opaque:
|
||||
@@ -165,9 +184,11 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) {
|
||||
return getNumTupleElements_Stored() == substType->getNumElements();
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
case Kind::ClangType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard:
|
||||
if (isTypeParameter())
|
||||
return true;
|
||||
auto tuple = dyn_cast<TupleType>(getType());
|
||||
@@ -217,6 +238,8 @@ AbstractionPattern::getTupleElementType(unsigned index) const {
|
||||
llvm_unreachable("querying invalid abstraction pattern!");
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
llvm_unreachable("function types are not tuples");
|
||||
case Kind::Opaque:
|
||||
@@ -228,6 +251,8 @@ AbstractionPattern::getTupleElementType(unsigned index) const {
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
cast<TupleType>(getType()).getElementType(index),
|
||||
getClangArrayElementType(getClangType(), index));
|
||||
case Kind::Discard:
|
||||
llvm_unreachable("operation not needed on discarded abstractions yet");
|
||||
case Kind::Type:
|
||||
if (isTypeParameter())
|
||||
return AbstractionPattern::getOpaque();
|
||||
@@ -264,6 +289,16 @@ AbstractionPattern::getTupleElementType(unsigned index) const {
|
||||
return AbstractionPattern(getGenericSignature(), swiftEltType,
|
||||
method->parameters()[paramIndex]->getType().getTypePtr());
|
||||
}
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType: {
|
||||
// Jump over the self parameter in the Clang type.
|
||||
unsigned clangIndex = index;
|
||||
int selfIndex = getCFunctionAsMethodSelfIndex();
|
||||
if (selfIndex >= 0 && clangIndex >= (unsigned)selfIndex)
|
||||
++clangIndex;
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
cast<TupleType>(getType()).getElementType(index),
|
||||
getClangFunctionParameterType(getClangType(), clangIndex));
|
||||
}
|
||||
case Kind::ObjCMethodParamTupleType: {
|
||||
auto tupleType = cast<TupleType>(getType());
|
||||
assert(tupleType->getNumElements() == 2);
|
||||
@@ -281,7 +316,7 @@ AbstractionPattern::getTupleElementType(unsigned index) const {
|
||||
llvm_unreachable("bad kind");
|
||||
}
|
||||
|
||||
/// Return a pattern correspond to the 'self' parameter of the given
|
||||
/// Return a pattern corresponding to the 'self' parameter of the given
|
||||
/// Objective-C method.
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getObjCMethodSelfPattern(CanType selfType) const {
|
||||
@@ -295,7 +330,58 @@ AbstractionPattern::getObjCMethodSelfPattern(CanType selfType) const {
|
||||
selfType, clangSelfType);
|
||||
}
|
||||
|
||||
/// Return a pattern correspond to the formal parameters of the
|
||||
/// Return a pattern corresponding to the 'self' parameter of the given
|
||||
/// C function imported as a method.
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getCFunctionAsMethodSelfPattern(CanType selfType) const {
|
||||
int selfIndex = getCFunctionAsMethodSelfIndex();
|
||||
if (selfIndex >= 0) {
|
||||
// Use the clang type for the receiver type. If this is ever
|
||||
// insufficient --- if we have interesting bridging to do to
|
||||
// 'self' --- we have the right information to be more exact.
|
||||
auto clangSelfType =
|
||||
getClangFunctionParameterType(getClangType(), selfIndex);
|
||||
|
||||
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
||||
selfType, clangSelfType);
|
||||
}
|
||||
// The formal metatype parameter to a C function imported as a static method
|
||||
// is dropped on the floor. Leave it untransformed.
|
||||
return AbstractionPattern::getDiscard(
|
||||
getGenericSignatureForFunctionComponent(), selfType);
|
||||
}
|
||||
|
||||
/// Return a pattern corresponding to the formal method parameters of
|
||||
/// the current C function imported as a method.
|
||||
AbstractionPattern AbstractionPattern::
|
||||
getCFunctionAsMethodFormalParamPattern(CanType paramType) const {
|
||||
auto sig = getGenericSignatureForFunctionComponent();
|
||||
auto clangType = getClangType();
|
||||
|
||||
// Nullary methods still take a formal () parameter clause.
|
||||
// There's no corresponding Clang type for that.
|
||||
if (isVoidLike(paramType))
|
||||
return AbstractionPattern(paramType);
|
||||
|
||||
// If we imported as a tuple type, construct the special
|
||||
// method-formal-parameters abstraction pattern.
|
||||
if (isa<TupleType>(paramType)) {
|
||||
return getCFunctionAsMethodFormalParamTuple(sig, paramType,
|
||||
clangType, OtherData);
|
||||
}
|
||||
|
||||
// Otherwise, we imported a single parameter.
|
||||
// Get the non-self parameter from the Clang type.
|
||||
unsigned paramIndex = 0;
|
||||
int selfIndex = getCFunctionAsMethodSelfIndex();
|
||||
if (selfIndex == 0)
|
||||
paramIndex = 1;
|
||||
|
||||
return AbstractionPattern(sig, paramType,
|
||||
getClangFunctionParameterType(clangType, paramIndex));
|
||||
}
|
||||
|
||||
/// Return a pattern corresponding to the formal parameters of the
|
||||
/// current Objective-C method.
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getObjCMethodFormalParamPattern(CanType inputType) const {
|
||||
@@ -361,6 +447,13 @@ AbstractionPattern AbstractionPattern::transformType(
|
||||
case Kind::CurriedObjCMethodType:
|
||||
return getCurriedObjCMethod(transform(getType()), getObjCMethod(),
|
||||
getEncodedForeignErrorInfo());
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
return getPartialCurriedCFunctionAsMethod(getGenericSignature(),
|
||||
transform(getType()),
|
||||
getClangType(), OtherData);
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
return getCurriedCFunctionAsMethod(transform(getType()), getClangType(),
|
||||
OtherData);
|
||||
case Kind::ObjCMethodType:
|
||||
return getObjCMethod(transform(getType()), getObjCMethod(),
|
||||
getEncodedForeignErrorInfo());
|
||||
@@ -369,6 +462,9 @@ AbstractionPattern AbstractionPattern::transformType(
|
||||
transform(getType()), getClangType());
|
||||
case Kind::Type:
|
||||
return AbstractionPattern(getGenericSignature(), transform(getType()));
|
||||
case Kind::Discard:
|
||||
return AbstractionPattern::getDiscard(getGenericSignature(),
|
||||
transform(getType()));
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
return getObjCMethodParamTuple(getGenericSignature(),
|
||||
transform(getType()), getObjCMethod(),
|
||||
@@ -399,6 +495,14 @@ AbstractionPattern AbstractionPattern::transformType(
|
||||
getObjCMethod()->parameters()[0]->getType().getTypePtr());
|
||||
}
|
||||
}
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType: {
|
||||
auto newType = transform(getType());
|
||||
if (isa<TupleType>(newType)) {
|
||||
return getCFunctionAsMethodFormalParamTuple(getGenericSignature(),
|
||||
newType, getClangType(),
|
||||
OtherData);
|
||||
}
|
||||
}
|
||||
}
|
||||
llvm_unreachable("bad kind");
|
||||
}
|
||||
@@ -420,19 +524,24 @@ AbstractionPattern AbstractionPattern::dropLastTupleElement() const {
|
||||
return getOpaque();
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
llvm_unreachable("not a tuple type");
|
||||
case Kind::ClangType:
|
||||
llvm_unreachable("dropping last element of imported array?");
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
llvm_unreachable("operation is not needed on method abstraction patterns");
|
||||
case Kind::Type:
|
||||
if (isTypeParameter())
|
||||
return AbstractionPattern::getOpaque();
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
dropLastElement(getType()));
|
||||
|
||||
case Kind::Discard:
|
||||
llvm_unreachable("don't need to drop element on discarded abstractions "
|
||||
"yet");
|
||||
// In both of the following cases, if the transform makes it no
|
||||
// longer a tuple type, we need to change kinds.
|
||||
case Kind::ClangFunctionParamTupleType: {
|
||||
@@ -458,15 +567,21 @@ AbstractionPattern AbstractionPattern::getLValueObjectType() const {
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
llvm_unreachable("abstraction pattern for lvalue cannot be tuple");
|
||||
case Kind::Opaque:
|
||||
return *this;
|
||||
case Kind::Type:
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
getType().getLValueOrInOutObjectType());
|
||||
case Kind::Discard:
|
||||
return AbstractionPattern::getDiscard(getGenericSignature(),
|
||||
getType().getLValueOrInOutObjectType());
|
||||
case Kind::ClangType:
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
getType().getLValueOrInOutObjectType(),
|
||||
@@ -486,6 +601,7 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
case Kind::Tuple:
|
||||
llvm_unreachable("abstraction pattern for tuple cannot be function");
|
||||
case Kind::Opaque:
|
||||
@@ -495,7 +611,10 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
|
||||
return AbstractionPattern::getOpaque();
|
||||
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
||||
getResultType(getType()));
|
||||
case Kind::ClangType: {
|
||||
case Kind::Discard:
|
||||
llvm_unreachable("don't need to discard function abstractions yet");
|
||||
case Kind::ClangType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType: {
|
||||
auto clangFunctionType = getClangFunctionType(getClangType());
|
||||
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
||||
getResultType(getType()),
|
||||
@@ -507,6 +626,12 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
|
||||
getResultType(getType()),
|
||||
getObjCMethod(),
|
||||
getEncodedForeignErrorInfo());
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
return getPartialCurriedCFunctionAsMethod(
|
||||
getGenericSignatureForFunctionComponent(),
|
||||
getResultType(getType()),
|
||||
getClangType(),
|
||||
OtherData);
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::ObjCMethodType:
|
||||
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
||||
@@ -523,6 +648,7 @@ AbstractionPattern AbstractionPattern::getFunctionInputType() const {
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
case Kind::ObjCMethodParamTupleType:
|
||||
case Kind::ObjCMethodFormalParamTupleType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
case Kind::Tuple:
|
||||
llvm_unreachable("abstraction pattern for tuple cannot be function");
|
||||
case Kind::Opaque:
|
||||
@@ -532,6 +658,8 @@ AbstractionPattern AbstractionPattern::getFunctionInputType() const {
|
||||
return AbstractionPattern::getOpaque();
|
||||
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
||||
cast<AnyFunctionType>(getType()).getInput());
|
||||
case Kind::Discard:
|
||||
llvm_unreachable("don't need to discard function abstractions yet");
|
||||
case Kind::ClangType: {
|
||||
// Preserve the Clang type in the resulting abstraction pattern.
|
||||
auto inputType = cast<AnyFunctionType>(getType()).getInput();
|
||||
@@ -545,6 +673,12 @@ AbstractionPattern AbstractionPattern::getFunctionInputType() const {
|
||||
getClangFunctionParameterType(getClangType(), 0));
|
||||
}
|
||||
}
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
return getCFunctionAsMethodSelfPattern(
|
||||
cast<AnyFunctionType>(getType()).getInput());
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
return getCFunctionAsMethodFormalParamPattern(
|
||||
cast<AnyFunctionType>(getType()).getInput());
|
||||
case Kind::CurriedObjCMethodType:
|
||||
return getObjCMethodSelfPattern(
|
||||
cast<AnyFunctionType>(getType()).getInput());
|
||||
@@ -580,11 +714,17 @@ AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const {
|
||||
case Kind::ObjCMethodType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::PartialCurriedObjCMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::Tuple:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
return *this;
|
||||
case Kind::Type:
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
getType().getReferenceStorageReferent());
|
||||
case Kind::Discard:
|
||||
return AbstractionPattern::getDiscard(getGenericSignature(),
|
||||
getType().getReferenceStorageReferent());
|
||||
case Kind::ClangType:
|
||||
// This is not reflected in clang types.
|
||||
return AbstractionPattern(getGenericSignature(),
|
||||
@@ -608,7 +748,11 @@ void AbstractionPattern::print(raw_ostream &out) const {
|
||||
out << "AP::Opaque";
|
||||
return;
|
||||
case Kind::Type:
|
||||
out << "AP::Type";
|
||||
case Kind::Discard:
|
||||
out << (getKind() == Kind::Type
|
||||
? "AP::Type" :
|
||||
getKind() == Kind::Discard
|
||||
? "AP::Discard" : "<<UNHANDLED CASE>>");
|
||||
if (auto sig = getGenericSignature()) {
|
||||
sig->print(out);
|
||||
}
|
||||
@@ -626,13 +770,28 @@ void AbstractionPattern::print(raw_ostream &out) const {
|
||||
return;
|
||||
case Kind::ClangType:
|
||||
case Kind::ClangFunctionParamTupleType:
|
||||
out << (getKind() == Kind::ClangType ? "AP::ClangType("
|
||||
: "AP::ClangFunctionParamTupleType(");
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CFunctionAsMethodFormalParamTupleType:
|
||||
out << (getKind() == Kind::ClangType
|
||||
? "AP::ClangType(" :
|
||||
getKind() == Kind::ClangFunctionParamTupleType
|
||||
? "AP::ClangFunctionParamTupleType(" :
|
||||
getKind() == Kind::CurriedCFunctionAsMethodType
|
||||
? "AP::CurriedCFunctionAsMethodType(" :
|
||||
getKind() == Kind::PartialCurriedCFunctionAsMethodType
|
||||
? "AP::PartialCurriedCFunctionAsMethodType(" :
|
||||
getKind() == Kind::CFunctionAsMethodFormalParamTupleType
|
||||
? "AP::CFunctionAsMethodFormalParamTupleType("
|
||||
: "<<UNHANDLED CASE>>(");
|
||||
getType().dump(out);
|
||||
out << ", ";
|
||||
// It would be better to use print, but we need a PrintingPolicy
|
||||
// for that, for which we need a clang LangOptions, and... ugh.
|
||||
clang::QualType(getClangType(), 0).dump();
|
||||
if (hasCFunctionAsMethodSelfIndex()) {
|
||||
out << ", selfIndex=" << getCFunctionAsMethodSelfIndex();
|
||||
}
|
||||
out << ")";
|
||||
return;
|
||||
case Kind::CurriedObjCMethodType:
|
||||
|
||||
Reference in New Issue
Block a user