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:
Joe Groff
2016-03-17 10:42:52 -07:00
parent 09c98f7be8
commit c4a69e9d5d
12 changed files with 843 additions and 80 deletions

View File

@@ -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: