mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Similarly to how we've always handled parameter types, we now recursively expand tuples in result types and separately determine a result convention for each result. The most important code-generation change here is that indirect results are now returned separately from each other and from any direct results. It is generally far better, when receiving an indirect result, to receive it as an independent result; the caller is much more likely to be able to directly receive the result in the address they want to initialize, rather than having to receive it in temporary memory and then copy parts of it into the target. The most important conceptual change here that clients and producers of SIL must be aware of is the new distinction between a SILFunctionType's *parameters* and its *argument list*. The former is just the formal parameters, derived purely from the parameter types of the original function; indirect results are no longer in this list. The latter includes the indirect result arguments; as always, all the indirect results strictly precede the parameters. Apply instructions and entry block arguments follow the argument list, not the parameter list. A relatively minor change is that there can now be multiple direct results, each with its own result convention. This is a minor change because I've chosen to leave return instructions as taking a single operand and apply instructions as producing a single result; when the type describes multiple results, they are implicitly bound up in a tuple. It might make sense to split these up and allow e.g. return instructions to take a list of operands; however, it's not clear what to do on the caller side, and this would be a major change that can be separated out from this already over-large patch. Unsurprisingly, the most invasive changes here are in SILGen; this requires substantial reworking of both call emission and reabstraction. It also proved important to switch several SILGen operations over to work with RValue instead of ManagedValue, since otherwise they would be forced to spuriously "implode" buffers.
823 lines
29 KiB
C++
823 lines
29 KiB
C++
//===--- AbstractionPattern.h - SIL type abstraction patterns ---*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the AbstractionPattern class, which is used to
|
|
// lower formal AST types into their SIL lowerings.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_ABSTRACTIONPATTERN_H
|
|
#define SWIFT_SIL_ABSTRACTIONPATTERN_H
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Types.h"
|
|
|
|
namespace llvm {
|
|
template <class T> class function_ref;
|
|
}
|
|
|
|
namespace clang {
|
|
class ObjCMethodDecl;
|
|
class Type;
|
|
}
|
|
|
|
namespace swift {
|
|
namespace Lowering {
|
|
|
|
/// A pattern for the abstraction of a value. See the large comment
|
|
/// in SILGenPoly.cpp.
|
|
///
|
|
/// The representation of values in Swift can vary according to how
|
|
/// their type is abstracted: which is to say, according to the pattern
|
|
/// of opaque type variables within their type. The main motivation
|
|
/// here is performance: it would be far easier for types to adopt a
|
|
/// single representation regardless of their abstraction, but this
|
|
/// would force Swift to adopt a very inefficient representation for
|
|
/// abstractable values.
|
|
///
|
|
/// For example, consider the comparison function on Int:
|
|
/// func <(lhs : Int, rhs : Int) -> Bool
|
|
///
|
|
/// This function can be used as an opaque value of type
|
|
/// (Int,Int)->Bool. An optimal representation of values of that type
|
|
/// (ignoring context parameters for the moment) would be a pointer to
|
|
/// a function that takes these two arguments directly in registers and
|
|
/// returns the result directly in a register.
|
|
///
|
|
/// (It's important to remember throughout this discussion that we're
|
|
/// talking about abstract values. There's absolutely nothing that
|
|
/// requires direct uses of the function to follow the same conventions
|
|
/// as abstract uses! A direct use of a declaration --- even one that
|
|
/// implies an indirect call, like a class's instance method ---
|
|
/// provides a concrete specification for exactly how to interact with
|
|
/// value.)
|
|
///
|
|
/// However, that representation is problematic in the presence of
|
|
/// generics. This function could be passed off to any of the following
|
|
/// generic functions:
|
|
/// func foo<T>(f : (T, Int) -> Bool)
|
|
/// func bar<U,V>(f : (U, V) -> Bool)
|
|
/// func baz<W>(f : (Int, Int) -> W)
|
|
///
|
|
/// These generic functions all need to be able to call 'f'. But in
|
|
/// Swift's implementation model, these functions don't have to be
|
|
/// instantiated for different parameter types, which means that (e.g.)
|
|
/// the same 'baz' implementation needs to also be able to work when
|
|
/// W=String. But the optimal way to pass an Int to a function might
|
|
/// well be different from the optimal way to pass a String.
|
|
///
|
|
/// And this runs in both directions: a generic function might return
|
|
/// a function that the caller would like to use as an (Int,Int)->Bool:
|
|
/// func getFalseFunction<T>() -> (T,T)->Bool
|
|
///
|
|
/// There are three ways we can deal with this:
|
|
///
|
|
/// 1. Give all types in Swift a common representation. The generic
|
|
/// implementation can work with both W=String and W=Int because
|
|
/// both of those types have the same (direct) storage representation.
|
|
/// That's pretty clearly not an acceptable sacrifice.
|
|
///
|
|
/// 2. Adopt a most-general representation of function types that is
|
|
/// used for opaque values; for example, all parameters and results
|
|
/// could be passed indirectly. Concrete values must be coerced to
|
|
/// this representation when made abstract. Unfortunately, there
|
|
/// are a lot of obvious situations where this is sub-optimal:
|
|
/// for example, in totally non-generic code that just passes around
|
|
/// a value of type (Int,Int)->Bool. It's particularly bad because
|
|
/// Swift functions take multiple arguments as just a tuple, and that
|
|
/// tuple is usually abstractable: e.g., '<' above could also be
|
|
/// passed to this:
|
|
/// func fred<T>(f : T -> Bool)
|
|
///
|
|
/// 3. Permit the representation of values to vary by abstraction.
|
|
/// Values require coercion when changing abstraction patterns.
|
|
/// For example, the argument to 'fred' would be expected to return
|
|
/// its Bool result directly but take a single T parameter indirectly.
|
|
/// When '<' is passed to this, what must actually be passed is a
|
|
/// thunk that expects a tuple of type (Int,Int) to be stored at
|
|
/// the input address.
|
|
///
|
|
/// There is one major risk with (3): naively implemented, a single
|
|
/// function value which undergoes many coercions could build up a
|
|
/// linear number of re-abstraction thunks. However, this can be
|
|
/// solved dynamically by applying thunks with a runtime function that
|
|
/// can recognize and bypass its own previous handiwork.
|
|
///
|
|
/// There is one major exception to what sub-expressions in a type
|
|
/// expression can be abstracted with type variables: a type substitution
|
|
/// must always be materializable. For example:
|
|
/// func f(inout Int, Int) -> Bool
|
|
/// 'f' cannot be passed to 'foo' above: T=inout Int is not a legal
|
|
/// substitution. Nor can it be passed to 'fred'.
|
|
///
|
|
/// In general, abstraction patterns are derived from some explicit
|
|
/// type expression, such as the written type of a variable or
|
|
/// parameter. This works whenever the expression directly provides
|
|
/// structure for the type in question; for example, when the original
|
|
/// type is (T,Int)->Bool and we are working with an (Int,Int)->Bool
|
|
/// substitution. However, it is inadequate when the expression does
|
|
/// not provide structure at the appropriate level, i.e. when that
|
|
/// level is substituted in: when the original type is merely T. In
|
|
/// these cases, we must devolve to a representation which all legal
|
|
/// substitutors will agree upon. In general, this is the
|
|
/// representation of the type which replaces all materializable
|
|
/// sub-expressions with a fresh type variable.
|
|
///
|
|
/// For example, when applying the substitution
|
|
/// T=(Int,Int)->Bool
|
|
/// values of T are abstracted as if they were of type U->V, i.e.
|
|
/// taking one indirect parameter and returning one indirect result.
|
|
///
|
|
/// But under the substitution
|
|
/// T=(inout Int,Int)->Bool
|
|
/// values of T are abstracted as if they were of type (inout U,V)->W,
|
|
/// i.e. taking one parameter inout, another indirectly, and returning
|
|
/// one indirect result.
|
|
///
|
|
/// An abstraction pattern is represented with an original,
|
|
/// unsubstituted type. The archetypes or generic parameters
|
|
/// naturally fall at exactly the specified abstraction points.
|
|
class AbstractionPattern {
|
|
enum class Kind {
|
|
/// A type reference. OrigType is valid.
|
|
Type,
|
|
/// An invalid pattern.
|
|
Invalid,
|
|
/// A completely opaque abstraction pattern.
|
|
Opaque,
|
|
/// An open-coded tuple pattern. OrigTupleElements is valid.
|
|
/// OtherData is the number of tuple elements.
|
|
Tuple,
|
|
/// A type reference with a Clang type. OrigType and ClangType are valid.
|
|
ClangType,
|
|
/// A reference to the parameters of a Clang function type,
|
|
/// imported as a tuple type. OrigType is valid and is a tuple
|
|
/// type. ClangType is valid and is a function type, a function
|
|
/// pointer type, or a block pointer type.
|
|
ClangFunctionParamTupleType,
|
|
/// The curried imported type of an Objective-C method (that is,
|
|
/// 'Self -> Input -> Result'). OrigType is valid and is a function
|
|
/// type. ObjCMethod is valid. OtherData is an encoded foreign
|
|
/// error index.
|
|
CurriedObjCMethodType,
|
|
/// The partially-applied curried imported type of an Objective-C
|
|
/// method (that is, 'Input -> Result'). OrigType is valid and is a
|
|
/// function type. ObjCMethod is valid. OtherData is an encoded
|
|
/// foreign error index.
|
|
PartialCurriedObjCMethodType,
|
|
/// The uncurried imported type of an Objective-C method (that is,
|
|
/// '(Input, Self) -> Result'). OrigType is valid and is a function
|
|
/// type. ObjCMethod is valid. OtherData is an encoded foreign
|
|
/// error index.
|
|
ObjCMethodType,
|
|
/// A reference to the uncurried parameters of a Clang Objective-C
|
|
/// method type, imported as a tuple type (that is, '(Input,
|
|
/// Self'). OrigType is valid and is a tuple type with two
|
|
/// elements. ObjCMethod is valid. OtherData is an encoded
|
|
/// foreign error index.
|
|
ObjCMethodParamTupleType,
|
|
/// A reference to the formal parameters of a Clang Objective-C
|
|
/// method type when they were imported as a tuple type (that is,
|
|
/// 'Input', if it's a tuple type). OrigType is valid and is a
|
|
/// tuple type. ObjCMethod is valid. OtherData is an encoded
|
|
/// foreign error index.
|
|
ObjCMethodFormalParamTupleType,
|
|
};
|
|
|
|
class EncodedForeignErrorInfo {
|
|
unsigned Value;
|
|
|
|
public:
|
|
EncodedForeignErrorInfo() : Value(0) {}
|
|
EncodedForeignErrorInfo(unsigned errorParameterIndex,
|
|
bool replaceParamWithVoid,
|
|
bool stripsResultOptionality)
|
|
: Value(1 +
|
|
(unsigned(stripsResultOptionality)) +
|
|
(unsigned(replaceParamWithVoid) << 1) +
|
|
(errorParameterIndex << 2)) {}
|
|
|
|
static EncodedForeignErrorInfo
|
|
encode(const Optional<ForeignErrorConvention> &foreignError);
|
|
|
|
bool hasValue() const { return Value != 0; }
|
|
bool hasErrorParameter() const { return hasValue(); }
|
|
bool hasUnreplacedErrorParameter() const {
|
|
return hasValue() && !isErrorParameterReplacedWithVoid();
|
|
}
|
|
|
|
bool stripsResultOptionality() const {
|
|
assert(hasValue());
|
|
return (Value - 1) & 1;
|
|
}
|
|
|
|
bool isErrorParameterReplacedWithVoid() const {
|
|
assert(hasValue());
|
|
return (Value - 1) & 2;
|
|
}
|
|
|
|
unsigned getErrorParameterIndex() const {
|
|
assert(hasValue());
|
|
return (Value - 1) >> 2;
|
|
}
|
|
|
|
unsigned getOpaqueValue() const { return Value; }
|
|
static EncodedForeignErrorInfo fromOpaqueValue(unsigned value) {
|
|
EncodedForeignErrorInfo result;
|
|
result.Value = value;
|
|
return result;
|
|
}
|
|
};
|
|
|
|
unsigned TheKind : 4;
|
|
unsigned OtherData : 28;
|
|
CanType OrigType;
|
|
union {
|
|
const clang::Type *ClangType;
|
|
const clang::ObjCMethodDecl *ObjCMethod;
|
|
const AbstractionPattern *OrigTupleElements;
|
|
};
|
|
CanGenericSignature GenericSig;
|
|
|
|
Kind getKind() const { return Kind(TheKind); }
|
|
|
|
CanGenericSignature getGenericSignatureForFunctionComponent() const {
|
|
if (auto genericFn = dyn_cast<GenericFunctionType>(getType())) {
|
|
return genericFn.getGenericSignature();
|
|
} else {
|
|
return getGenericSignature();
|
|
}
|
|
}
|
|
|
|
unsigned getNumTupleElements_Stored() const {
|
|
assert(getKind() == Kind::Tuple);
|
|
return OtherData;
|
|
}
|
|
|
|
bool hasStoredClangType() const {
|
|
return (getKind() == Kind::ClangType ||
|
|
getKind() == Kind::ClangFunctionParamTupleType);
|
|
}
|
|
|
|
bool hasStoredObjCMethod() const {
|
|
return (getKind() == Kind::CurriedObjCMethodType ||
|
|
getKind() == Kind::PartialCurriedObjCMethodType ||
|
|
getKind() == Kind::ObjCMethodType ||
|
|
getKind() == Kind::ObjCMethodParamTupleType ||
|
|
getKind() == Kind::ObjCMethodFormalParamTupleType);
|
|
}
|
|
|
|
bool hasStoredForeignErrorInfo() const {
|
|
return hasStoredObjCMethod();
|
|
}
|
|
|
|
void initSwiftType(CanGenericSignature signature, CanType origType,
|
|
Kind kind = Kind::Type) {
|
|
assert(signature || !origType->hasTypeParameter());
|
|
TheKind = unsigned(kind);
|
|
OrigType = origType;
|
|
GenericSig = CanGenericSignature();
|
|
if (origType->hasTypeParameter())
|
|
GenericSig = signature;
|
|
}
|
|
|
|
void initClangType(CanGenericSignature signature,
|
|
CanType origType, const clang::Type *clangType,
|
|
Kind kind = Kind::ClangType) {
|
|
initSwiftType(signature, origType, kind);
|
|
ClangType = clangType;
|
|
}
|
|
|
|
void initObjCMethod(CanGenericSignature signature,
|
|
CanType origType, const clang::ObjCMethodDecl *method,
|
|
Kind kind, EncodedForeignErrorInfo errorInfo) {
|
|
initSwiftType(signature, origType, kind);
|
|
ObjCMethod = method;
|
|
OtherData = errorInfo.getOpaqueValue();
|
|
}
|
|
|
|
AbstractionPattern() {}
|
|
explicit AbstractionPattern(Kind kind) : TheKind(unsigned(kind)) {}
|
|
|
|
public:
|
|
explicit AbstractionPattern(Type origType)
|
|
: AbstractionPattern(origType->getCanonicalType()) {}
|
|
explicit AbstractionPattern(CanType origType)
|
|
: AbstractionPattern(nullptr, origType) {}
|
|
explicit AbstractionPattern(CanGenericSignature signature, CanType origType) {
|
|
initSwiftType(signature, origType);
|
|
}
|
|
explicit AbstractionPattern(CanType origType, const clang::Type *clangType)
|
|
: AbstractionPattern(nullptr, origType, clangType) {}
|
|
explicit AbstractionPattern(CanGenericSignature signature, CanType origType,
|
|
const clang::Type *clangType) {
|
|
initClangType(signature, origType, clangType);
|
|
}
|
|
|
|
static AbstractionPattern getOpaque() {
|
|
return AbstractionPattern(Kind::Opaque);
|
|
}
|
|
|
|
static AbstractionPattern getInvalid() {
|
|
return AbstractionPattern(Kind::Invalid);
|
|
}
|
|
|
|
bool hasGenericSignature() const {
|
|
return (getKind() == Kind::Type ||
|
|
hasStoredClangType() ||
|
|
hasStoredObjCMethod());
|
|
}
|
|
|
|
CanGenericSignature getGenericSignature() const {
|
|
assert(getKind() == Kind::Type ||
|
|
hasStoredClangType() ||
|
|
hasStoredObjCMethod());
|
|
return CanGenericSignature(GenericSig);
|
|
}
|
|
|
|
/// Return an open-coded abstraction pattern for a tuple. The
|
|
/// caller is responsible for ensuring that the storage for the
|
|
/// tuple elements is valid for as long as the abstraction pattern is.
|
|
static AbstractionPattern getTuple(ArrayRef<AbstractionPattern> tuple) {
|
|
AbstractionPattern pattern(Kind::Tuple);
|
|
pattern.OtherData = tuple.size();
|
|
pattern.OrigTupleElements = tuple.data();
|
|
return pattern;
|
|
}
|
|
|
|
private:
|
|
/// Return an abstraction pattern for a tuple representing all the
|
|
/// parameters to a C or block function.
|
|
static AbstractionPattern
|
|
getClangFunctionParamTuple(CanGenericSignature signature, CanType origType,
|
|
const clang::Type *clangType) {
|
|
assert(isa<TupleType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initClangType(signature, origType, clangType,
|
|
Kind::ClangFunctionParamTupleType);
|
|
return pattern;
|
|
}
|
|
|
|
public:
|
|
/// Return an abstraction pattern for the curried type of an
|
|
/// Objective-C method.
|
|
static AbstractionPattern
|
|
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError);
|
|
|
|
private:
|
|
/// Return an abstraction pattern for the curried type of an
|
|
/// Objective-C method.
|
|
static AbstractionPattern
|
|
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
|
|
EncodedForeignErrorInfo errorInfo) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(nullptr, origType, method,
|
|
Kind::CurriedObjCMethodType, errorInfo);
|
|
return pattern;
|
|
}
|
|
|
|
/// Return an abstraction pattern for the partially-applied curried
|
|
/// type of an Objective-C method.
|
|
static AbstractionPattern
|
|
getPartialCurriedObjCMethod(CanGenericSignature signature,
|
|
CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
EncodedForeignErrorInfo errorInfo) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(signature, origType, method,
|
|
Kind::PartialCurriedObjCMethodType, errorInfo);
|
|
return pattern;
|
|
}
|
|
|
|
public:
|
|
/// Return an abstraction pattern for the type of an Objective-C method.
|
|
static AbstractionPattern
|
|
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
|
|
const Optional<ForeignErrorConvention> &foreignError);
|
|
|
|
private:
|
|
/// Return an abstraction pattern for the uncurried type of an
|
|
/// Objective-C method.
|
|
static AbstractionPattern
|
|
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
|
|
EncodedForeignErrorInfo errorInfo) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(nullptr, origType, method, Kind::ObjCMethodType,
|
|
errorInfo);
|
|
return pattern;
|
|
}
|
|
|
|
/// Return an abstraction pattern for a tuple representing the
|
|
/// uncurried parameter clauses of an Objective-C method.
|
|
static AbstractionPattern
|
|
getObjCMethodParamTuple(CanGenericSignature signature, CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
EncodedForeignErrorInfo errorInfo) {
|
|
assert(isa<TupleType>(origType));
|
|
assert(cast<TupleType>(origType)->getNumElements() == 2);
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(signature, origType, method,
|
|
Kind::ObjCMethodParamTupleType, errorInfo);
|
|
return pattern;
|
|
}
|
|
|
|
/// Return a pattern correspond to the 'self' parameter of the
|
|
/// current Objective-C method.
|
|
AbstractionPattern getObjCMethodSelfPattern(CanType paramType) const;
|
|
|
|
/// Return a pattern correspond to the formal parameters of the
|
|
/// current Objective-C method.
|
|
AbstractionPattern getObjCMethodFormalParamPattern(CanType paramType) const;
|
|
|
|
/// Return an abstraction pattern for a tuple representing the
|
|
/// formal parameters to an Objective-C method.
|
|
static AbstractionPattern
|
|
getObjCMethodFormalParamTuple(CanGenericSignature signature, CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
EncodedForeignErrorInfo errorInfo) {
|
|
assert(isa<TupleType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(signature, origType, method,
|
|
Kind::ObjCMethodFormalParamTupleType, errorInfo);
|
|
return pattern;
|
|
}
|
|
|
|
public:
|
|
/// Return an abstraction pattern with an added level of optionality.
|
|
///
|
|
/// The based abstraction pattern must be either opaque or based on
|
|
/// a Clang or Swift type. That is, it cannot be a tuple or an ObjC
|
|
/// method type.
|
|
static AbstractionPattern getOptional(AbstractionPattern objectPattern,
|
|
OptionalTypeKind optionalKind);
|
|
|
|
/// Does this abstraction pattern have something that can be used as a key?
|
|
bool hasCachingKey() const {
|
|
// Only the simplest Kind::Type pattern has a caching key; we
|
|
// don't want to try to unique by Clang node.
|
|
return getKind() == Kind::Type || getKind() == Kind::Opaque;
|
|
}
|
|
using CachingKey = CanType;
|
|
CachingKey getCachingKey() const {
|
|
assert(hasCachingKey());
|
|
return OrigType;
|
|
}
|
|
|
|
bool isValid() const {
|
|
return getKind() != Kind::Invalid;
|
|
}
|
|
|
|
bool isTypeParameter() const {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return true;
|
|
case Kind::Type: {
|
|
auto type = getType();
|
|
if (isa<ArchetypeType>(type) ||
|
|
isa<DependentMemberType>(type) ||
|
|
isa<AbstractTypeParamType>(type)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Is this an interface type that is subject to a concrete
|
|
/// same-type constraint?
|
|
bool isConcreteType(ModuleDecl &module) const {
|
|
assert(isTypeParameter());
|
|
return (getKind() != Kind::Opaque &&
|
|
GenericSig != nullptr &&
|
|
GenericSig->isConcreteType(getType(), module));
|
|
}
|
|
|
|
bool requiresClass(ModuleDecl &module) {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return false;
|
|
case Kind::Type: {
|
|
auto type = getType();
|
|
if (auto archetype = dyn_cast<ArchetypeType>(type))
|
|
return archetype->requiresClass();
|
|
else if (isa<DependentMemberType>(type) ||
|
|
isa<AbstractTypeParamType>(type)) {
|
|
assert(GenericSig &&
|
|
"Dependent type in pattern without generic signature?");
|
|
return GenericSig->requiresClass(type, module);
|
|
}
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Return the Swift type which provides structure for this
|
|
/// abstraction pattern.
|
|
///
|
|
/// This is always valid unless the pattern is opaque or an
|
|
/// open-coded tuple. However, it does not always fully describe
|
|
/// the abstraction pattern.
|
|
CanType getType() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
llvm_unreachable("opaque pattern has no type");
|
|
case Kind::Tuple:
|
|
llvm_unreachable("open-coded tuple pattern has no type");
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::Type:
|
|
return OrigType;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Return whether this abstraction pattern contains foreign type
|
|
/// information.
|
|
///
|
|
/// In general, after eliminating tuples, a foreign abstraction
|
|
/// pattern will satisfy either isClangType() or isObjCMethod().
|
|
bool isForeign() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::Tuple:
|
|
case Kind::Type:
|
|
return false;
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Return whether this abstraction pattern represents a Clang type.
|
|
/// If so, it is legal to return getClangType().
|
|
bool isClangType() const {
|
|
return (getKind() == Kind::ClangType);
|
|
}
|
|
|
|
const clang::Type *getClangType() const {
|
|
assert(hasStoredClangType());
|
|
return ClangType;
|
|
}
|
|
|
|
/// Return whether this abstraction pattern represents an
|
|
/// Objective-C method. If so, it is legal to call getObjCMethod().
|
|
bool isObjCMethod() const {
|
|
return (getKind() == Kind::ObjCMethodType ||
|
|
getKind() == Kind::CurriedObjCMethodType);
|
|
}
|
|
|
|
const clang::ObjCMethodDecl *getObjCMethod() const {
|
|
assert(hasStoredObjCMethod());
|
|
return ObjCMethod;
|
|
}
|
|
|
|
EncodedForeignErrorInfo getEncodedForeignErrorInfo() const {
|
|
assert(hasStoredForeignErrorInfo());
|
|
return EncodedForeignErrorInfo::fromOpaqueValue(OtherData);
|
|
}
|
|
|
|
bool hasForeignErrorStrippingResultOptionality() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Tuple:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
llvm_unreachable("querying foreign-error bits on non-function pattern");
|
|
|
|
case Kind::Opaque:
|
|
case Kind::ClangType:
|
|
case Kind::Type:
|
|
return false;
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType: {
|
|
auto errorInfo = getEncodedForeignErrorInfo();
|
|
return (errorInfo.hasValue() && errorInfo.stripsResultOptionality());
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
template<typename TYPE>
|
|
typename CanTypeWrapperTraits<TYPE>::type
|
|
getAs() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
return typename CanTypeWrapperTraits<TYPE>::type();
|
|
case Kind::Tuple:
|
|
return typename CanTypeWrapperTraits<TYPE>::type();
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
case Kind::Type:
|
|
return dyn_cast<TYPE>(getType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Is this pattern the exact given type?
|
|
///
|
|
/// This is only useful for avoiding redundant work at compile time;
|
|
/// code should be prepared to do the right thing in the face of a slight
|
|
/// mismatch. This may happen for any number of reasons.
|
|
bool isExactType(CanType type) const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::Tuple:
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
// We assume that the Clang type might provide additional structure.
|
|
return false;
|
|
case Kind::Type:
|
|
return getType() == type;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern transformType(llvm::function_ref<CanType(CanType)>) const;
|
|
|
|
/// Is the given tuple type a valid substitution of this abstraction
|
|
/// pattern?
|
|
bool matchesTuple(CanTupleType substType);
|
|
|
|
bool isTuple() {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
return false;
|
|
case Kind::Tuple:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
return true;
|
|
case Kind::Type:
|
|
case Kind::ClangType:
|
|
return isa<TupleType>(getType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
size_t getNumTupleElements() const {
|
|
switch (getKind()) {
|
|
case Kind::Invalid:
|
|
llvm_unreachable("querying invalid abstraction pattern!");
|
|
case Kind::Opaque:
|
|
case Kind::PartialCurriedObjCMethodType:
|
|
case Kind::CurriedObjCMethodType:
|
|
case Kind::ObjCMethodType:
|
|
llvm_unreachable("pattern is not a tuple");
|
|
case Kind::Tuple:
|
|
return getNumTupleElements_Stored();
|
|
case Kind::Type:
|
|
case Kind::ClangType:
|
|
case Kind::ClangFunctionParamTupleType:
|
|
case Kind::ObjCMethodParamTupleType:
|
|
case Kind::ObjCMethodFormalParamTupleType:
|
|
return cast<TupleType>(getType())->getNumElements();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
AbstractionPattern dropLastTupleElement() const;
|
|
|
|
class TupleElementRange;
|
|
|
|
/// Return a range over the tuple elements.
|
|
TupleElementRange getTupleElements() const;
|
|
|
|
/// Given that the value being abstracted is a tuple type, return
|
|
/// the abstraction pattern for its object type.
|
|
AbstractionPattern getTupleElementType(unsigned index) const;
|
|
|
|
/// Given that the value being abstracted is an l-value type, return
|
|
/// the abstraction pattern for its object type.
|
|
AbstractionPattern getLValueObjectType() const;
|
|
|
|
/// Given that the value being abstracted is a function, return the
|
|
/// abstraction pattern for its result type.
|
|
AbstractionPattern getFunctionResultType() const;
|
|
|
|
/// Given that the value being abstracted is a function, return the
|
|
/// abstraction pattern for its input type.
|
|
AbstractionPattern getFunctionInputType() const;
|
|
|
|
/// Given that the value being abstracted is optional, return the
|
|
/// abstraction pattern for its object type.
|
|
AbstractionPattern getAnyOptionalObjectType() const;
|
|
|
|
/// If this pattern refers to a reference storage type, look through
|
|
/// it.
|
|
AbstractionPattern getReferenceStorageReferentType() const;
|
|
|
|
void dump() const LLVM_ATTRIBUTE_USED;
|
|
void print(raw_ostream &OS) const;
|
|
};
|
|
|
|
/// A range of abstraction patterns for the tuple elements of an
|
|
/// abstraction pattern.
|
|
class AbstractionPattern::TupleElementRange {
|
|
AbstractionPattern Parent;
|
|
unsigned NumElements;
|
|
public:
|
|
TupleElementRange(AbstractionPattern parent, unsigned numElements)
|
|
: Parent(parent), NumElements(numElements) {}
|
|
|
|
struct iterator {
|
|
const TupleElementRange *Range;
|
|
unsigned Index;
|
|
|
|
AbstractionPattern operator*() const {
|
|
return Range->Parent.getTupleElementType(Index);
|
|
}
|
|
|
|
iterator &operator++() {
|
|
assert(Index < Range->NumElements);
|
|
Index++;
|
|
return *this;
|
|
}
|
|
iterator operator++(int _) {
|
|
iterator saved = *this;
|
|
operator++();
|
|
return saved;
|
|
}
|
|
|
|
bool operator==(const iterator &other) const {
|
|
assert(Range == other.Range);
|
|
return Index == other.Index;
|
|
}
|
|
bool operator!=(const iterator &other) const {
|
|
return !operator==(other);
|
|
}
|
|
};
|
|
|
|
iterator begin() const { return { this, 0 }; }
|
|
iterator end() const { return { this, NumElements }; }
|
|
};
|
|
|
|
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &out,
|
|
const AbstractionPattern &pattern) {
|
|
pattern.print(out);
|
|
return out;
|
|
}
|
|
|
|
inline AbstractionPattern::TupleElementRange
|
|
AbstractionPattern::getTupleElements() const {
|
|
return TupleElementRange(*this, getNumTupleElements());
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|