mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
An ObjC API maybe imported as async that had multiple non-error arguments to its completion handler, which we treat in Swift as returning a tuple. Use a new form of abstraction pattern to represent this return type, to maintain the correct relation between individual tuple elements and the Clang block parameter types they map to.
1170 lines
44 KiB
C++
1170 lines
44 KiB
C++
//===--- AbstractionPattern.cpp - Abstraction patterns --------------------===//
|
|
//
|
|
// 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 abstraction patterns.
|
|
// working in concert with the Clang importer.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "libsil"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/ForeignAsyncConvention.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/GenericSignature.h"
|
|
#include "swift/AST/ModuleLoader.h"
|
|
#include "swift/SIL/TypeLowering.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/AST/DeclCXX.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,
|
|
bool isNonObjC) {
|
|
if (auto var = dyn_cast<VarDecl>(decl)) {
|
|
return getAbstractionPattern(var, isNonObjC);
|
|
} else {
|
|
return getAbstractionPattern(cast<SubscriptDecl>(decl), isNonObjC);
|
|
}
|
|
}
|
|
|
|
AbstractionPattern
|
|
TypeConverter::getAbstractionPattern(SubscriptDecl *decl, bool isNonObjC) {
|
|
auto type = decl->getElementInterfaceType()->getCanonicalType();
|
|
CanGenericSignature genericSig;
|
|
if (auto sig = decl->getGenericSignatureOfContext()) {
|
|
genericSig = sig.getCanonicalSignature();
|
|
type = sig->getCanonicalTypeInContext(type);
|
|
}
|
|
return AbstractionPattern(genericSig, type);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
static Bridgeability getClangDeclBridgeability(const clang::Decl *decl) {
|
|
// These declarations are always imported without bridging (for now).
|
|
if (isa<clang::VarDecl>(decl) ||
|
|
isa<clang::FieldDecl>(decl) ||
|
|
isa<clang::IndirectFieldDecl>(decl))
|
|
return Bridgeability::None;
|
|
|
|
// Functions and methods always use normal bridging.
|
|
return Bridgeability::Full;
|
|
}
|
|
|
|
AbstractionPattern
|
|
TypeConverter::getAbstractionPattern(VarDecl *var, bool isNonObjC) {
|
|
CanType swiftType = var->getInterfaceType()
|
|
->getCanonicalType();
|
|
|
|
CanGenericSignature genericSig;
|
|
if (auto sig = var->getDeclContext()->getGenericSignatureOfContext()) {
|
|
genericSig = sig.getCanonicalSignature();
|
|
swiftType = genericSig->getCanonicalTypeInContext(swiftType);
|
|
}
|
|
|
|
if (isNonObjC)
|
|
return AbstractionPattern(genericSig, swiftType);
|
|
|
|
if (auto clangDecl = var->getClangDecl()) {
|
|
auto clangType = getClangType(clangDecl);
|
|
auto contextType = var->getDeclContext()->mapTypeIntoContext(swiftType);
|
|
swiftType = getLoweredBridgedType(
|
|
AbstractionPattern(genericSig, swiftType, clangType),
|
|
contextType, getClangDeclBridgeability(clangDecl),
|
|
SILFunctionTypeRepresentation::CFunctionPointer,
|
|
TypeConverter::ForMemory)->getCanonicalType();
|
|
return AbstractionPattern(genericSig, swiftType, clangType);
|
|
}
|
|
|
|
return AbstractionPattern(genericSig, swiftType);
|
|
}
|
|
|
|
AbstractionPattern TypeConverter::getAbstractionPattern(EnumElementDecl *decl) {
|
|
assert(decl->hasAssociatedValues());
|
|
assert(!decl->hasClangNode());
|
|
|
|
// This cannot be implemented correctly for Optional.Some.
|
|
assert(!decl->getParentEnum()->isOptionalDecl() &&
|
|
"Optional.Some does not have a unique abstraction pattern because "
|
|
"optionals are re-abstracted");
|
|
|
|
CanType type = decl->getArgumentInterfaceType()->getCanonicalType();
|
|
|
|
CanGenericSignature genericSig;
|
|
if (auto sig = decl->getParentEnum()->getGenericSignatureOfContext()) {
|
|
genericSig = sig.getCanonicalSignature();
|
|
type = genericSig->getCanonicalTypeInContext(type);
|
|
}
|
|
|
|
return AbstractionPattern(genericSig, type);
|
|
}
|
|
|
|
AbstractionPattern::EncodedForeignInfo
|
|
AbstractionPattern::EncodedForeignInfo::encode(
|
|
const Optional<ForeignErrorConvention> &foreignError,
|
|
const Optional<ForeignAsyncConvention> &foreignAsync) {
|
|
// Foreign async convention takes precedence.
|
|
if (foreignAsync.hasValue()) {
|
|
return EncodedForeignInfo(EncodedForeignInfo::Async,
|
|
foreignAsync->completionHandlerParamIndex(),
|
|
foreignAsync->completionHandlerErrorParamIndex());
|
|
} else if (foreignError.hasValue()) {
|
|
return EncodedForeignInfo(EncodedForeignInfo::Error,
|
|
foreignError->getErrorParameterIndex(),
|
|
foreignError->isErrorParameterReplacedWithVoid(),
|
|
foreignError->stripsResultOptionality());
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getObjCMethod(CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError,
|
|
const Optional<ForeignAsyncConvention> &foreignAsync) {
|
|
auto errorInfo = EncodedForeignInfo::encode(foreignError, foreignAsync);
|
|
return getObjCMethod(origType, method, errorInfo);
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getCurriedObjCMethod(CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError,
|
|
const Optional<ForeignAsyncConvention> &foreignAsync) {
|
|
auto errorInfo = EncodedForeignInfo::encode(foreignError, foreignAsync);
|
|
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->getImportAsMemberStatus());
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getCurriedCXXMethod(CanType origType,
|
|
const AbstractFunctionDecl *function) {
|
|
auto clangMethod = cast<clang::CXXMethodDecl>(function->getClangDecl());
|
|
return getCurriedCXXMethod(origType, clangMethod);
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getCurriedCXXOperatorMethod(
|
|
CanType origType, const AbstractFunctionDecl *function) {
|
|
auto clangMethod = cast<clang::CXXMethodDecl>(function->getClangDecl());
|
|
return getCurriedCXXOperatorMethod(origType, clangMethod);
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getOptional(AbstractionPattern object) {
|
|
switch (object.getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
llvm_unreachable("cannot add optionality to non-type abstraction");
|
|
case Kind::Opaque:
|
|
return AbstractionPattern::getOpaque();
|
|
case Kind::ClangType:
|
|
return AbstractionPattern(object.getGenericSignature(),
|
|
OptionalType::get(object.getType())
|
|
->getCanonicalType(),
|
|
object.getClangType());
|
|
case Kind::Type:
|
|
return AbstractionPattern(object.getGenericSignature(),
|
|
OptionalType::get(object.getType())
|
|
->getCanonicalType());
|
|
case Kind::Discard:
|
|
return AbstractionPattern::getDiscard(object.getGenericSignature(),
|
|
OptionalType::get(object.getType())
|
|
->getCanonicalType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool AbstractionPattern::isConcreteType() const {
|
|
assert(isTypeParameter());
|
|
return (getKind() != Kind::Opaque &&
|
|
GenericSig != nullptr &&
|
|
GenericSig->isConcreteType(getType()));
|
|
}
|
|
|
|
bool AbstractionPattern::requiresClass() const {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return false;
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
case Kind::ClangType: {
|
|
auto type = getType();
|
|
if (auto archetype = dyn_cast<ArchetypeType>(type))
|
|
return archetype->requiresClass();
|
|
if (type->isTypeParameter()) {
|
|
if (getKind() == Kind::ClangType) {
|
|
// ObjC generics are always class constrained.
|
|
return true;
|
|
}
|
|
|
|
assert(GenericSig &&
|
|
"Dependent type in pattern without generic signature?");
|
|
return GenericSig->requiresClass(type);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return LayoutConstraint();
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
case Kind::ClangType: {
|
|
auto type = getType();
|
|
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
|
|
return archetype->getLayoutConstraint();
|
|
} else if (isa<DependentMemberType>(type) ||
|
|
isa<GenericTypeParamType>(type)) {
|
|
if (getKind() == Kind::ClangType) {
|
|
// ObjC generics are always class constrained.
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::Class);
|
|
}
|
|
|
|
assert(GenericSig &&
|
|
"Dependent type in pattern without generic signature?");
|
|
return GenericSig->getLayoutConstraint(type);
|
|
}
|
|
return LayoutConstraint();
|
|
}
|
|
default:
|
|
return LayoutConstraint();
|
|
}
|
|
}
|
|
|
|
bool AbstractionPattern::matchesTuple(CanTupleType substType) {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
return false;
|
|
case Kind::Opaque:
|
|
return true;
|
|
case Kind::Tuple:
|
|
return getNumTupleElements_Stored() == substType->getNumElements();
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
case Kind::ClangType:
|
|
case Kind::Type:
|
|
case Kind::Discard: {
|
|
if (isTypeParameter())
|
|
return true;
|
|
auto type = getType();
|
|
if (auto tuple = dyn_cast<TupleType>(type))
|
|
return (tuple->getNumElements() == substType->getNumElements());
|
|
if (isa<OpaqueTypeArchetypeType>(type))
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
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();
|
|
} else if (auto refTy = clangType->getAs<clang::ReferenceType>()) {
|
|
clangType = refTy->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 CanType getCanTupleElementType(CanType type, unsigned index) {
|
|
if (auto tupleTy = dyn_cast<TupleType>(type))
|
|
return tupleTy.getElementType(index);
|
|
|
|
assert(index == 0);
|
|
return type;
|
|
}
|
|
|
|
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::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
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(),
|
|
getCanTupleElementType(getType(), index),
|
|
getClangArrayElementType(getClangType(), index));
|
|
case Kind::Discard:
|
|
llvm_unreachable("operation not needed on discarded abstractions yet");
|
|
case Kind::Type:
|
|
if (isTypeParameterOrOpaqueArchetype())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getCanTupleElementType(getType(), index));
|
|
|
|
case Kind::ObjCCompletionHandlerArgumentsType: {
|
|
// Match up the tuple element with the parameter from the Clang block type,
|
|
// skipping the error parameter index if any.
|
|
auto callback = cast<clang::FunctionProtoType>(getClangType());
|
|
auto errorIndex = getEncodedForeignInfo()
|
|
.getAsyncCompletionHandlerErrorParamIndex();
|
|
unsigned paramIndex = index + (errorIndex && index >= *errorIndex);
|
|
return AbstractionPattern(getGenericSignature(),
|
|
getCanTupleElementType(getType(), index),
|
|
callback->getParamType(paramIndex).getTypePtr());
|
|
}
|
|
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Return a pattern corresponding 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 corresponding to the 'self' parameter of the given
|
|
/// C function imported as a method.
|
|
AbstractionPattern
|
|
AbstractionPattern::getCFunctionAsMethodSelfPattern(CanType selfType) const {
|
|
auto memberStatus = getImportAsMemberStatus();
|
|
if (memberStatus.isInstance()) {
|
|
// 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(),memberStatus.getSelfIndex());
|
|
|
|
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);
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getCXXMethodSelfPattern(CanType selfType) const {
|
|
assert(hasStoredCXXMethod());
|
|
auto CXXMethod = getCXXMethod();
|
|
if (CXXMethod->isInstance()) {
|
|
// 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 =
|
|
CXXMethod->getThisType().getTypePtr();
|
|
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);
|
|
}
|
|
|
|
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::ObjCCompletionHandlerArgumentsType:
|
|
case Kind::Tuple:
|
|
llvm_unreachable("abstraction pattern for tuple cannot be function");
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Type:
|
|
if (isTypeParameterOrOpaqueArchetype())
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()));
|
|
case Kind::Discard:
|
|
llvm_unreachable("don't need to discard function abstractions yet");
|
|
case Kind::ClangType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType: {
|
|
auto clangFunctionType = getClangFunctionType(getClangType());
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
clangFunctionType->getReturnType().getTypePtr());
|
|
}
|
|
case Kind::CXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getCXXMethod()->getReturnType().getTypePtr());
|
|
case Kind::CurriedObjCMethodType:
|
|
return getPartialCurriedObjCMethod(
|
|
getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getObjCMethod(),
|
|
getEncodedForeignInfo());
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
return getPartialCurriedCFunctionAsMethod(
|
|
getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getClangType(),
|
|
getImportAsMemberStatus());
|
|
case Kind::CurriedCXXMethodType:
|
|
return getPartialCurriedCXXMethod(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()), getCXXMethod());
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
return getPartialCurriedCXXOperatorMethod(
|
|
getGenericSignatureForFunctionComponent(), getResultType(getType()),
|
|
getCXXMethod());
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodType: {
|
|
// If this is a foreign async function, the result type comes from the
|
|
// completion callback argument to the original method. Line up the
|
|
// result abstraction pattern with that callback argument.
|
|
if (getEncodedForeignInfo().getKind() == EncodedForeignInfo::IsAsync) {
|
|
auto paramIndex
|
|
= getEncodedForeignInfo().getAsyncCompletionHandlerParamIndex();
|
|
|
|
auto callbackParamTy = getObjCMethod()->parameters()[paramIndex]
|
|
->getType()
|
|
->getPointeeType()
|
|
->getAs<clang::FunctionProtoType>();
|
|
|
|
// The result comprises the non-error argument(s) to the callback, if
|
|
// any.
|
|
|
|
auto callbackErrorIndex = getEncodedForeignInfo()
|
|
.getAsyncCompletionHandlerErrorParamIndex();
|
|
assert((!callbackErrorIndex.hasValue()
|
|
|| callbackParamTy->getNumParams() > *callbackErrorIndex)
|
|
&& "completion handler has invalid error param index?!");
|
|
unsigned numNonErrorParams
|
|
= callbackParamTy->getNumParams() - callbackErrorIndex.hasValue();
|
|
|
|
switch (numNonErrorParams) {
|
|
case 0:
|
|
// If there are no result arguments, then the imported result type is
|
|
// Void, with no interesting abstraction properties.
|
|
return AbstractionPattern(TupleType::getEmpty(getType()->getASTContext()));
|
|
|
|
case 1: {
|
|
// If there's a single argument, abstract it according to its formal type
|
|
// in the ObjC signature.
|
|
unsigned callbackResultIndex
|
|
= callbackErrorIndex && *callbackErrorIndex == 0;
|
|
auto clangResultType = callbackParamTy
|
|
->getParamType(callbackResultIndex)
|
|
.getTypePtr();
|
|
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()), clangResultType);
|
|
}
|
|
|
|
default:
|
|
// If there are multiple results, we have a special abstraction pattern
|
|
// form to represent the mapping from block parameters to tuple elements
|
|
// in the return type.
|
|
return AbstractionPattern::getObjCCompletionHandlerArgumentsType(
|
|
getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()), callbackParamTy,
|
|
getEncodedForeignInfo());
|
|
}
|
|
}
|
|
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
getResultType(getType()),
|
|
getObjCMethod()->getReturnType().getTypePtr());
|
|
}
|
|
case Kind::OpaqueFunction:
|
|
return getOpaque();
|
|
case Kind::OpaqueDerivativeFunction:
|
|
static SmallVector<AbstractionPattern, 2> elements{getOpaque(),
|
|
getOpaqueFunction()};
|
|
return getTuple(elements);
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getObjCMethodAsyncCompletionHandlerType(
|
|
CanType swiftCompletionHandlerType) const {
|
|
switch (getKind()) {
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodType: {
|
|
// Create an abstraction pattern using the original ObjC type of the
|
|
// completion handler.
|
|
assert(getEncodedForeignInfo().getKind() == EncodedForeignInfo::IsAsync);
|
|
auto paramIndex = getEncodedForeignInfo().getAsyncCompletionHandlerParamIndex();
|
|
auto callbackParamTy = getObjCMethod()->parameters()[paramIndex]
|
|
->getType().getTypePtr();
|
|
|
|
return AbstractionPattern(swiftCompletionHandlerType, callbackParamTy);
|
|
}
|
|
case Kind::Opaque:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::Type:
|
|
return AbstractionPattern(getGenericSignature(),
|
|
swiftCompletionHandlerType);
|
|
case Kind::Invalid:
|
|
case Kind::Tuple:
|
|
case Kind::Discard:
|
|
case Kind::ClangType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
swift_unreachable("not appropriate for this kind");
|
|
}
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::getFunctionParamType(unsigned index) const {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return *this;
|
|
case Kind::Type: {
|
|
if (isTypeParameterOrOpaqueArchetype())
|
|
return AbstractionPattern::getOpaque();
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
params[index].getParameterType());
|
|
}
|
|
case Kind::CurriedCFunctionAsMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
assert(params.size() == 1);
|
|
return getCFunctionAsMethodSelfPattern(params[0].getParameterType());
|
|
}
|
|
case Kind::CurriedCXXMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
assert(params.size() == 1);
|
|
return getCXXMethodSelfPattern(params[0].getParameterType());
|
|
}
|
|
case Kind::CurriedCXXOperatorMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
assert(params.size() == 1);
|
|
|
|
// The formal metatype parameter to a C++ member operator function imported
|
|
// as a static method is dropped on the floor. Leave it untransformed.
|
|
return AbstractionPattern::getDiscard(
|
|
getGenericSignatureForFunctionComponent(),
|
|
params[0].getParameterType());
|
|
}
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
|
|
// Only the full method type has a 'self' parameter.
|
|
if (getKind() == Kind::CFunctionAsMethodType) {
|
|
assert(params.size() > 0);
|
|
|
|
// The last parameter is 'self'.
|
|
if (index == params.size() - 1) {
|
|
return getCFunctionAsMethodSelfPattern(params.back().getParameterType());
|
|
}
|
|
}
|
|
|
|
// A parameter of type () does not correspond to a Clang parameter.
|
|
auto paramType = params[index].getParameterType();
|
|
if (paramType->isVoid())
|
|
return AbstractionPattern(paramType);
|
|
|
|
// Otherwise, we're talking about the formal parameter clause.
|
|
// Jump over the self parameter in the Clang type.
|
|
unsigned clangIndex = index;
|
|
auto memberStatus = getImportAsMemberStatus();
|
|
if (memberStatus.isInstance() && clangIndex >= memberStatus.getSelfIndex())
|
|
++clangIndex;
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
paramType,
|
|
getClangFunctionParameterType(getClangType(), clangIndex));
|
|
}
|
|
case Kind::CXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
|
|
// Only the full method type has a 'self' parameter.
|
|
if (getKind() == Kind::CXXMethodType) {
|
|
assert(params.size() > 0);
|
|
|
|
// The last parameter is 'self'.
|
|
if (index == params.size() - 1) {
|
|
return getCXXMethodSelfPattern(params.back().getParameterType());
|
|
}
|
|
}
|
|
|
|
// A parameter of type () does not correspond to a Clang parameter.
|
|
auto paramType = params[index].getParameterType();
|
|
if (paramType->isVoid())
|
|
return AbstractionPattern(paramType);
|
|
|
|
// Otherwise, we're talking about the formal parameter clause.
|
|
auto methodType = getCXXMethod()->getType().getTypePtr();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
paramType,
|
|
getClangFunctionParameterType(methodType, index));
|
|
}
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
auto paramType = params[index].getParameterType();
|
|
|
|
// The first parameter holds the left-hand-side operand, which gets passed
|
|
// to the C++ function as the this pointer.
|
|
if (index == 0)
|
|
return getCXXMethodSelfPattern(paramType);
|
|
|
|
// A parameter of type () does not correspond to a Clang parameter.
|
|
if (paramType->isVoid())
|
|
return AbstractionPattern(paramType);
|
|
|
|
// Otherwise, we're talking about the formal parameter clause.
|
|
auto methodType = getCXXMethod()->getType().getTypePtr();
|
|
return AbstractionPattern(
|
|
getGenericSignatureForFunctionComponent(), paramType,
|
|
getClangFunctionParameterType(methodType, index - 1));
|
|
}
|
|
case Kind::CurriedObjCMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
assert(params.size() == 1);
|
|
return getObjCMethodSelfPattern(params[0].getParameterType());
|
|
}
|
|
case Kind::ObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
|
|
// Only the full method type has a 'self' parameter.
|
|
if (getKind() == Kind::ObjCMethodType) {
|
|
assert(params.size() > 0);
|
|
|
|
// The last parameter is 'self'.
|
|
if (index == params.size() - 1) {
|
|
return getObjCMethodSelfPattern(params.back().getParameterType());
|
|
}
|
|
}
|
|
|
|
// A parameter of type () does not correspond to a Clang parameter.
|
|
auto paramType = params[index].getParameterType();
|
|
if (paramType->isVoid())
|
|
return AbstractionPattern(paramType);
|
|
|
|
// Otherwise, we're talking about the formal parameter clause.
|
|
auto method = getObjCMethod();
|
|
auto errorInfo = getEncodedForeignInfo();
|
|
|
|
unsigned paramIndex = index;
|
|
if (errorInfo.hasValue()) {
|
|
auto errorParamIndex = errorInfo.getForeignParamIndex();
|
|
|
|
if (!errorInfo.hasErrorParameterReplacedWithVoid()) {
|
|
if (paramIndex >= errorParamIndex) {
|
|
++paramIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
paramType,
|
|
method->parameters()[paramIndex]->getType().getTypePtr());
|
|
}
|
|
case Kind::ClangType: {
|
|
auto params = cast<AnyFunctionType>(getType()).getParams();
|
|
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
|
|
params[index].getParameterType(),
|
|
getClangFunctionParameterType(getClangType(), index));
|
|
}
|
|
case Kind::OpaqueFunction:
|
|
return getOpaque();
|
|
case Kind::OpaqueDerivativeFunction:
|
|
return getOpaque();
|
|
default:
|
|
llvm_unreachable("does not have function parameters");
|
|
}
|
|
}
|
|
|
|
unsigned AbstractionPattern::getNumFunctionParams() const {
|
|
return cast<AnyFunctionType>(getType()).getParams().size();
|
|
}
|
|
|
|
static CanType getOptionalObjectType(CanType type) {
|
|
auto objectType = type.getOptionalObjectType();
|
|
assert(objectType && "type was not optional");
|
|
return objectType;
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getOptionalObjectType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::Tuple:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
llvm_unreachable("pattern for function or tuple cannot be for optional");
|
|
|
|
case Kind::Opaque:
|
|
return *this;
|
|
|
|
case Kind::Type:
|
|
if (isTypeParameter())
|
|
return AbstractionPattern::getOpaque();
|
|
if (isa<OpaqueTypeArchetypeType>(getType()))
|
|
return AbstractionPattern::getOpaque();
|
|
return AbstractionPattern(getGenericSignature(),
|
|
::getOptionalObjectType(getType()));
|
|
|
|
case Kind::Discard:
|
|
return AbstractionPattern::getDiscard(getGenericSignature(),
|
|
::getOptionalObjectType(getType()));
|
|
|
|
case Kind::ClangType:
|
|
// This is not reflected in clang types.
|
|
return AbstractionPattern(getGenericSignature(),
|
|
::getOptionalObjectType(getType()),
|
|
getClangType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::Tuple:
|
|
case Kind::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
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(),
|
|
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::OpaqueFunction:
|
|
out << "AP::OpaqueFunction";
|
|
return;
|
|
case Kind::OpaqueDerivativeFunction:
|
|
out << "AP::OpaqueDerivativeFunction";
|
|
return;
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
out << (getKind() == Kind::Type
|
|
? "AP::Type" :
|
|
getKind() == Kind::Discard
|
|
? "AP::Discard" : "<<UNHANDLED CASE>>");
|
|
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::CurriedCFunctionAsMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
out << (getKind() == Kind::ClangType
|
|
? "AP::ClangType(" :
|
|
getKind() == Kind::CurriedCFunctionAsMethodType
|
|
? "AP::CurriedCFunctionAsMethodType(" :
|
|
getKind() == Kind::PartialCurriedCFunctionAsMethodType
|
|
? "AP::PartialCurriedCFunctionAsMethodType(" :
|
|
getKind() == Kind::ObjCCompletionHandlerArgumentsType
|
|
? "AP::ObjCCompletionHandlerArgumentsType("
|
|
: "AP::CFunctionAsMethodType(");
|
|
if (auto sig = getGenericSignature()) {
|
|
sig->print(out);
|
|
}
|
|
getType().dump(out);
|
|
out << ", ";
|
|
// [TODO: Improve-Clang-type-printing]
|
|
// 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 (hasImportAsMemberStatus()) {
|
|
out << ", member=";
|
|
auto status = getImportAsMemberStatus();
|
|
if (status.isInstance()) {
|
|
out << "instance, self=" << status.getSelfIndex();
|
|
} else if (status.isStatic()) {
|
|
out << "static";
|
|
}
|
|
}
|
|
if (hasStoredForeignInfo()) {
|
|
if (auto errorIndex
|
|
= getEncodedForeignInfo().getAsyncCompletionHandlerErrorParamIndex()){
|
|
out << ", errorParamIndex=" << *errorIndex;
|
|
}
|
|
}
|
|
out << ")";
|
|
return;
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
out << (getKind() == Kind::CXXOperatorMethodType
|
|
? "AP::CXXOperatorMethodType(" :
|
|
getKind() == Kind::CurriedCXXOperatorMethodType
|
|
? "AP::CurriedCXXOperatorMethodType(" :
|
|
getKind() == Kind::PartialCurriedCXXOperatorMethodType
|
|
? "AP::PartialCurriedCXXOperatorMethodType(" :
|
|
getKind() == Kind::CXXMethodType
|
|
? "AP::CXXMethodType(" :
|
|
getKind() == Kind::CurriedCXXMethodType
|
|
? "AP::CurriedCXXMethodType("
|
|
: "AP::PartialCurriedCXXMethodType");
|
|
if (auto sig = getGenericSignature()) {
|
|
sig->print(out);
|
|
}
|
|
getType().dump(out);
|
|
out << ", ";
|
|
getCXXMethod()->dump();
|
|
assert(!hasImportAsMemberStatus());
|
|
out << ")";
|
|
return;
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
out << (getKind() == Kind::ObjCMethodType
|
|
? "AP::ObjCMethodType(" :
|
|
getKind() == Kind::CurriedObjCMethodType
|
|
? "AP::CurriedObjCMethodType("
|
|
: "AP::PartialCurriedObjCMethodType(");
|
|
getType().dump(out);
|
|
auto errorInfo = getEncodedForeignInfo();
|
|
switch (errorInfo.getKind()) {
|
|
case EncodedForeignInfo::IsNotForeign:
|
|
break;
|
|
|
|
case EncodedForeignInfo::IsError:
|
|
out << ", errorParameter=" << errorInfo.getErrorParamIndex();
|
|
if (errorInfo.hasErrorParameterReplacedWithVoid())
|
|
out << ", replacedWithVoid";
|
|
if (errorInfo.errorStripsResultOptionality())
|
|
out << ", stripsResultOptionality";
|
|
break;
|
|
|
|
case EncodedForeignInfo::IsAsync:
|
|
out << ", completionHandlerParameter=" << errorInfo.getAsyncCompletionHandlerParamIndex();
|
|
if (auto errorParam = errorInfo.getAsyncCompletionHandlerErrorParamIndex()) {
|
|
out << " (errorParam=" << *errorParam << ')';
|
|
}
|
|
}
|
|
out << ", ";
|
|
getObjCMethod()->dump(out);
|
|
out << ")";
|
|
return;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool AbstractionPattern::hasSameBasicTypeStructure(CanType l, CanType r) {
|
|
if (l == r) return true;
|
|
|
|
// Tuples must match.
|
|
auto lTuple = dyn_cast<TupleType>(l);
|
|
auto rTuple = dyn_cast<TupleType>(r);
|
|
if (lTuple && rTuple) {
|
|
auto lElts = lTuple.getElementTypes();
|
|
auto rElts = rTuple.getElementTypes();
|
|
if (lElts.size() != rElts.size())
|
|
return false;
|
|
for (auto i : indices(lElts)) {
|
|
if (!hasSameBasicTypeStructure(lElts[i], rElts[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
} else if (lTuple || rTuple) {
|
|
return false;
|
|
}
|
|
|
|
// Functions must match.
|
|
auto lFunction = dyn_cast<AnyFunctionType>(l);
|
|
auto rFunction = dyn_cast<AnyFunctionType>(r);
|
|
if (lFunction && rFunction) {
|
|
auto lParam = lFunction.getParams();
|
|
auto rParam = rFunction.getParams();
|
|
if (lParam.size() != rParam.size())
|
|
return false;
|
|
|
|
for (unsigned i : indices(lParam)) {
|
|
if (!hasSameBasicTypeStructure(lParam[i].getPlainType(),
|
|
rParam[i].getPlainType()))
|
|
return false;
|
|
}
|
|
|
|
return hasSameBasicTypeStructure(lFunction.getResult(),
|
|
rFunction.getResult());
|
|
} else if (lFunction || rFunction) {
|
|
return false;
|
|
}
|
|
|
|
// Optionals must match, sortof.
|
|
auto lObject = l.getOptionalObjectType();
|
|
auto rObject = r.getOptionalObjectType();
|
|
if (lObject && rObject) {
|
|
return hasSameBasicTypeStructure(lObject, rObject);
|
|
} else if (lObject || rObject) {
|
|
// Allow optionality mis-matches, but require the underlying types to match.
|
|
return hasSameBasicTypeStructure(lObject ? lObject : l,
|
|
rObject ? rObject : r);
|
|
}
|
|
|
|
// Otherwise, the structure is similar enough.
|
|
return true;
|
|
}
|
|
|
|
AbstractionPattern
|
|
AbstractionPattern::unsafeGetSubstFieldType(ValueDecl *member,
|
|
CanType origMemberInterfaceType)
|
|
const {
|
|
if (isTypeParameterOrOpaqueArchetype()) {
|
|
// Fall back to the generic abstraction pattern for the member.
|
|
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
|
|
CanType memberTy = origMemberInterfaceType
|
|
? origMemberInterfaceType
|
|
: member->getInterfaceType()->getCanonicalType(sig);
|
|
return AbstractionPattern(sig.getCanonicalSignature(), memberTy);
|
|
}
|
|
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
llvm_unreachable("should be handled by isTypeParameter");
|
|
case Kind::Invalid:
|
|
llvm_unreachable("called on invalid abstraction pattern");
|
|
case Kind::Tuple:
|
|
llvm_unreachable("should not have a tuple pattern matching a struct/enum "
|
|
"type");
|
|
case Kind::OpaqueFunction:
|
|
llvm_unreachable("should not have an opaque function pattern matching a "
|
|
"struct/enum type");
|
|
case Kind::OpaqueDerivativeFunction:
|
|
llvm_unreachable("should not have an opaque derivative function pattern "
|
|
"matching a struct/enum type");
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
llvm_unreachable("should not have a completion handler argument pattern "
|
|
"matching a struct/enum type");
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedCFunctionAsMethodType:
|
|
case Kind::CurriedCFunctionAsMethodType:
|
|
case Kind::CFunctionAsMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
case Kind::CXXOperatorMethodType:
|
|
case Kind::CurriedCXXOperatorMethodType:
|
|
case Kind::PartialCurriedCXXOperatorMethodType:
|
|
case Kind::ClangType:
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
auto memberTy = getType()->getTypeOfMember(member->getModuleContext(),
|
|
member, origMemberInterfaceType)
|
|
->getCanonicalType(getGenericSignature());
|
|
|
|
return AbstractionPattern(getGenericSignature(), memberTy);
|
|
}
|
|
llvm_unreachable("invalid abstraction pattern kind");
|
|
}
|
|
|
|
AbstractionPattern AbstractionPattern::getAutoDiffDerivativeFunctionType(
|
|
IndexSubset *parameterIndices, AutoDiffDerivativeFunctionKind kind,
|
|
LookupConformanceFn lookupConformance,
|
|
GenericSignature derivativeGenericSignature, bool makeSelfParamFirst) {
|
|
switch (getKind()) {
|
|
case Kind::Type: {
|
|
auto fnTy = dyn_cast<AnyFunctionType>(getType());
|
|
if (!fnTy)
|
|
return getOpaqueDerivativeFunction();
|
|
auto derivativeFnTy = fnTy->getAutoDiffDerivativeFunctionType(
|
|
parameterIndices, kind, lookupConformance, derivativeGenericSignature,
|
|
makeSelfParamFirst);
|
|
assert(derivativeFnTy);
|
|
return AbstractionPattern(
|
|
getGenericSignature(),
|
|
derivativeFnTy->getCanonicalType(getGenericSignature()));
|
|
}
|
|
case Kind::Opaque:
|
|
return getOpaqueDerivativeFunction();
|
|
default:
|
|
llvm_unreachable("called on unsupported abstraction pattern kind");
|
|
}
|
|
}
|