Files
swift-mirror/lib/SIL/IR/AbstractionPattern.cpp
2025-11-12 21:02:55 -08:00

3028 lines
109 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.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/Types.h"
#include "llvm/ADT/SmallVector.h"
#define DEBUG_TYPE "libsil"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ConformanceLookup.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/AST/TypeCheckRequests.h"
#include "swift/AST/CanTypeVisitor.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Defer.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/SIL/AbstractionPatternGenerators.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 sig = decl->getGenericSignatureOfContext().getCanonicalSignature();
auto type = sig.getReducedType(decl->getElementInterfaceType());
return AbstractionPattern(sig, 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) {
auto sig = var->getDeclContext()
->getGenericSignatureOfContext()
.getCanonicalSignature();
auto interfaceType = var->getInterfaceType();
if (auto *packExpansionType = interfaceType->getAs<PackExpansionType>())
interfaceType = packExpansionType->getPatternType();
auto swiftType = sig.getReducedType(interfaceType);
if (isNonObjC)
return AbstractionPattern(sig, swiftType);
if (auto clangDecl = var->getClangDecl()) {
auto clangType = getClangType(clangDecl);
auto contextType = var->getDeclContext()->mapTypeIntoContext(swiftType);
swiftType =
getLoweredBridgedType(AbstractionPattern(sig, swiftType, clangType),
contextType, getClangDeclBridgeability(clangDecl),
SILFunctionTypeRepresentation::CFunctionPointer,
TypeConverter::ForMemory)
->getCanonicalType();
return AbstractionPattern(sig, swiftType, clangType);
}
return AbstractionPattern(sig, 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");
auto sig = decl->getParentEnum()
->getGenericSignatureOfContext()
.getCanonicalSignature();
auto type = sig.getReducedType(decl->getPayloadInterfaceType());
return AbstractionPattern(sig, type);
}
AbstractionPattern::EncodedForeignInfo
AbstractionPattern::EncodedForeignInfo::encode(
const std::optional<ForeignErrorConvention> &foreignError,
const std::optional<ForeignAsyncConvention> &foreignAsync) {
// Foreign async convention takes precedence.
if (foreignAsync.has_value()) {
return EncodedForeignInfo(EncodedForeignInfo::Async,
foreignAsync->completionHandlerParamIndex(),
foreignAsync->completionHandlerErrorParamIndex(),
foreignAsync->completionHandlerFlagParamIndex(),
foreignAsync->completionHandlerFlagIsErrorOnZero());
} else if (foreignError.has_value()) {
return EncodedForeignInfo(EncodedForeignInfo::Error,
foreignError->getErrorParameterIndex(),
foreignError->isErrorParameterReplacedWithVoid(),
foreignError->stripsResultOptionality());
} else {
return {};
}
}
AbstractionPattern AbstractionPattern::getObjCMethod(
CanType origType, const clang::ObjCMethodDecl *method,
const std::optional<ForeignErrorConvention> &foreignError,
const std::optional<ForeignAsyncConvention> &foreignAsync) {
auto errorInfo = EncodedForeignInfo::encode(foreignError, foreignAsync);
return getObjCMethod(origType, method, errorInfo);
}
AbstractionPattern AbstractionPattern::getCurriedObjCMethod(
CanType origType, const clang::ObjCMethodDecl *method,
const std::optional<ForeignErrorConvention> &foreignError,
const std::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, 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::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.getGenericSubstitutions(),
object.getGenericSignature(),
OptionalType::get(object.getType())
->getCanonicalType(),
object.getClangType());
case Kind::Type:
return AbstractionPattern(object.getGenericSubstitutions(),
object.getGenericSignature(),
OptionalType::get(object.getType())
->getCanonicalType());
case Kind::Discard:
return AbstractionPattern::getDiscard(
object.getGenericSubstitutions(),
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 element = dyn_cast<PackElementType>(type))
type = element.getPackType();
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::conformsToKnownProtocol(
CanType substTy, KnownProtocolKind protocolKind) const {
auto suppressible
= substTy->getASTContext().getProtocol(protocolKind);
auto definitelyConforms = [&](CanType t) -> bool {
auto result =
checkConformanceWithoutContext(t, suppressible,
/*allowMissing=*/false);
return result.has_value() && !result.value().isInvalid();
};
// If the substituted type definitely conforms, that's authoritative.
if (definitelyConforms(substTy)) {
return true;
}
// If the substituted type is fully concrete, that's it. If there are unbound
// type variables in the type, then we may have to account for the upper
// abstraction bound from the abstraction pattern.
if (!substTy->hasTypeParameter()) {
return false;
}
switch (getKind()) {
case Kind::Opaque: {
// The abstraction pattern doesn't provide any more specific bounds.
return false;
}
case Kind::Type:
case Kind::Discard:
case Kind::ClangType: {
// See whether the abstraction pattern's context gives us an upper bound
// that ensures the type conforms.
auto type = getType();
if (hasGenericSignature() && getType()->hasTypeParameter()) {
type = GenericEnvironment::mapTypeIntoContext(
getGenericSignature().getGenericEnvironment(), getType())
->getReducedType(getGenericSignature());
}
return definitelyConforms(type);
}
case Kind::Tuple: {
// A tuple conforms if all elements do.
if (doesTupleVanish()) {
return getVanishingTupleElementPatternType().value()
.conformsToKnownProtocol(substTy, protocolKind);
}
auto substTupleTy = cast<TupleType>(substTy);
for (unsigned i = 0, e = getNumTupleElements(); i < e; ++i) {
if (!getTupleElementType(i).conformsToKnownProtocol(
substTupleTy.getElementType(i), protocolKind)) {
return false;
}
}
return true;
}
// Functions are, at least for now, always copyable.
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return true;
case Kind::Invalid:
llvm_unreachable("asking invalid abstraction pattern");
}
}
bool AbstractionPattern::isNoncopyable(CanType substTy) const {
return !conformsToKnownProtocol(substTy, KnownProtocolKind::Copyable);
}
bool AbstractionPattern::isEscapable(CanType substTy) const {
return conformsToKnownProtocol(substTy, KnownProtocolKind::Escapable);
}
bool AbstractionPattern::matchesTuple(CanType substType) 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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
case Kind::Opaque:
return true;
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::ClangType:
case Kind::Type:
case Kind::Discard:
if (isTypeParameterOrOpaqueArchetype())
return true;
if (!isa<TupleType>(getType()))
return false;
LLVM_FALLTHROUGH;
case Kind::Tuple: {
if (doesTupleVanish()) {
// TODO: recurse into elements.
return true;
}
auto substTupleType = dyn_cast<TupleType>(substType);
if (!substTupleType) return false;
size_t nextSubstIndex = 0;
auto nextComponentIsAcceptable = [&](bool isPackExpansion) -> bool {
if (nextSubstIndex == substTupleType->getNumElements())
return false;
auto substComponentType = substTupleType.getElementType(nextSubstIndex++);
return (isPackExpansion == isa<PackExpansionType>(substComponentType));
};
for (auto elt : getTupleElementTypes()) {
bool isPackExpansion = elt.isPackExpansion();
if (isPackExpansion && elt.GenericSubs) {
auto origExpansion = cast<PackExpansionType>(elt.getType());
auto substShape = cast<PackType>(
origExpansion.getCountType().subst(elt.GenericSubs)
->getCanonicalType());
for (auto shapeElt : substShape.getElementTypes()) {
if (!nextComponentIsAcceptable(isa<PackExpansionType>(shapeElt)))
return false;
}
} else if (!nextComponentIsAcceptable(isPackExpansion)) {
return false;
}
}
return nextSubstIndex == substTupleType->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();
} 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::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(getGenericSubstitutions(),
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(getGenericSubstitutions(),
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<clang::FunctionProtoType>(getClangType());
auto errorIndex = getEncodedForeignInfo()
.getAsyncCompletionHandlerErrorParamIndex();
auto flagIndex = getEncodedForeignInfo()
.getAsyncCompletionHandlerErrorFlagParamIndex();
unsigned paramIndex = index;
if (errorIndex && paramIndex >= *errorIndex)
++paramIndex;
if (flagIndex && paramIndex >= *flagIndex)
++paramIndex;
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
getCanTupleElementType(getType(), index),
callback->getParamType(paramIndex).getTypePtr());
}
}
llvm_unreachable("bad kind");
}
bool AbstractionPattern::doesTupleContainPackExpansionType() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("pattern is not a tuple");
case Kind::Tuple: {
for (auto &elt :
llvm::ArrayRef(OrigTupleElements, getNumTupleElements_Stored())) {
if (elt.isPackExpansion())
return true;
}
return true;
}
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::Type:
case Kind::Discard:
case Kind::ClangType:
return cast<TupleType>(getType()).containsPackExpansionType();
}
llvm_unreachable("bad kind");
}
bool AbstractionPattern::doesTupleVanish() const {
assert(isTuple());
return getVanishingTupleElementPatternType().has_value();
}
std::optional<AbstractionPattern>
AbstractionPattern::getVanishingTupleElementPatternType() const {
if (!isTuple())
return std::nullopt;
if (!GenericSubs)
return std::nullopt;
// Substitution causes tuples to vanish when substituting the elements
// produces a singleton tuple and it didn't start that way.
auto numOrigElts = getNumTupleElements();
// Track whether we've found a single element.
std::optional<AbstractionPattern> singletonEltType;
bool hadOrigExpansion = false;
for (auto index : range(numOrigElts)) {
auto eltType = getTupleElementType(index);
// If this pattern isn't a pack expansion, we've got a new candidate
// singleton. If this is the second such candidate, of course, it's
// not a singleton.
if (!eltType.isPackExpansion()) {
if (singletonEltType)
return std::nullopt;
singletonEltType = eltType;
// Otherwise, check what the expansion shape expands to.
} else {
hadOrigExpansion = true;
auto expansionType = cast<PackExpansionType>(eltType.getType());
auto substShape = cast<PackType>(
expansionType.getCountType().subst(GenericSubs)->getCanonicalType());
auto expansionCount = substShape->getNumElements();
// If it expands to multiple elements or to a single expansion, we
// won't have a singleton tuple. If it expands to a single scalar
// element, this is a singleton candidate.
if (expansionCount > 1) {
return std::nullopt;
} else if (expansionCount == 1) {
auto substExpansion =
dyn_cast<PackExpansionType>(substShape.getElementType(0));
if (substExpansion)
return std::nullopt;
if (singletonEltType)
return std::nullopt;
singletonEltType = eltType.getPackExpansionPatternType();
}
}
}
// If we found a singleton scalar element, and we didn't start with
// a singleton element, that's the index we want to return.
if (singletonEltType && !(numOrigElts == 1 && !hadOrigExpansion))
return singletonEltType;
return std::nullopt;
}
void AbstractionPattern::forEachTupleElement(CanType substType,
llvm::function_ref<void(TupleElementGenerator &)> handleElement) const {
TupleElementGenerator elt(*this, substType);
for (; !elt.isFinished(); elt.advance()) {
handleElement(elt);
}
elt.finish();
}
TupleElementGenerator::TupleElementGenerator(
AbstractionPattern origTupleType,
CanType substType)
: origTupleType(origTupleType), substType(substType) {
assert(origTupleType.isTuple());
assert(origTupleType.matchesTuple(substType));
origTupleVanishes = origTupleType.doesTupleVanish();
origTupleTypeIsOpaque = origTupleType.isOpaqueTuple();
numOrigElts = origTupleType.getNumTupleElements();
if (!isFinished()) loadElement();
}
void AbstractionPattern::forEachExpandedTupleElement(CanType substType,
llvm::function_ref<void(AbstractionPattern origEltType,
CanType substEltType,
const TupleTypeElt &elt)>
handleElement) const {
assert(matchesTuple(substType));
// Handle opaque patterns by just iterating the substituted components.
if (!isTuple()) {
auto substTupleType = cast<TupleType>(substType);
auto substEltTypes = substTupleType.getElementTypes();
for (auto i : indices(substEltTypes)) {
handleElement(getTupleElementType(i), substEltTypes[i],
substTupleType->getElement(i));
}
return;
}
// For vanishing tuples, just call the callback once.
if (auto origEltType = getVanishingTupleElementPatternType()) {
handleElement(*origEltType, substType, TupleTypeElt(substType));
return;
}
auto substTupleType = cast<TupleType>(substType);
auto substEltTypes = substTupleType.getElementTypes();
// For non-opaque patterns, we have to iterate the original components
// in order to match things up properly, but we'll still end up calling
// once per substituted element.
size_t substEltIndex = 0;
for (size_t origEltIndex : range(getNumTupleElements())) {
auto origEltType = getTupleElementType(origEltIndex);
if (!origEltType.isPackExpansion()) {
handleElement(origEltType, substEltTypes[substEltIndex],
substTupleType->getElement(substEltIndex));
substEltIndex++;
} else {
auto origPatternType = origEltType.getPackExpansionPatternType();
for (auto i : range(origEltType.getNumPackExpandedComponents())) {
(void) i;
auto substEltType = substEltTypes[substEltIndex];
// When the substituted type is a pack expansion, pass down
// the original element type so that it's *also* a pack expansion.
// Clients expect to look through this structure in parallel on
// both types. The count is misleading, but normal usage won't
// access it, and there's nothing we could provide that *wouldn't*
// be misleading in one way or another.
handleElement(isa<PackExpansionType>(substEltType)
? origEltType : origPatternType,
substEltType,
substTupleType->getElement(substEltIndex));
substEltIndex++;
}
}
}
assert(substEltIndex == substEltTypes.size());
}
AbstractionPattern
AbstractionPattern::getPackElementPackType() 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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ClangType:
case Kind::Tuple:
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("not a pack type");
case Kind::Opaque:
return *this;
case Kind::Discard:
llvm_unreachable("operation not needed on discarded abstractions yet");
case Kind::Type:
if (isTypeParameterOrOpaqueArchetype())
return AbstractionPattern::getOpaque();
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
cast<PackElementType>(getType()).getPackType());
}
llvm_unreachable("bad kind");
}
static CanType getCanPackElementType(CanType type, unsigned index) {
return cast<PackType>(type).getElementType(index);
}
static CanType getCanSILPackElementType(CanType type, unsigned index) {
return cast<SILPackType>(type).getElementType(index);
}
static CanType getAnyCanPackElementType(CanType type, unsigned index) {
if (isa<PackType>(type)) {
return getCanPackElementType(type, index);
}
return getCanSILPackElementType(type, index);
}
AbstractionPattern
AbstractionPattern::getPackElementType(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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ClangType:
case Kind::Tuple:
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("not a pack type");
case Kind::Opaque:
return *this;
case Kind::Discard:
llvm_unreachable("operation not needed on discarded abstractions yet");
case Kind::Type:
if (isTypeParameterOrOpaqueArchetype())
return AbstractionPattern::getOpaque();
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
getAnyCanPackElementType(getType(), index));
}
llvm_unreachable("bad kind");
}
bool AbstractionPattern::matchesPack(CanPackType substType) 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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::Tuple:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::ClangType:
return false;
case Kind::Opaque:
return true;
case Kind::Type:
case Kind::Discard: {
if (isTypeParameterOrOpaqueArchetype())
return true;
auto type = getType();
if (auto pack = dyn_cast<PackType>(type))
return (pack->getNumElements() == substType->getNumElements());
return false;
}
}
llvm_unreachable("bad kind");
}
void AbstractionPattern::forEachPackElement(CanPackType substType,
llvm::function_ref<void(PackElementGenerator &)> handleElement) const {
PackElementGenerator elt(*this, substType);
for (; !elt.isFinished(); elt.advance()) {
handleElement(elt);
}
elt.finish();
}
void AbstractionPattern::forEachExpandedPackElement(CanPackType substPackType,
llvm::function_ref<void(AbstractionPattern origEltType,
CanType substEltType)>
handleElement) const {
assert(matchesPack(substPackType));
auto substEltTypes = substPackType.getElementTypes();
// Handle opaque patterns by just iterating the substituted components.
if (!isPack()) {
for (auto i : indices(substEltTypes)) {
handleElement(getPackElementType(i), substEltTypes[i]);
}
return;
}
// For non-opaque patterns, we have to iterate the original components
// in order to match things up properly, but we'll still end up calling
// once per substituted element.
size_t substEltIndex = 0;
for (size_t origEltIndex : range(getNumPackElements())) {
auto origEltType = getPackElementType(origEltIndex);
if (!origEltType.isPackExpansion()) {
handleElement(origEltType, substEltTypes[substEltIndex]);
substEltIndex++;
} else {
auto origPatternType = origEltType.getPackExpansionPatternType();
for (auto i : range(origEltType.getNumPackExpandedComponents())) {
(void) i;
auto substEltType = substEltTypes[substEltIndex];
// When the substituted type is a pack expansion, pass down
// the original element type so that it's *also* a pack expansion.
// Clients expect to look through this structure in parallel on
// both types. The count is misleading, but normal usage won't
// access it, and there's nothing we could provide that *wouldn't*
// be misleading in one way or another.
handleElement(isa<PackExpansionType>(substEltType)
? origEltType : origPatternType,
substEltType);
substEltIndex++;
}
}
}
assert(substEltIndex == substEltTypes.size());
}
PackElementGenerator::PackElementGenerator(
AbstractionPattern origPackType,
CanPackType substPackType)
: origPackType(origPackType), substPackType(substPackType) {
assert(origPackType.isPack());
assert(origPackType.matchesPack(substPackType));
numOrigElts = origPackType.getNumPackElements();
if (!isFinished()) loadElement();
}
AbstractionPattern
AbstractionPattern::getPackExpansionComponentType(CanType substType) const {
return getPackExpansionComponentType(isa<PackExpansionType>(substType));
}
AbstractionPattern
AbstractionPattern::getPackExpansionComponentType(bool isExpansion) const {
assert(isPackExpansion());
return isExpansion ? *this : getPackExpansionPatternType();
}
static CanType getPackExpansionPatternType(CanType type) {
return cast<PackExpansionType>(type).getPatternType();
}
AbstractionPattern AbstractionPattern::getPackExpansionPatternType() 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::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::ClangType:
llvm_unreachable("pattern for function or tuple cannot be for "
"pack expansion type");
case Kind::Opaque:
return *this;
case Kind::Type:
if (isTypeParameterOrOpaqueArchetype())
return AbstractionPattern::getOpaque();
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
::getPackExpansionPatternType(getType()));
case Kind::Discard:
return AbstractionPattern::getDiscard(
getGenericSubstitutions(), getGenericSignature(),
::getPackExpansionPatternType(getType()));
}
llvm_unreachable("bad kind");
}
static CanType getPackExpansionCountType(CanType type) {
return cast<PackExpansionType>(type).getCountType();
}
AbstractionPattern AbstractionPattern::getPackExpansionCountType() 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::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::ClangType:
llvm_unreachable("pattern for function or tuple cannot be for "
"pack expansion type");
case Kind::Opaque:
return *this;
case Kind::Type:
if (isTypeParameterOrOpaqueArchetype())
return AbstractionPattern::getOpaque();
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
::getPackExpansionCountType(getType()));
case Kind::Discard:
return AbstractionPattern::getDiscard(
getGenericSubstitutions(), getGenericSignature(),
::getPackExpansionCountType(getType()));
}
llvm_unreachable("bad kind");
}
size_t AbstractionPattern::getNumPackExpandedComponents() const {
assert(isPackExpansion());
assert(getKind() == Kind::Type || getKind() == Kind::Discard);
// If we don't have substitutions, we should be walking parallel
// structure; take a single element.
if (!GenericSubs) return 1;
// Otherwise, substitute the expansion shape.
auto origExpansion = cast<PackExpansionType>(getType());
auto substShape = cast<PackType>(
origExpansion.getCountType().subst(GenericSubs)->getCanonicalType());
return substShape->getNumElements();
}
AbstractionPattern AbstractionPattern::getMetatypeInstanceType() const {
assert(getKind() == Kind::Type);
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
cast<AnyMetatypeType>(getType()).getInstanceType());
}
AbstractionPattern AbstractionPattern::getDynamicSelfSelfType() const {
assert(getKind() == Kind::Type);
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
cast<DynamicSelfType>(getType()).getSelfType());
}
AbstractionPattern
AbstractionPattern::getProtocolCompositionMemberType(unsigned argIndex) const {
assert(getKind() == Kind::Type);
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
cast<ProtocolCompositionType>(getType()).getMembers()[argIndex]);
}
AbstractionPattern
AbstractionPattern::getParameterizedProtocolArgType(unsigned argIndex) const {
assert(getKind() == Kind::Type);
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
cast<ParameterizedProtocolType>(getType()).getArgs()[argIndex]);
}
AbstractionPattern AbstractionPattern::removingMoveOnlyWrapper() 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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("function types can not be move only");
case Kind::ClangType:
llvm_unreachable("clang types can not be move only yet");
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("not handled yet");
case Kind::Discard:
llvm_unreachable("operation not needed on discarded abstractions yet");
case Kind::Tuple:
llvm_unreachable("cannot apply move-only wrappers to open-coded patterns");
case Kind::Opaque:
// Opaque is opaque. We do not remove anything.
return *this;
case Kind::Type:
if (auto mvi = dyn_cast<SILMoveOnlyWrappedType>(getType())) {
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(), mvi->getInnerType());
}
return *this;
}
llvm_unreachable("bad kind");
}
AbstractionPattern AbstractionPattern::addingMoveOnlyWrapper() 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::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("function types can not be move only");
case Kind::ClangType:
llvm_unreachable("clang types can not be move only yet");
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("not handled yet");
case Kind::Discard:
llvm_unreachable("operation not needed on discarded abstractions yet");
case Kind::Tuple:
llvm_unreachable("cannot add move only wrapper to open-coded pattern");
case Kind::Opaque:
case Kind::Type:
if (isa<SILMoveOnlyWrappedType>(getType()))
return *this;
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
SILMoveOnlyWrappedType::get(getType()));
}
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(getGenericSubstitutions(),
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(getGenericSubstitutions(),
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(
getGenericSubstitutions(),
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(getGenericSubstitutions(),
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(
getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(), selfType);
}
static CanType getResultType(CanType type, bool withoutYields) {
auto aft = cast<AnyFunctionType>(type);
if (withoutYields)
aft = CanAnyFunctionType(aft->getWithoutYields());
return aft.getResult();
}
AbstractionPattern AbstractionPattern::getFunctionResultType(bool withoutYields) 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(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields));
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(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
clangFunctionType->getReturnType().getTypePtr());
}
case Kind::CXXMethodType:
case Kind::PartialCurriedCXXMethodType:
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
getCXXMethod()->getReturnType().getTypePtr());
case Kind::CurriedObjCMethodType:
return getPartialCurriedObjCMethod(
getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
getObjCMethod(),
getEncodedForeignInfo());
case Kind::CurriedCFunctionAsMethodType:
return getPartialCurriedCFunctionAsMethod(
getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
getClangType(),
getImportAsMemberStatus());
case Kind::CurriedCXXMethodType:
return getPartialCurriedCXXMethod(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
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<clang::FunctionProtoType>();
// The result comprises the non-error argument(s) to the callback, if
// any.
auto callbackErrorIndex = getEncodedForeignInfo()
.getAsyncCompletionHandlerErrorParamIndex();
auto callbackErrorFlagIndex = getEncodedForeignInfo()
.getAsyncCompletionHandlerErrorFlagParamIndex();
assert((!callbackErrorIndex.has_value()
|| callbackParamTy->getNumParams() > *callbackErrorIndex)
&& "completion handler has invalid error param index?!");
assert((!callbackErrorFlagIndex.has_value()
|| callbackParamTy->getNumParams() > *callbackErrorFlagIndex)
&& "completion handler has invalid error param index?!");
unsigned numNonErrorParams
= callbackParamTy->getNumParams() - callbackErrorIndex.has_value()
- callbackErrorFlagIndex.has_value();
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;
for (auto index : indices(callbackParamTy->getParamTypes())) {
if (callbackErrorIndex && index == *callbackErrorIndex)
continue;
if (callbackErrorFlagIndex && index == *callbackErrorFlagIndex)
continue;
callbackResultIndex = index;
break;
}
auto clangResultType = callbackParamTy
->getParamType(callbackResultIndex)
.getTypePtr();
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
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(
getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
callbackParamTy,
getEncodedForeignInfo());
}
}
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
getResultType(getType(), withoutYields),
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");
}
std::optional<AbstractionPattern>
AbstractionPattern::getFunctionThrownErrorType() 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 getOpaque();
if (auto errorType = cast<AnyFunctionType>(getType())->getEffectiveThrownErrorType()) {
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
(*errorType)->getCanonicalType());
}
return std::nullopt;
}
case Kind::Discard:
llvm_unreachable("don't need to discard function abstractions yet");
case Kind::ClangType:
case Kind::CFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CurriedObjCMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
llvm_unreachable("implement me");
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return std::nullopt;
}
llvm_unreachable("bad kind");
}
std::optional<std::pair<AbstractionPattern, CanType>>
AbstractionPattern::getFunctionThrownErrorType(
CanAnyFunctionType substFnInterfaceType) const {
auto optOrigErrorType = getFunctionThrownErrorType();
if (!optOrigErrorType)
return std::nullopt;
auto substErrorType = substFnInterfaceType->getEffectiveThrownErrorType();
if (isTypeParameterOrOpaqueArchetype()) {
if (!substErrorType)
return std::nullopt;
// FIXME: This is actually unsound. The most opaque form of
// `(T) throws(U) -> V` should actually be
// `(T) throws(any Error) -> V`.
auto pattern = ((*substErrorType)->isErrorExistentialType()
? AbstractionPattern(*substErrorType)
: AbstractionPattern::getOpaque());
return std::make_pair(pattern,
(*substErrorType)->getCanonicalType());
}
if (!substErrorType) {
substErrorType = optOrigErrorType->getEffectiveThrownErrorType();
}
return std::make_pair(*optOrigErrorType,
(*substErrorType)->getCanonicalType());
}
CanType AbstractionPattern::getEffectiveThrownErrorType() const {
CanType type = getType();
if (type->hasTypeParameter())
return type->getASTContext().getNeverType()->getCanonicalType();
return type;
}
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<GenericFunctionType>(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::CurriedObjCMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::CurriedCXXMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
swift_unreachable("not appropriate for this kind");
}
llvm_unreachable("covered switch");
}
CanType AbstractionPattern::getObjCMethodAsyncCompletionHandlerForeignType(
ForeignAsyncConvention convention,
Lowering::TypeConverter &TC
) const {
auto nativeCHTy = convention.completionHandlerType();
// Use the abstraction pattern we're lowering against in order to lower
// the completion handler type, so we can preserve C/ObjC distinctions that
// normally get abstracted away by the importer.
auto completionHandlerNativeOrigTy = getObjCMethodAsyncCompletionHandlerType(nativeCHTy);
// Bridge the Swift completion handler type back to its
// foreign representation.
auto foreignCHTy = TC.getLoweredBridgedType(completionHandlerNativeOrigTy,
nativeCHTy,
Bridgeability::Full,
SILFunctionTypeRepresentation::ObjCMethod,
TypeConverter::ForArgument)
->getCanonicalType();
return foreignCHTy;
}
unsigned AbstractionPattern::getLoweredParamIndex(unsigned formalIndex) const {
switch (getKind()) {
// In the most general abstraction pattern, tuple parameters are
// not expanded, so the lowered parameter index matches the formal
// index.
case Kind::Opaque:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return formalIndex;
case Kind::Type: {
// Total the flattened value count of the parameters prior to the
// given formal index.
unsigned loweredIndex = 0;
for (auto i : range(formalIndex)) {
loweredIndex += getFunctionParamType(i).getFlattenedValueCount();
}
return loweredIndex;
}
default:
// FIXME: to implement this, we'd need to adjust for the implicit
// rearrangement and hidden arguments that we can get from import.
// It's definitely doable, but it's currently unnecessary given the
// limited situations in which we use this method. I'm very sorry
// if you hit this time bomb.
llvm_unreachable("not yet implemented");
}
}
unsigned AbstractionPattern::getFlattenedValueCount() const {
// The count is always 1 unless the original type is a tuple.
if (!isTuple())
return 1;
// Add up the elements.
unsigned count = 0;
for (auto elt : getTupleElementTypes()) {
// Expansion components turn into a single pack parameter.
if (elt.isPackExpansion()) {
count++;
// Recursively expand scalar components.
} else {
count += elt.getFlattenedValueCount();
}
}
return count;
}
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(getGenericSubstitutions(),
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::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::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(getGenericSubstitutions(),
getGenericSignatureForFunctionComponent(),
paramType,
method->parameters()[paramIndex]->getType().getTypePtr());
}
case Kind::ClangType: {
auto params = cast<AnyFunctionType>(getType()).getParams();
return AbstractionPattern(getGenericSubstitutions(),
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");
}
}
ParameterTypeFlags
AbstractionPattern::getFunctionParamFlags(unsigned index) const {
return cast<AnyFunctionType>(getType()).getParams()[index]
.getParameterFlags();
}
bool
AbstractionPattern::isFunctionParamAddressable(unsigned index) const {
switch (getKind()) {
case Kind::Invalid:
case Kind::Tuple:
llvm_unreachable("not any kind of function!");
case Kind::Opaque:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
// If the function abstraction pattern is completely opaque, assume we
// may need to preserve the address for dependencies.
return false;
case Kind::ClangType:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::Type:
case Kind::Discard: {
auto type = getType();
if (type->isTypeParameter() || type->is<ArchetypeType>()) {
return false;
}
auto fnTy = cast<AnyFunctionType>(getType());
// The parameter might directly be marked addressable.
return fnTy.getParams()[index].getParameterFlags().isAddressable();
}
}
llvm_unreachable("bad kind");
}
ArrayRef<LifetimeDependenceInfo>
AbstractionPattern::getLifetimeDependencies() const {
switch (getKind()) {
case Kind::Invalid:
case Kind::Tuple:
llvm_unreachable("not any kind of function!");
case Kind::Opaque:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
// If the function abstraction pattern is completely opaque, assume we
// may need to preserve the address for dependencies.
return {};
case Kind::ClangType:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::Type:
case Kind::Discard: {
auto type = getType();
if (type->isTypeParameter() || type->is<ArchetypeType>()) {
return {};
}
auto fnTy = cast<AnyFunctionType>(getType());
return fnTy->getExtInfo().getLifetimeDependencies();
}
}
llvm_unreachable("bad kind");
}
unsigned AbstractionPattern::getNumFunctionParams() const {
return cast<AnyFunctionType>(getType()).getParams().size();
}
void AbstractionPattern::
forEachFunctionParam(AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalOrigParam,
llvm::function_ref<void(FunctionParamGenerator &param)> function) const {
FunctionParamGenerator generator(*this, substParams, ignoreFinalOrigParam);
for (; !generator.isFinished(); generator.advance()) {
function(generator);
}
generator.finish();
}
FunctionParamGenerator::FunctionParamGenerator(
AbstractionPattern origFunctionType,
AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalOrigParam)
: origFunctionType(origFunctionType), allSubstParams(substParams) {
origFunctionTypeIsOpaque =
(origFunctionType.isTypeParameterOrOpaqueArchetype() ||
origFunctionType.isOpaqueFunctionOrOpaqueDerivativeFunction());
if (origFunctionTypeIsOpaque) {
numOrigParams = allSubstParams.size();
} else {
numOrigParams = origFunctionType.getNumFunctionParams();
if (ignoreFinalOrigParam)
numOrigParams--;
}
if (!isFinished()) loadParameter();
}
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::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(getGenericSubstitutions(),
getGenericSignature(),
::getOptionalObjectType(getType()));
case Kind::Discard:
return AbstractionPattern::getDiscard(getGenericSubstitutions(),
getGenericSignature(),
::getOptionalObjectType(getType()));
case Kind::ClangType:
// This is not reflected in clang types.
return AbstractionPattern(getGenericSubstitutions(),
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::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ObjCCompletionHandlerArgumentsType:
return *this;
case Kind::Type:
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
getType().getReferenceStorageReferent());
case Kind::Discard:
return AbstractionPattern::getDiscard(getGenericSubstitutions(),
getGenericSignature(),
getType().getReferenceStorageReferent());
case Kind::ClangType:
// This is not reflected in clang types.
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
getType().getReferenceStorageReferent(),
getClangType());
}
llvm_unreachable("bad kind");
}
static CanType getExistentialConstraintType(CanType type) {
assert(type.isExistentialType());
if (auto *ET = type->getAs<ExistentialType>()) {
return CanType(ET->getConstraintType());
}
return type;
}
AbstractionPattern AbstractionPattern::getExistentialConstraintType() 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::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(getGenericSubstitutions(),
getGenericSignature(),
::getExistentialConstraintType(getType()));
case Kind::Discard:
return AbstractionPattern::getDiscard(
getGenericSubstitutions(), getGenericSignature(),
::getExistentialConstraintType(getType()));
case Kind::ClangType:
// This is not reflected in clang types.
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
::getExistentialConstraintType(getType()),
getClangType());
}
llvm_unreachable("bad kind");
}
void AbstractionPattern::dump() const {
print(llvm::errs());
llvm::errs() << "\n";
}
static void printGenerics(raw_ostream &out, const AbstractionPattern &pattern) {
if (auto sig = pattern.getGenericSignature()) {
sig->print(out);
}
// It'd be really nice if we could get these interleaved with the types.
if (auto subs = pattern.getGenericSubstitutions()) {
out << "@<";
bool first = true;
for (auto sub : subs.getReplacementTypes()) {
if (!first) {
out << ",";
} else {
first = false;
}
out << sub;
}
out << ">";
}
}
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>>");
printGenerics(out, *this);
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(");
printGenerics(out, *this);
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:
out << (getKind() == Kind::CXXMethodType
? "AP::CXXMethodType(" :
getKind() == Kind::CurriedCXXMethodType
? "AP::CurriedCXXMethodType("
: "AP::PartialCurriedCXXMethodType");
printGenerics(out, *this);
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<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,
SubstitutionMap subMap)
const {
assert(origMemberInterfaceType);
if (isTypeParameterOrOpaqueArchetype()) {
// Fall back to the generic abstraction pattern for the member.
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
return AbstractionPattern(subMap, sig.getCanonicalSignature(),
origMemberInterfaceType);
}
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::ClangType:
case Kind::Type:
case Kind::Discard:
auto memberTy = getType()->getTypeOfMember(
member, origMemberInterfaceType)
->getReducedType(getGenericSignature());
return AbstractionPattern(getGenericSubstitutions(),
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->getReducedType(getGenericSignature()));
}
case Kind::Opaque:
return getOpaqueDerivativeFunction();
default:
llvm_unreachable("called on unsupported abstraction pattern kind");
}
}
AbstractionPattern::CallingConventionKind
AbstractionPattern::getResultConvention(TypeConverter &TC) const {
// Tuples should be destructured.
if (isTuple()) {
return Destructured;
}
switch (getKind()) {
case Kind::Opaque:
// Maximally abstracted values are always passed indirectly.
return Indirect;
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
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:
// Function types are always passed directly
return Direct;
case Kind::ClangType:
case Kind::Type:
case Kind::Discard:
// Pass according to the formal type.
return SILType::isFormallyReturnedIndirectly(getType(),
TC,
getGenericSignatureOrNull())
? Indirect : Direct;
case Kind::Invalid:
case Kind::Tuple:
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("should not get here");
}
}
AbstractionPattern::CallingConventionKind
AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
// Tuples should be destructured.
if (isTuple()) {
return Destructured;
}
switch (getKind()) {
case Kind::Opaque:
// Maximally abstracted values are always passed indirectly.
return Indirect;
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
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:
// Function types are always passed directly
return Direct;
case Kind::ClangType:
case Kind::Type:
case Kind::Discard:
// Pass according to the formal type.
return SILType::isFormallyPassedIndirectly(getType(),
TC,
getGenericSignatureOrNull())
? Indirect : Direct;
case Kind::Invalid:
case Kind::Tuple:
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("should not get here");
}
}
AbstractionPattern::CallingConventionKind
AbstractionPattern::getErrorConvention(TypeConverter &TC) const {
switch (getKind()) {
case Kind::Opaque:
// Maximally abstracted values are always thrown indirectly.
return Indirect;
case Kind::ClangType:
case Kind::Type:
case Kind::Discard:
// Pass according to the formal type.
return SILType::isFormallyThrownIndirectly(getType(),
TC,
getGenericSignatureOrNull())
? Indirect : Direct;
case Kind::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
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::Invalid:
case Kind::ObjCCompletionHandlerArgumentsType:
llvm_unreachable("should not get here");
}
}
bool AbstractionPattern::arePackElementsPassedIndirectly(TypeConverter &TC) const {
assert(getKind() == Kind::Type && isa<PackExpansionType>(getType()));
// It makes sense to pass classes, metatypes, and similar sorts of
// types using direct packs. At the other end of the spectrum, we
// definitely shouldn't pass types directly in packs if it's
// address-only and we'd need to do a non-trivial operation to move
// the value in and out of the pack. There's also a size component
// to this analysis --- we shouldn't pass packs of enormous address-only
// structs directly --- and unfortunately we don't have that
// information at this point.
//
// The simplest thing to do is to just not use direct packs for now,
// but we should revisit that before locking down the ABI.
return true;
}
bool
AbstractionPattern::operator==(const AbstractionPattern &other) const {
if (TheKind != other.TheKind)
return false;
switch (getKind()) {
case Kind::Opaque:
case Kind::Invalid:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
// No additional info to compare.
return true;
case Kind::Tuple:
if (getNumTupleElements() != other.getNumTupleElements()) {
return false;
}
for (unsigned i = 0; i < getNumTupleElements(); ++i) {
if (getTupleElementType(i) != other.getTupleElementType(i)) {
return false;
}
}
return true;
case Kind::Type:
case Kind::Discard:
return OrigType == other.OrigType
&& GenericSig == other.GenericSig;
case Kind::ClangType:
return OrigType == other.OrigType
&& GenericSig == other.GenericSig
&& ClangType == other.ClangType;
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
return OrigType == other.OrigType
&& GenericSig == other.GenericSig
&& ClangType == other.ClangType
&& OtherData == other.OtherData;
case Kind::ObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
return OrigType == other.OrigType
&& GenericSig == other.GenericSig
&& ObjCMethod == other.ObjCMethod
&& OtherData == other.OtherData;
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
return OrigType == other.OrigType
&& GenericSig == other.GenericSig
&& CXXMethod == other.CXXMethod
&& OtherData == other.OtherData;
}
}
namespace {
class SubstFunctionTypePatternVisitor
: public CanTypeVisitor<SubstFunctionTypePatternVisitor, CanType,
AbstractionPattern>
{
public:
TypeConverter &TC;
SmallVector<GenericTypeParamType *, 2> substGenericParams;
SmallVector<Requirement, 2> substRequirements;
SmallVector<Type, 2> substReplacementTypes;
CanType substYieldType;
unsigned packExpansionLevel;
bool &unimplementable;
SubstFunctionTypePatternVisitor(TypeConverter &TC, bool &unimplementable)
: TC(TC), packExpansionLevel(0), unimplementable(unimplementable) {}
// Creates and returns a fresh type parameter in the substituted generic
// signature if `pattern` is a type parameter or opaque archetype. Returns
// null otherwise.
CanType handleTypeParameter(AbstractionPattern pattern, CanType substTy,
unsigned level) {
if (!pattern.isTypeParameterOrOpaqueArchetype())
return CanType();
unsigned paramIndex = substGenericParams.size();
bool withinExpansion = (level < packExpansionLevel);
// Pack parameters that aren't within expansions should just be
// abstracted as scalars.
bool isParameterPack = (withinExpansion && pattern.isTypeParameterPack());
auto paramKind = GenericTypeParamKind::Type;
if (isParameterPack) {
paramKind = GenericTypeParamKind::Pack;
}
auto gp = GenericTypeParamType::get(paramKind, /*depth=*/0, paramIndex,
/*weight=*/0, /*valueType=*/Type(),
TC.Context);
substGenericParams.push_back(gp);
CanType replacement;
if (withinExpansion) {
// If we're within an expansion, and there are substitutions in the
// abstraction pattern, use those instead of substTy. substTy is not
// contextually meaningful in this case; see handlePackExpansion.
if (auto subs = pattern.getGenericSubstitutions()) {
replacement = pattern.getType().subst(subs)->getCanonicalType();
// If we don't have substitutions, but we're abstracting a pack
// parameter, assume that we're lowering a function type using
// itself as its pattern or something like. The substituted type
// should be `each T` for some pack reference; wrap that in a pack.
} else if (isParameterPack) {
replacement = CanPackType::getSingletonPackExpansion(substTy);
// Otherwise, just use substTy.
} else {
replacement = substTy;
}
// Otherwise, we can just use substTy.
} else {
assert(!isParameterPack);
assert(!isa<PackType>(substTy));
replacement = substTy;
}
substReplacementTypes.push_back(replacement);
if (auto layout = pattern.getLayoutConstraint()) {
// Look at the layout constraint on this position in the abstraction pattern
// and carry it over, with some generalization to the point it affects
// calling convention.
// TODO: We should do this once we surface more interesting layout
// constraints in the language. There are several places in type lowering
// that need to be changed to allow for this and generate correct calling
// convention lowering.
#if WE_MAKE_LAYOUT_CONSTRAINTS_AVAILABLE_IN_THE_SURFACE_LANGUAGE
switch (layout->getKind()) {
// Keep these layout constraints as is.
case LayoutConstraintKind::RefCountedObject:
case LayoutConstraintKind::TrivialOfAtMostSize:
case LayoutConstraintKind::BridgeObject:
case LayoutConstraintKind::TrivialStride:
break;
case LayoutConstraintKind::UnknownLayout:
case LayoutConstraintKind::Trivial:
// These constraints don't really constrain the ABI, so we can
// eliminate them.
layout = LayoutConstraint();
break;
// Replace these specific constraints with one of the more general
// constraints above.
case LayoutConstraintKind::NativeClass:
case LayoutConstraintKind::Class:
case LayoutConstraintKind::NativeRefCountedObject:
// These can all be generalized to RefCountedObject.
layout = LayoutConstraint::getLayoutConstraint(
LayoutConstraintKind::RefCountedObject);
break;
case LayoutConstraintKind::TrivialOfExactSize:
// Generalize to TrivialOfAtMostSize.
layout = LayoutConstraint::getLayoutConstraint(
LayoutConstraintKind::TrivialOfAtMostSize,
layout->getTrivialSizeInBits(),
layout->getAlignmentInBits(),
C);
break;
}
#endif
if (layout) {
substRequirements.push_back(
Requirement(RequirementKind::Layout, gp, layout));
}
}
if (level > 0)
return CanType(PackElementType::get(gp, level));
return CanType(gp);
}
CanType visit(CanType t, AbstractionPattern pattern) {
unsigned level = 0;
if (auto elementType = dyn_cast<PackElementType>(t)) {
level = elementType->getLevel();
t = elementType.getPackType();
pattern = pattern.getPackElementPackType();
}
if (auto gp = handleTypeParameter(pattern, t, level))
return gp;
if (pattern.isTuple())
return visitTuplePattern(t, pattern);
return CanTypeVisitor::visit(t, pattern);
}
CanType visitType(CanType t, AbstractionPattern pattern) {
assert(pattern.getType()->isExistentialType() ||
(!pattern.getType()->hasTypeParameter()
&& !pattern.getType()->hasArchetype()
&& !pattern.getType()->hasOpaqueArchetype()));
return pattern.getType();
}
CanType visitDynamicSelfType(CanDynamicSelfType dst,
AbstractionPattern pattern) {
// A "dynamic self" type can be bound to another dynamic self type, or the
// non-dynamic base class type.
if (isa<DynamicSelfType>(pattern.getType())) {
auto origSelf = pattern.getDynamicSelfSelfType();
auto newBase = visit(dst.getSelfType(), origSelf);
return DynamicSelfType::get(newBase, TC.Context)
->getCanonicalType();
}
return visit(dst.getSelfType(), pattern);
}
CanType visitAnyMetatypeType(CanAnyMetatypeType mt, AbstractionPattern pattern){
auto substInstance = visit(mt.getInstanceType(),
pattern.getMetatypeInstanceType());
// The CanType cast is required for this to type-check because
// C++'s ?: operator doesn't look for common superclasses.
return isa<ExistentialMetatypeType>(mt)
? CanExistentialMetatypeType::get(substInstance)
: CanType(CanMetatypeType::get(substInstance));
}
CanType handleGenericNominalType(AbstractionPattern origPattern, CanType subst) {
CanType orig = origPattern.getType();
CanGenericSignature origSig = origPattern.getGenericSignatureOrNull();
auto origPatternSubs = origPattern.getGenericSubstitutions();
// If there are no loose type parameters in the pattern here, we don't need
// to do a recursive visit at all.
if (!orig->hasTypeParameter()
&& !orig->hasArchetype()
&& !orig->hasOpaqueArchetype()) {
return subst;
}
// If the substituted type is a subclass of the abstraction pattern
// type, use the substituted type for the abstraction pattern. This only
// comes up when lowering override types for vtable entries.
auto getDifferentBaseClass = [](Type substInstance, Type origInstance) -> ClassDecl* {
if (auto dynA = substInstance->getAs<DynamicSelfType>()) {
substInstance = dynA->getSelfType();
}
if (auto dynB = origInstance->getAs<DynamicSelfType>()) {
origInstance = dynB->getSelfType();
}
if (auto aClass = substInstance->getClassOrBoundGenericClass()) {
if (auto bClass = origInstance->getClassOrBoundGenericClass()) {
if (aClass != bClass) {
return bClass;
}
}
}
return nullptr;
};
// Both instance and class methods can be overridden; check for metatype
// subtyping too.
ClassDecl *differentOrigClass = getDifferentBaseClass(subst, orig);
if (!differentOrigClass) {
if (auto substMeta = subst->getAs<MetatypeType>()) {
if (auto origMeta = dyn_cast<MetatypeType>(orig)) {
differentOrigClass = getDifferentBaseClass(substMeta->getInstanceType(),
origMeta->getInstanceType());
}
}
}
if (differentOrigClass) {
orig = subst;
origSig = TC.getCurGenericSignature();
origPatternSubs = SubstitutionMap();
assert((!subst->hasTypeParameter() || origSig) &&
"lowering mismatched interface types in a context without "
"a generic signature");
}
auto decl = orig->getAnyNominal();
auto origSubMap = orig->getContextSubstitutionMap(decl);
auto substSubMap = subst->getContextSubstitutionMap(decl);
auto nomGenericSig = decl->getGenericSignature();
SmallVector<Type, 2> replacementTypes;
for (auto gp : nomGenericSig.getGenericParams()) {
auto origParamTy = Type(gp).subst(origSubMap)
->getCanonicalType();
auto substParamTy = Type(gp).subst(substSubMap)
->getCanonicalType();
replacementTypes.push_back(
visit(substParamTy,
AbstractionPattern(origPatternSubs, origSig, origParamTy)));
}
auto newSubMap = SubstitutionMap::get(nomGenericSig, replacementTypes,
LookUpConformanceInModule());
for (auto reqt : nomGenericSig.getRequirements()) {
// Skip conformance requirements to Copyable and Escapable.
if (reqt.getKind() == RequirementKind::Conformance &&
reqt.getProtocolDecl()->getInvertibleProtocolKind()) {
continue;
}
substRequirements.push_back(reqt.subst(newSubMap));
}
return decl->getDeclaredInterfaceType().subst(newSubMap)->getCanonicalType();
}
CanType visitNominalType(CanNominalType nom, AbstractionPattern pattern) {
auto nomDecl = nom->getDecl();
// If the type is generic (because it's a nested type in a generic context),
// process the generic type bindings.
if (!isa<ProtocolDecl>(nomDecl) && nomDecl->isGenericContext()) {
return handleGenericNominalType(pattern, nom);
}
// Otherwise, there are no structural type parameters to visit.
return nom;
}
CanType visitBuiltinGenericType(CanBuiltinGenericType bga,
AbstractionPattern pattern) {
auto orig = pattern.getAs<BuiltinGenericType>();
// If there are no loose type parameters in the pattern here, we don't need
// to do a recursive visit at all.
if (!orig->hasTypeParameter()
&& !orig->hasArchetype()
&& !orig->hasOpaqueArchetype()) {
return bga;
}
SmallVector<Type, 2> newReplacements;
for (unsigned i : indices(bga->getSubstitutions().getReplacementTypes())) {
CanType newReplacement
= visit(CanType(bga->getSubstitutions().getReplacementTypes()[i]),
AbstractionPattern(pattern.getGenericSubstitutions(),
pattern.getGenericSignatureOrNull(),
CanType(orig->getSubstitutions().getReplacementTypes()[i])));
newReplacements.push_back(newReplacement);
}
// TODO: handle conformances. no generic builtins currently have protocol
// requirements.
auto newSubs = SubstitutionMap::get(bga->getGenericSignature(),
newReplacements,
ArrayRef<ProtocolConformanceRef>{});
return bga->getWithSubstitutions(newSubs);
}
CanType visitBoundGenericType(CanBoundGenericType bgt,
AbstractionPattern pattern) {
return handleGenericNominalType(pattern, bgt);
}
CanType visitPackType(CanPackType pack, AbstractionPattern pattern) {
assert(pattern.isPack());
// Break down the pack.
SmallVector<CanType, 4> packElts;
pattern.forEachPackElement(pack, [&](PackElementGenerator &elt) {
auto substEltTypes = elt.getSubstTypes();
CanType eltTy;
if (!elt.isOrigPackExpansion()) {
eltTy = visit(substEltTypes[0], elt.getOrigType());
} else {
CanType candidateSubstType;
if (!substEltTypes.empty())
candidateSubstType = substEltTypes[0];
eltTy = handlePackExpansion(elt.getOrigType(), candidateSubstType);
}
packElts.push_back(eltTy);
});
return CanPackType::get(TC.Context, packElts);
}
CanType visitPackExpansionType(CanPackExpansionType pack,
AbstractionPattern pattern) {
llvm_unreachable("shouldn't encounter pack expansion by itself");
}
CanType visitPackElementType(CanPackElementType packElement,
AbstractionPattern pattern) {
llvm_unreachable("shouldn't encounter pack element by itself");
}
CanType handlePackExpansion(AbstractionPattern origExpansion,
CanType candidateSubstType) {
// When we're within a pack expansion, pack references matching that
// expansion should be abstracted as packs. The substitution will be
// the pack substitution for that parameter recorded in the pattern.
// Remember that we're within an expansion.
++packExpansionLevel;
SWIFT_DEFER {
--packExpansionLevel;
};
auto origPatternType = origExpansion.getPackExpansionPatternType();
// We only really need a subst type here if we don't have
// substitutions in the pattern, because handleTypeParameter
// will always those substitutions within an expansion if
// they're available. And if we don't have substitutions in the
// pattern, we can't map the pack expansion to a concrete set
// of expanded components, so we should have exactly one subst
// type.
CanType substPatternType;
if (origExpansion.getGenericSubstitutions()) {
substPatternType = origPatternType.getType();
} else {
assert(candidateSubstType);
substPatternType =
cast<PackExpansionType>(candidateSubstType).getPatternType();
}
// Recursively visit the pattern type.
auto patternTy = visit(substPatternType, origPatternType);
// If the pattern contains a pack parameter, use that as the count type.
CanType countParam;
patternTy->walkPackReferences([&](Type t) {
if (t->isTypeParameter()) {
auto param = t->getRootGenericParam();
if (param->isParameterPack()) {
countParam = CanType(param);
return true;
}
}
return false;
});
// If the pattern was fully substituted, substitute the original
// count type and use that instead.
if (!countParam) {
auto origCountType = origExpansion.getPackExpansionCountType();
CanType substCountType;
if (origExpansion.getGenericSubstitutions()) {
substCountType = cast<PackExpansionType>(origExpansion.getType())
.getCountType();
} else {
assert(candidateSubstType);
substCountType =
cast<PackExpansionType>(candidateSubstType).getCountType();
}
countParam = visit(substCountType, origCountType);
}
return CanPackExpansionType::get(patternTy, countParam);
}
CanType visitExistentialType(CanExistentialType exist,
AbstractionPattern pattern) {
// Avoid walking into the constraint type if we can help it.
if (!exist->hasTypeParameter() && !exist->hasArchetype() &&
!exist->hasOpaqueArchetype()) {
return CanType(exist);
}
return CanExistentialType::get(visit(
exist.getConstraintType(), pattern.getExistentialConstraintType()));
}
CanType visitParameterizedProtocolType(CanParameterizedProtocolType ppt,
AbstractionPattern pattern) {
// Recurse into the arguments of the parameterized protocol.
auto origPPT = pattern.getAs<ParameterizedProtocolType>();
if (!origPPT)
return ppt;
SmallVector<Type, 4> substArgs;
for (unsigned i = 0; i < ppt->getArgs().size(); ++i) {
auto argTy = ppt.getArgs()[i];
auto origArgTy = pattern.getParameterizedProtocolArgType(i);
auto substArgTy = visit(argTy, origArgTy);
substArgs.push_back(substArgTy);
}
return CanType(ParameterizedProtocolType::get(
TC.Context, ppt->getBaseType(), substArgs));
}
CanType visitProtocolCompositionType(CanProtocolCompositionType pct,
AbstractionPattern pattern) {
// Recurse into the arguments of the protocol composition.
auto origPCT = pattern.getAs<ProtocolCompositionType>();
if (!origPCT)
return pct;
SmallVector<Type, 4> substMembers;
for (unsigned i = 0; i < pct->getMembers().size(); ++i) {
auto memberTy = CanType(pct->getMembers()[i]);
auto origMemberTy = pattern.getProtocolCompositionMemberType(i);
auto substMemberTy = visit(memberTy, origMemberTy);
substMembers.push_back(substMemberTy);
}
return CanType(ProtocolCompositionType::get(
TC.Context,
substMembers,
pct->getInverses(),
pct->hasExplicitAnyObject()));
}
/// Visit a tuple pattern. Note that, because of vanishing tuples,
/// we can't handle this case by matching a tuple type in the
/// substituted type; we have to check for a tuple pattern in the
/// top-level visit routine.
CanType visitTuplePattern(CanType substType, AbstractionPattern pattern) {
assert(pattern.isTuple());
SmallVector<TupleTypeElt, 4> tupleElts;
pattern.forEachTupleElement(substType, [&](TupleElementGenerator &elt) {
auto substEltTypes = elt.getSubstTypes();
CanType eltTy;
if (!elt.isOrigPackExpansion()) {
eltTy = visit(substEltTypes[0], elt.getOrigType());
} else {
CanType candidateSubstType;
if (!substEltTypes.empty())
candidateSubstType = substEltTypes[0];
eltTy = handlePackExpansion(elt.getOrigType(), candidateSubstType);
}
tupleElts.push_back(elt.getOrigElement().getWithType(eltTy));
});
return CanType(TupleType::get(tupleElts, TC.Context));
}
CanType handleUnabstractedFunctionType(CanAnyFunctionType func,
AbstractionPattern pattern,
CanType yieldType,
AbstractionPattern yieldPattern) {
SmallVector<FunctionType::Param, 4> newParams;
auto addParam = [&](ParameterTypeFlags oldFlags, CanType newType) {
newParams.push_back(FunctionType::Param(
newType, /*label*/ Identifier(), oldFlags.withVariadic(false),
/*internal label*/ Identifier()));
};
pattern.forEachFunctionParam(func.getParams(), /*ignore self*/ false,
[&](FunctionParamGenerator &param) {
if (param.isUnimplementablePackExpansion()) {
unimplementable = true;
// Just ignore it.
} else if (!param.isOrigPackExpansion()) {
auto newParamTy = visit(param.getSubstParams()[0].getParameterType(),
param.getOrigType());
addParam(param.getOrigFlags(), newParamTy);
} else {
auto substParams = param.getSubstParams();
CanType candidateSubstType;
if (!substParams.empty())
candidateSubstType = substParams[0].getParameterType();
auto expansionType =
handlePackExpansion(param.getOrigType(), candidateSubstType);
addParam(param.getOrigFlags(), expansionType);
}
});
if (yieldType)
substYieldType = visit(yieldType, yieldPattern);
CanType newErrorType;
if (auto optPair = pattern.getFunctionThrownErrorType(func)) {
auto errorPattern = optPair->first;
auto errorType = optPair->second;
newErrorType = visit(errorType, errorPattern);
}
auto newResultTy = visit(func->getWithoutYields()->getResult()->getCanonicalType(),
pattern.getFunctionResultType(/* withoutYields */ true));
std::optional<FunctionType::ExtInfo> extInfo;
if (func->hasExtInfo())
extInfo = func->getExtInfo();
if (newErrorType) {
if (!extInfo)
extInfo = FunctionType::ExtInfo();
extInfo = extInfo->withThrows(true, newErrorType);
}
// Yields were substituted separately
if (extInfo)
extInfo = extInfo->withCoroutine(false);
return CanFunctionType::get(FunctionType::CanParamArrayRef(newParams),
newResultTy, extInfo);
}
CanType visitFunctionType(CanFunctionType func,
AbstractionPattern pattern) {
return handleUnabstractedFunctionType(func, pattern,
CanType(),
AbstractionPattern::getInvalid());
}
};
}
std::tuple<AbstractionPattern, SubstitutionMap, AbstractionPattern>
AbstractionPattern::getSubstFunctionTypePattern(CanAnyFunctionType substType,
TypeConverter &TC,
AbstractionPattern origYieldType,
CanType substYieldType,
bool &unimplementable)
const {
// If this abstraction pattern isn't meaningfully generic, then we don't
// need to do any transformation.
if (!isTypeParameterOrOpaqueArchetype()
&& !isOpaqueFunctionOrOpaqueDerivativeFunction()
&& !getType()->hasArchetype()
&& !getType()->hasOpaqueArchetype()
&& !getType()->hasTypeParameter()
&& !isa<GenericFunctionType>(getType())) {
return std::make_tuple(
AbstractionPattern(TC.getCurGenericSignature(), substType),
SubstitutionMap(),
substYieldType
? AbstractionPattern(TC.getCurGenericSignature(), substYieldType)
: AbstractionPattern::getInvalid());
}
SubstFunctionTypePatternVisitor visitor(TC, unimplementable);
auto substTy = visitor.handleUnabstractedFunctionType(substType, *this,
substYieldType,
origYieldType);
auto substSig = buildGenericSignature(TC.Context, GenericSignature(),
std::move(visitor.substGenericParams),
std::move(visitor.substRequirements),
/*allowInverses=*/false)
.getCanonicalSignature();
auto subMap = SubstitutionMap::get(substSig,
[&](SubstitutableType *dependentType) -> Type {
auto index = cast<GenericTypeParamType>(dependentType)->getIndex();
return visitor.substReplacementTypes[index];
}, LookUpConformanceInModule());
auto yieldType = visitor.substYieldType;
if (yieldType)
yieldType = yieldType->getReducedType(substSig);
// Note that we specifically do not want to put subMap in the
// abstraction patterns here, because the types we will be lowering
// against them will not be substituted.
return std::make_tuple(
AbstractionPattern(substSig, substTy->getReducedType(substSig)),
subMap,
yieldType
? AbstractionPattern(substSig, yieldType)
: AbstractionPattern::getInvalid());
}