//===--- 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(decl)) { return getAbstractionPattern(var, isNonObjC); } else { return getAbstractionPattern(cast(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(decl)) { return valueDecl->getType().getTypePtr(); } // This should *really* be a ValueDecl. return cast(decl)->getType().getTypePtr(); } static Bridgeability getClangDeclBridgeability(const clang::Decl *decl) { // These declarations are always imported without bridging (for now). if (isa(decl) || isa(decl) || isa(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 &foreignError, const Optional &foreignAsync) { // Foreign async convention takes precedence. if (foreignAsync.hasValue()) { return EncodedForeignInfo(EncodedForeignInfo::Async, foreignAsync->completionHandlerParamIndex(), foreignAsync->completionHandlerErrorParamIndex(), foreignAsync->completionHandlerFlagParamIndex(), foreignAsync->completionHandlerFlagIsErrorOnZero()); } 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 &foreignError, const Optional &foreignAsync) { auto errorInfo = EncodedForeignInfo::encode(foreignError, foreignAsync); return getObjCMethod(origType, method, errorInfo); } AbstractionPattern AbstractionPattern::getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method, const Optional &foreignError, const Optional &foreignAsync) { auto errorInfo = EncodedForeignInfo::encode(foreignError, foreignAsync); return getCurriedObjCMethod(origType, method, errorInfo); } AbstractionPattern AbstractionPattern::getCurriedCFunctionAsMethod(CanType origType, const AbstractFunctionDecl *function) { auto clangFn = cast(function->getClangDecl()); return getCurriedCFunctionAsMethod(origType, clangFn->getType().getTypePtr(), function->getImportAsMemberStatus()); } AbstractionPattern AbstractionPattern::getCurriedCXXMethod(CanType origType, const AbstractFunctionDecl *function) { auto clangMethod = cast(function->getClangDecl()); return getCurriedCXXMethod(origType, clangMethod, function->getImportAsMemberStatus()); } AbstractionPattern AbstractionPattern::getCurriedCXXOperatorMethod( CanType origType, const AbstractFunctionDecl *function) { auto clangMethod = cast(function->getClangDecl()); return getCurriedCXXOperatorMethod(origType, clangMethod, function->getImportAsMemberStatus()); } 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(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(type)) { return archetype->getLayoutConstraint(); } else if (isa(type) || isa(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 (isTypeParameterOrOpaqueArchetype()) return true; auto type = getType(); if (auto tuple = dyn_cast(type)) return (tuple->getNumElements() == substType->getNumElements()); return false; } } llvm_unreachable("bad kind"); } static const clang::FunctionType * getClangFunctionType(const clang::Type *clangType) { if (auto ptrTy = clangType->getAs()) { clangType = ptrTy->getPointeeType().getTypePtr(); } else if (auto blockTy = clangType->getAs()) { clangType = blockTy->getPointeeType().getTypePtr(); } else if (auto refTy = clangType->getAs()) { clangType = refTy->getPointeeType().getTypePtr(); } return clangType->castAs(); } 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(); 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(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 and flag indexes if any. auto callback = cast(getClangType()); auto errorIndex = getEncodedForeignInfo() .getAsyncCompletionHandlerErrorParamIndex(); auto flagIndex = getEncodedForeignInfo() .getAsyncCompletionHandlerErrorFlagParamIndex(); unsigned paramIndex = index; if (errorIndex && paramIndex >= *errorIndex) ++paramIndex; if (flagIndex && paramIndex >= *flagIndex) ++paramIndex; 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(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(), getImportAsMemberStatus()); case Kind::CurriedCXXOperatorMethodType: return getPartialCurriedCXXOperatorMethod( getGenericSignatureForFunctionComponent(), getResultType(getType()), getCXXMethod(), getImportAsMemberStatus()); 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(); // The result comprises the non-error argument(s) to the callback, if // any. auto callbackErrorIndex = getEncodedForeignInfo() .getAsyncCompletionHandlerErrorParamIndex(); auto callbackErrorFlagIndex = getEncodedForeignInfo() .getAsyncCompletionHandlerErrorFlagParamIndex(); assert((!callbackErrorIndex.hasValue() || callbackParamTy->getNumParams() > *callbackErrorIndex) && "completion handler has invalid error param index?!"); assert((!callbackErrorFlagIndex.hasValue() || callbackParamTy->getNumParams() > *callbackErrorFlagIndex) && "completion handler has invalid error param index?!"); unsigned numNonErrorParams = callbackParamTy->getNumParams() - callbackErrorIndex.hasValue() - callbackErrorFlagIndex.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 = 0; if (callbackErrorIndex && callbackResultIndex >= *callbackErrorIndex) ++callbackResultIndex; if (callbackErrorFlagIndex && callbackResultIndex >= *callbackErrorFlagIndex) ++callbackResultIndex; 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 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(); CanGenericSignature patternSig; if (auto origSig = getGenericSignature()) { patternSig = origSig; } else if (auto genFnTy = dyn_cast(getType())) { patternSig = genFnTy->getGenericSignature()->getCanonicalSignature(); } return AbstractionPattern(patternSig, 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"); } llvm_unreachable("covered switch"); } AbstractionPattern AbstractionPattern::getFunctionParamType(unsigned index) const { switch (getKind()) { case Kind::Opaque: return *this; case Kind::Type: { if (isTypeParameterOrOpaqueArchetype()) return AbstractionPattern::getOpaque(); auto params = cast(getType()).getParams(); return AbstractionPattern(getGenericSignatureForFunctionComponent(), params[index].getParameterType()); } case Kind::CurriedCFunctionAsMethodType: { auto params = cast(getType()).getParams(); assert(params.size() == 1); return getCFunctionAsMethodSelfPattern(params[0].getParameterType()); } case Kind::CurriedCXXMethodType: { auto params = cast(getType()).getParams(); assert(params.size() == 1); return getCXXMethodSelfPattern(params[0].getParameterType()); } case Kind::CurriedCXXOperatorMethodType: { auto params = cast(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(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(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(getType()).getParams(); auto paramType = params[index].getParameterType(); // See importer::isImportedAsStatic bool isStatic = getImportAsMemberStatus().isStatic(); if (isStatic) { // 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); } else { // The last parameter is 'self'. if (getKind() == Kind::CXXOperatorMethodType && index == params.size() - 1) return getCXXMethodSelfPattern(params.back().getParameterType()); } // 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 - (isStatic ? 1 : 0))); } case Kind::CurriedObjCMethodType: { auto params = cast(getType()).getParams(); assert(params.size() == 1); return getObjCMethodSelfPattern(params[0].getParameterType()); } case Kind::ObjCMethodType: case Kind::PartialCurriedObjCMethodType: { auto params = cast(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(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(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 (isTypeParameterOrOpaqueArchetype()) 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" : "<>"); 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; if (auto errorFlag = errorInfo.getAsyncCompletionHandlerErrorFlagParamIndex()) { out << ", errorFlagParam=" << *errorFlag << (errorInfo.isCompletionErrorFlagZeroOnError() ? ", zeroOnError" : ", nonzeroOnError"); } out << ')'; } } 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(l); auto rTuple = dyn_cast(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(l); auto rFunction = dyn_cast(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(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"); } }