mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Similarly to how we've always handled parameter types, we now recursively expand tuples in result types and separately determine a result convention for each result. The most important code-generation change here is that indirect results are now returned separately from each other and from any direct results. It is generally far better, when receiving an indirect result, to receive it as an independent result; the caller is much more likely to be able to directly receive the result in the address they want to initialize, rather than having to receive it in temporary memory and then copy parts of it into the target. The most important conceptual change here that clients and producers of SIL must be aware of is the new distinction between a SILFunctionType's *parameters* and its *argument list*. The former is just the formal parameters, derived purely from the parameter types of the original function; indirect results are no longer in this list. The latter includes the indirect result arguments; as always, all the indirect results strictly precede the parameters. Apply instructions and entry block arguments follow the argument list, not the parameter list. A relatively minor change is that there can now be multiple direct results, each with its own result convention. This is a minor change because I've chosen to leave return instructions as taking a single operand and apply instructions as producing a single result; when the type describes multiple results, they are implicitly bound up in a tuple. It might make sense to split these up and allow e.g. return instructions to take a list of operands; however, it's not clear what to do on the caller side, and this would be a major change that can be separated out from this already over-large patch. Unsurprisingly, the most invasive changes here are in SILGen; this requires substantial reworking of both call emission and reabstraction. It also proved important to switch several SILGen operations over to work with RValue instead of ManagedValue, since otherwise they would be forced to spuriously "implode" buffers.
670 lines
25 KiB
C++
670 lines
25 KiB
C++
//===--- AbstractionPattern.cpp - Abstraction patterns --------------------===//
|
|
//
|
|
// 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 routines relating to abstraction patterns.
|
|
// working in concert with the Clang importer.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "libsil"
|
|
#include "swift/SIL/TypeLowering.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/Basic/Fallthrough.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/DeclObjC.h"
|
|
#include "clang/AST/PrettyPrinter.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::Lowering;
|
|
|
|
AbstractionPattern TypeConverter::getAbstractionPattern(AbstractStorageDecl *decl) {
|
|
if (auto var = dyn_cast<VarDecl>(decl)) {
|
|
return getAbstractionPattern(var);
|
|
} else {
|
|
return getAbstractionPattern(cast<SubscriptDecl>(decl));
|
|
}
|
|
}
|
|
|
|
AbstractionPattern TypeConverter::getAbstractionPattern(SubscriptDecl *decl) {
|
|
// TODO: honor the declared type?
|
|
// TODO: use interface types
|
|
return AbstractionPattern(decl->getElementType());
|
|
}
|
|
|
|
AbstractionPattern
|
|
TypeConverter::getIndicesAbstractionPattern(SubscriptDecl *decl) {
|
|
CanGenericSignature genericSig;
|
|
if (auto sig = decl->getGenericSignatureOfContext())
|
|
genericSig = sig->getCanonicalSignature();
|
|
return AbstractionPattern(genericSig,
|
|
decl->getIndicesInterfaceType()
|
|
->getCanonicalType());
|
|
}
|
|
|
|
static const clang::Type *getClangType(const clang::Decl *decl) {
|
|
if (auto valueDecl = dyn_cast<clang::ValueDecl>(decl)) {
|
|
return valueDecl->getType().getTypePtr();
|
|
}
|
|
|
|
// This should *really* be a ValueDecl.
|
|
return cast<clang::ObjCPropertyDecl>(decl)->getType().getTypePtr();
|
|
}
|
|
|
|
AbstractionPattern TypeConverter::getAbstractionPattern(VarDecl *var) {
|
|
CanType swiftType = var->getType()->getCanonicalType();
|
|
if (auto inout = dyn_cast<InOutType>(swiftType)) {
|
|
swiftType = inout.getObjectType();
|
|
}
|
|
|
|
if (auto clangDecl = var->getClangDecl()) {
|
|
auto clangType = getClangType(clangDecl);
|
|
swiftType = getLoweredBridgedType(AbstractionPattern(swiftType, clangType),
|
|
swiftType,
|
|
SILFunctionTypeRepresentation::CFunctionPointer,
|
|
TypeConverter::ForMemory)
|
|
->getCanonicalType();
|
|
return AbstractionPattern(swiftType, clangType);
|
|
} else {
|
|
return AbstractionPattern(swiftType);
|
|
}
|
|
}
|
|
|
|
AbstractionPattern TypeConverter::getAbstractionPattern(EnumElementDecl *decl) {
|
|
assert(decl->hasArgumentType());
|
|
assert(!decl->hasClangNode());
|
|
|
|
CanGenericSignature genericSig;
|
|
if (auto sig = decl->getParentEnum()->getGenericSignatureOfContext())
|
|
genericSig = sig->getCanonicalSignature();
|
|
return AbstractionPattern(genericSig,
|
|
decl->getArgumentInterfaceType()
|
|
->getCanonicalType());
|
|
}
|
|
|
|
AbstractionPattern::EncodedForeignErrorInfo
|
|
AbstractionPattern::EncodedForeignErrorInfo::encode(
|
|
const Optional<ForeignErrorConvention> &foreignError) {
|
|
EncodedForeignErrorInfo errorInfo;
|
|
if (foreignError.hasValue()) {
|
|
errorInfo =
|
|
EncodedForeignErrorInfo(foreignError->getErrorParameterIndex(),
|
|
foreignError->isErrorParameterReplacedWithVoid(),
|
|
foreignError->stripsResultOptionality());
|
|
}
|
|
return errorInfo;
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getObjCMethod(CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError) {
|
|
auto errorInfo = EncodedForeignErrorInfo::encode(foreignError);
|
|
return getObjCMethod(origType, method, errorInfo);
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getCurriedObjCMethod(CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError) {
|
|
auto errorInfo = EncodedForeignErrorInfo::encode(foreignError);
|
|
return getCurriedObjCMethod(origType, method, errorInfo);
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getOptional(AbstractionPattern object,
|
|
OptionalTypeKind optionalKind) {
|
|
switch (object.getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
llvm_unreachable("cannot add optionality to non-type abstraction");
|
|
case Kind::Opaque:
|
|
return AbstractionPattern::getOpaque();
|
|
case Kind::ClangType:
|
|
return AbstractionPattern(object.getGenericSignature(),
|
|
OptionalType::get(optionalKind, object.getType())
|
|
->getCanonicalType(),
|
|
object.getClangType());
|
|
case Kind::Type:
|
|
return AbstractionPattern(object.getGenericSignature(),
|
|
OptionalType::get(optionalKind, object.getType())
|
|
->getCanonicalType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool AbstractionPattern::matchesTuple(CanTupleType substType) {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
return false;
|
|
case Kind::Opaque:
|
|
return true;
|
|
case Kind::Tuple:
|
|
return getNumTupleElements_Stored() == substType->getNumElements();
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ClangType:
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return true;
|
|
auto tuple = dyn_cast<TupleType>(getType());
|
|
return (tuple && tuple->getNumElements() == substType->getNumElements());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
static const clang::FunctionType *
|
|
getClangFunctionType(const clang::Type *clangType) {
|
|
if (auto ptrTy = clangType->getAs<clang::PointerType>()) {
|
|
clangType = ptrTy->getPointeeType().getTypePtr();
|
|
} else if (auto blockTy = clangType->getAs<clang::BlockPointerType>()) {
|
|
clangType = blockTy->getPointeeType().getTypePtr();
|
|
}
|
|
return clangType->castAs<clang::FunctionType>();
|
|
}
|
|
|
|
static
|
|
const clang::Type *getClangFunctionParameterType(const clang::Type *ty,
|
|
unsigned index) {
|
|
// TODO: adjust for error type parameter.
|
|
|
|
// If we're asking about parameters, we'd better have a FunctionProtoType.
|
|
auto fnType = getClangFunctionType(ty)->castAs<clang::FunctionProtoType>();
|
|
assert(index < fnType->getNumParams());
|
|
return fnType->getParamType(index).getTypePtr();
|
|
}
|
|
|
|
static
|
|
const clang::Type *getClangArrayElementType(const clang::Type *ty,
|
|
unsigned index) {
|
|
return ty->castAsArrayTypeUnsafe()->getElementType().getTypePtr();
|
|
}
|
|
|
|
static bool isVoidLike(CanType type) {
|
|
return (type->isVoid() ||
|
|
(isa<TupleType>(type) &&
|
|
cast<TupleType>(type)->getNumElements() == 1 &&
|
|
cast<TupleType>(type).getElementType(0)->isVoid()));
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getTupleElementType(unsigned index) const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
llvm_unreachable("function types are not tuples");
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Tuple:
|
|
assert(index < getNumTupleElements_Stored());
|
|
return OrigTupleElements[index];
|
|
case Kind::ClangType:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
cast<TupleType>(getType()).getElementType(index),
|
|
getClangArrayElementType(getClangType(), index));
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignature(),
|
|
cast<TupleType>(getType()).getElementType(index));
|
|
case Kind::ClangFunctionParamTupleType:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
cast<TupleType>(getType()).getElementType(index),
|
|
getClangFunctionParameterType(getClangType(), index));
|
|
|
|
case Kind::ObjCMethodFormalParamTupleType: {
|
|
auto swiftEltType = cast<TupleType>(getType()).getElementType(index);
|
|
auto method = getObjCMethod();
|
|
auto errorInfo = getEncodedForeignErrorInfo();
|
|
|
|
// If we're asking for something after the error parameter, slide
|
|
// the parameter index up by one.
|
|
auto paramIndex = index;
|
|
if (errorInfo.hasErrorParameter()) {
|
|
auto errorParamIndex = errorInfo.getErrorParameterIndex();
|
|
if (errorInfo.isErrorParameterReplacedWithVoid()) {
|
|
if (paramIndex == errorParamIndex) {
|
|
assert(isVoidLike(swiftEltType));
|
|
(void) isVoidLike;
|
|
return AbstractionPattern(swiftEltType);
|
|
}
|
|
} else {
|
|
if (paramIndex >= errorParamIndex) {
|
|
paramIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return AbstractionPattern(getGenericSignature(), swiftEltType,
|
|
method->parameters()[paramIndex]->getType().getTypePtr());
|
|
}
|
|
case Kind::ObjCMethodParamTupleType: {
|
|
auto tupleType = cast<TupleType>(getType());
|
|
assert(tupleType->getNumElements() == 2);
|
|
assert(index < 2);
|
|
|
|
auto swiftEltType = tupleType.getElementType(index);
|
|
if (index != 0) {
|
|
return getObjCMethodSelfPattern(swiftEltType);
|
|
}
|
|
|
|
// Otherwise, we're talking about the formal parameter clause.
|
|
return getObjCMethodFormalParamPattern(swiftEltType);
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Return a pattern correspond to the 'self' parameter of the given
|
|
/// Objective-C method.
|
|
AbstractionPattern
|
|
AbstractionPattern::getObjCMethodSelfPattern(CanType selfType) const {
|
|
// Just use id 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 =
|
|
getObjCMethod()->getASTContext().getObjCIdType().getTypePtr();
|
|
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
selfType, clangSelfType);
|
|
}
|
|
|
|
/// Return a pattern correspond to the formal parameters of the
|
|
/// current Objective-C method.
|
|
AbstractionPattern
|
|
AbstractionPattern::getObjCMethodFormalParamPattern(CanType inputType) const {
|
|
auto signature = getGenericSignatureForFunctionComponent();
|
|
auto method = getObjCMethod();
|
|
auto errorInfo = getEncodedForeignErrorInfo();
|
|
|
|
// Nullary methods still take a formal () parameter clause.
|
|
// There's no corresponding Clang type for that.
|
|
if (method->parameters().empty() ||
|
|
(method->parameters().size() == 1 &&
|
|
errorInfo.hasErrorParameter())) {
|
|
// Imported initializers also sometimes get "withFooBar: ()" clauses.
|
|
assert(isVoidLike(inputType));
|
|
return AbstractionPattern(inputType);
|
|
}
|
|
|
|
// If we imported as a tuple type, construct the special
|
|
// method-formal-parameters abstraction pattern.
|
|
if (isa<TupleType>(inputType)) {
|
|
// This assertion gets messed up by variadic methods that we've
|
|
// imported as non-variadic.
|
|
assert(method->isVariadic() ||
|
|
method->parameters().size() ==
|
|
cast<TupleType>(inputType)->getNumElements()
|
|
+ unsigned(errorInfo.hasUnreplacedErrorParameter()));
|
|
return getObjCMethodFormalParamTuple(signature, inputType,
|
|
method, errorInfo);
|
|
}
|
|
|
|
// Otherwise, we must have imported a single parameter.
|
|
// But we might also have a foreign error.
|
|
|
|
// If we don't, we must have a single source parameter.
|
|
if (!errorInfo.hasErrorParameter()) {
|
|
assert(method->parameters().size() == 1);
|
|
return AbstractionPattern(signature, inputType,
|
|
method->parameters()[0]->getType().getTypePtr());
|
|
}
|
|
|
|
// Otherwise, we must have two; pick the one that isn't the foreign error.
|
|
assert(method->parameters().size() == 2);
|
|
unsigned errorIndex = errorInfo.getErrorParameterIndex();
|
|
assert(errorIndex < 2);
|
|
unsigned paramIndex = (errorIndex == 0 ? 1 : 0);
|
|
return AbstractionPattern(signature, inputType,
|
|
method->parameters()[paramIndex]->getType().getTypePtr());
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::transformType(
|
|
llvm::function_ref<CanType(CanType)> transform) const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple:
|
|
return *this;
|
|
case Kind::Opaque:
|
|
return getOpaque();
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
return getPartialCurriedObjCMethod(getGenericSignature(),
|
|
transform(getType()), getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
case Kind::CurriedObjCMethodType:
|
|
return getCurriedObjCMethod(transform(getType()), getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
case Kind::ObjCMethodType:
|
|
return getObjCMethod(transform(getType()), getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
case Kind::ClangType:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
transform(getType()), getClangType());
|
|
case Kind::Type:
|
|
return AbstractionPattern(getGenericSignature(), transform(getType()));
|
|
case Kind::ObjCMethodParamTupleType:
|
|
return getObjCMethodParamTuple(getGenericSignature(),
|
|
transform(getType()), getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
|
|
// In both of the following cases, if the transform makes it no
|
|
// longer a tuple type, we need to change kinds.
|
|
case Kind::ClangFunctionParamTupleType: {
|
|
auto newType = transform(getType());
|
|
if (isa<TupleType>(newType)) {
|
|
return getClangFunctionParamTuple(getGenericSignature(),
|
|
newType, getClangType());
|
|
} else {
|
|
assert(getNumTupleElements() == 1);
|
|
return AbstractionPattern(getGenericSignature(), newType,
|
|
getClangFunctionParameterType(getClangType(), 0));
|
|
}
|
|
}
|
|
case Kind::ObjCMethodFormalParamTupleType: {
|
|
auto newType = transform(getType());
|
|
if (isa<TupleType>(newType)) {
|
|
return getObjCMethodFormalParamTuple(getGenericSignature(),
|
|
newType, getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
} else {
|
|
assert(getNumTupleElements() == 1);
|
|
return AbstractionPattern(getGenericSignature(), newType,
|
|
getObjCMethod()->parameters()[0]->getType().getTypePtr());
|
|
}
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
static CanType dropLastElement(CanType type) {
|
|
auto elts = cast<TupleType>(type)->getElements().drop_back();
|
|
return TupleType::get(elts, type->getASTContext())->getCanonicalType();
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::dropLastTupleElement() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple: {
|
|
auto n = getNumTupleElements_Stored();
|
|
return getTuple(llvm::makeArrayRef(OrigTupleElements, n - 1));
|
|
}
|
|
case Kind::Opaque:
|
|
return getOpaque();
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
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:
|
|
llvm_unreachable("operation is not needed on method abstraction patterns");
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignature(),
|
|
dropLastElement(getType()));
|
|
|
|
// In both of the following cases, if the transform makes it no
|
|
// longer a tuple type, we need to change kinds.
|
|
case Kind::ClangFunctionParamTupleType: {
|
|
auto newType = dropLastElement(getType());
|
|
if (isa<TupleType>(newType)) {
|
|
return getClangFunctionParamTuple(getGenericSignature(),
|
|
newType, getClangType());
|
|
} else {
|
|
assert(getNumTupleElements() == 2);
|
|
return AbstractionPattern(getGenericSignature(), newType,
|
|
getClangFunctionParameterType(getClangType(), 0));
|
|
}
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getLValueObjectType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
llvm_unreachable("abstraction pattern for lvalue cannot be tuple");
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Type:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getType().getLValueOrInOutObjectType());
|
|
case Kind::ClangType:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getType().getLValueOrInOutObjectType(),
|
|
getClangType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
static CanType getResultType(CanType type) {
|
|
return cast<AnyFunctionType>(type).getResult();
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getFunctionResultType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::Tuple:
|
|
llvm_unreachable("abstraction pattern for tuple cannot be function");
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()));
|
|
case Kind::ClangType: {
|
|
auto clangFunctionType = getClangFunctionType(getClangType());
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
clangFunctionType->getReturnType().getTypePtr());
|
|
}
|
|
case Kind::CurriedObjCMethodType:
|
|
return getPartialCurriedObjCMethod(
|
|
getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getObjCMethod()->getReturnType().getTypePtr());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getFunctionInputType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::Tuple:
|
|
llvm_unreachable("abstraction pattern for tuple cannot be function");
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
cast<AnyFunctionType>(getType()).getInput());
|
|
case Kind::ClangType: {
|
|
// Preserve the Clang type in the resulting abstraction pattern.
|
|
auto inputType = cast<AnyFunctionType>(getType()).getInput();
|
|
if (isa<TupleType>(inputType)) {
|
|
return getClangFunctionParamTuple(
|
|
getGenericSignatureForFunctionComponent(),
|
|
inputType, getClangType());
|
|
} else {
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
inputType,
|
|
getClangFunctionParameterType(getClangType(), 0));
|
|
}
|
|
}
|
|
case Kind::CurriedObjCMethodType:
|
|
return getObjCMethodSelfPattern(
|
|
cast<AnyFunctionType>(getType()).getInput());
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
return getObjCMethodFormalParamPattern(
|
|
cast<AnyFunctionType>(getType()).getInput());
|
|
case Kind::ObjCMethodType: {
|
|
// Preserve the Clang type in the resulting abstraction pattern.
|
|
auto inputType = cast<AnyFunctionType>(getType()).getInput();
|
|
assert(isa<TupleType>(inputType)); // always at least ((), SelfType)
|
|
return getObjCMethodParamTuple(getGenericSignatureForFunctionComponent(),
|
|
inputType, getObjCMethod(),
|
|
getEncodedForeignErrorInfo());
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getAnyOptionalObjectType() const {
|
|
// Currently, the abstraction pattern corresponding to an optional object
|
|
// is always opaque. Eventually we'll allow optionals to carry abstraction.
|
|
return getOpaque();
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::Tuple:
|
|
return *this;
|
|
case Kind::Type:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getType().getReferenceStorageReferent());
|
|
case Kind::ClangType:
|
|
// This is not reflected in clang types.
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getType().getReferenceStorageReferent(),
|
|
getClangType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
void AbstractionPattern::dump() const {
|
|
print(llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
void AbstractionPattern::print(raw_ostream &out) const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
out << "AP::Invalid";
|
|
return;
|
|
case Kind::Opaque:
|
|
out << "AP::Opaque";
|
|
return;
|
|
case Kind::Type:
|
|
out << "AP::Type";
|
|
if (auto sig = getGenericSignature()) {
|
|
sig->print(out);
|
|
}
|
|
out << '(';
|
|
getType().dump(out);
|
|
out << ')';
|
|
return;
|
|
case Kind::Tuple:
|
|
out << "AP::Tuple(";
|
|
for (unsigned i = 0, e = getNumTupleElements(); i != e; ++i) {
|
|
if (i != 0) out << ", ";
|
|
getTupleElementType(i).print(out);
|
|
}
|
|
out << ")";
|
|
return;
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
out << (getKind() == Kind::ClangType ? "AP::ClangType("
|
|
: "AP::ClangFunctionParamTupleType(");
|
|
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();
|
|
out << ")";
|
|
return;
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodType:
|
|
out << (getKind() == Kind::ObjCMethodType
|
|
? "AP::ObjCMethodType(" :
|
|
getKind() == Kind::CurriedObjCMethodType
|
|
? "AP::CurriedObjCMethodType(" :
|
|
getKind() == Kind::PartialCurriedObjCMethodType
|
|
? "AP::PartialCurriedObjCMethodType(" :
|
|
getKind() == Kind::ObjCMethodParamTupleType
|
|
? "AP::ObjCMethodParamTupleType("
|
|
: "AP::ObjCMethodFormalParamTupleType(");
|
|
getType().dump(out);
|
|
auto errorInfo = getEncodedForeignErrorInfo();
|
|
if (errorInfo.hasValue()) {
|
|
if (errorInfo.hasErrorParameter())
|
|
out << ", errorParameter=" << errorInfo.getErrorParameterIndex();
|
|
if (errorInfo.isErrorParameterReplacedWithVoid())
|
|
out << ", replacedWithVoid";
|
|
if (errorInfo.stripsResultOptionality())
|
|
out << ", stripsResultOptionality";
|
|
}
|
|
out << ", ";
|
|
getObjCMethod()->dump(out);
|
|
out << ")";
|
|
return;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|