Files
swift-mirror/lib/Sema/ConstraintSystem.h
Dmitri Hrybenko af8fa8c8cd Remove a circular dependency AST<->Sema caused by type printing
AST used to depend on Sema in type printing.  Specifically,
TypeVariableType::printImpl() is inside Sema.

This change moves the type variable identifier from
TypeVariableType::Implementation to TypeVariableType. This enables us to print
type variables in AST library.

Because type variable type is a temporary type for use inside type checker
only, I don't expect that we will modify it to be more verbose to enhance
diagnostics.  This is a job for locator printing.


Swift SVN r8559
2013-09-23 17:40:43 +00:00

2512 lines
88 KiB
C++

//===--- ConstraintSystem.h - Constraint-based Type Checking --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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 provides the constraint-based type checker, anchored by the
// \c ConstraintSystem class, which provides type checking and type
// inference for expressions.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_CONSTRAINT_SYSTEM_H
#define SWIFT_SEMA_CONSTRAINT_SYSTEM_H
#include "TypeChecker.h"
#include "swift/Basic/Fixnum.h"
#include "swift/Basic/LLVM.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <functional>
namespace swift {
class Expr;
namespace constraints {
class ConstraintSystem;
} // end namespace constraints
} // end namespace swift
/// \brief Allocate memory within the given constraint system.
void *operator new(size_t bytes, swift::constraints::ConstraintSystem& cs,
size_t alignment = 8);
namespace swift {
namespace constraints {
/// \brief A handle that holds the saved state of a type variable, which
/// can be restored.
class SavedTypeVariableBinding {
/// \brief The type variable.
TypeVariableType *TypeVar;
/// \brief The parent or fixed type.
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
/// The options.
unsigned Options;
public:
explicit SavedTypeVariableBinding(TypeVariableType *typeVar);
/// \brief Restore the state of the type variable to the saved state.
void restore();
};
/// \brief A set of saved type variable bindings.
typedef SmallVector<SavedTypeVariableBinding, 16> SavedTypeVariableBindings;
class ConstraintLocator;
} // end namespace constraints
/// Options that describe how a type variable can be used.
enum TypeVariableOptions {
/// Whether the type variable can be bound to an lvalue type or not.
TVO_CanBindToLValue = 0x01,
/// Whether a more specific deduction for this type variable implies a
/// better solution to the constraint system.
TVO_PrefersSubtypeBinding = 0x02
};
/// \brief The implementation object for a type variable used within the
/// constraint-solving type checker.
///
/// The implementation object for a type variable contains information about
/// the type variable, where it was generated, what protocols it must conform
/// to, what specific types it might be and, eventually, the fixed type to
/// which it is assigned.
class TypeVariableType::Implementation {
/// Type variable options.
unsigned Options : 2;
/// \brief The locator that describes where this type variable was generated.
constraints::ConstraintLocator *locator;
/// \brief Either the parent of this type variable within an equivalence
/// class of type variables, or the fixed type to which this type variable
/// type is bound.
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
friend class constraints::SavedTypeVariableBinding;
public:
explicit Implementation(constraints::ConstraintLocator *locator,
unsigned options)
: Options(options), locator(locator),
ParentOrFixed(getTypeVariable()) { }
/// \brief Retrieve the unique ID corresponding to this type variable.
unsigned getID() const { return getTypeVariable()->getID(); }
/// Whether this type variable can bind to an lvalue type.
bool canBindToLValue() const { return Options & TVO_CanBindToLValue; }
/// Whether this type variable prefers a subtype binding over a supertype
/// binding.
bool prefersSubtypeBinding() const {
return Options & TVO_PrefersSubtypeBinding;
}
/// \brief Retrieve the type variable associated with this implementation.
TypeVariableType *getTypeVariable() {
return reinterpret_cast<TypeVariableType *>(this) - 1;
}
/// \brief Retrieve the type variable associated with this implementation.
const TypeVariableType *getTypeVariable() const {
return reinterpret_cast<const TypeVariableType *>(this) - 1;
}
/// \brief Check whether this type variable either has a representative that
/// is not itself or has a fixed type binding.
bool hasRepresentativeOrFixed() const {
// If we have a fixed type, we're done.
if (!ParentOrFixed.is<TypeVariableType *>())
return true;
// Check whether the representatative is different from our own type
// variable.
return ParentOrFixed.get<TypeVariableType *>() != getTypeVariable();
}
/// \brief Record the current type-variable binding.
void recordBinding(constraints::SavedTypeVariableBindings &record) {
record.push_back(constraints::SavedTypeVariableBinding(getTypeVariable()));
}
/// \brief Retrieve the locator describing where this type variable was
/// created.
constraints::ConstraintLocator *getLocator() const {
return locator;
}
/// \brief Retrieve the archetype opened by this type variable.
ArchetypeType *getArchetype() const;
/// \brief Retrieve the representative of the equivalence class to which this
/// type variable belongs.
///
/// \param record The record of changes made by retrieving the representative,
/// which can happen due to path compression. If null, path compression is
/// not performed.
TypeVariableType *
getRepresentative(constraints::SavedTypeVariableBindings *record) {
// Find the representative type variable.
auto result = getTypeVariable();
Implementation *impl = this;
while (impl->ParentOrFixed.is<TypeVariableType *>()) {
// Extract the representative.
auto nextTV = impl->ParentOrFixed.get<TypeVariableType *>();
if (nextTV == result)
break;
result = nextTV;
impl = &nextTV->getImpl();
}
if (impl == this || !record)
return result;
// Perform path compression.
impl = this;
while (impl->ParentOrFixed.is<TypeVariableType *>()) {
// Extract the representative.
auto nextTV = impl->ParentOrFixed.get<TypeVariableType *>();
if (nextTV == result)
break;
// Record the state change.
impl->recordBinding(*record);
impl->ParentOrFixed = result;
impl = &nextTV->getImpl();
}
return result;
}
/// \brief Merge the equivalence class of this type variable with the
/// equivalence class of another type variable.
///
/// \param other The type variable to merge with.
///
/// \param record The record of state changes.
void mergeEquivalenceClasses(TypeVariableType *other,
constraints::SavedTypeVariableBindings *record) {
// Merge the equivalence classes corresponding to these two type
// variables. Always merge 'up' the constraint stack, because it is simpler.
if (getID() < other->getImpl().getID()) {
auto rep = other->getImpl().getRepresentative(record);
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().ParentOrFixed = getTypeVariable();
if (rep->getImpl().prefersSubtypeBinding()) {
auto myRep = getRepresentative(record);
if (record)
myRep->getImpl().recordBinding(*record);
myRep->getImpl().Options|=TVO_PrefersSubtypeBinding;
}
assert(rep->getImpl().canBindToLValue() == canBindToLValue());
} else {
auto rep = getRepresentative(record);
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().ParentOrFixed = other;
if (rep->getImpl().prefersSubtypeBinding()) {
auto otherRep = other->getImpl().getRepresentative(record);
if (record)
otherRep->getImpl().recordBinding(*record);
otherRep->getImpl().Options |= TVO_PrefersSubtypeBinding;
}
assert(rep->getImpl().canBindToLValue()
== other->getImpl().canBindToLValue());
}
}
/// \brief Retrieve the fixed type that corresponds to this type variable,
/// if there is one.
///
/// \returns the fixed type associated with this type variable, or a null
/// type if there is no fixed type.
///
/// \param record The record of changes made by retrieving the representative,
/// which can happen due to path compression. If null, path compression is
/// not performed.
Type getFixedType(constraints::SavedTypeVariableBindings *record) {
// Find the representative type variable.
Implementation *impl = this;
while (impl->ParentOrFixed.is<TypeVariableType *>()) {
auto nextTV = impl->ParentOrFixed.get<TypeVariableType *>();
// If we found the representative, there is no fixed type.
if (nextTV == impl->getTypeVariable()) {
return Type();
}
impl = &nextTV->getImpl();
}
Type result = impl->ParentOrFixed.get<TypeBase *>();
if (impl == this || !record)
return result;
// Perform path compression.
impl = this;
while (impl->ParentOrFixed.is<TypeVariableType *>()) {
// Extract the representative.
auto nextTV = impl->ParentOrFixed.get<TypeVariableType *>();
if (nextTV == impl->getTypeVariable())
return result;
impl->recordBinding(*record);
impl->ParentOrFixed = result.getPointer();
impl = &nextTV->getImpl();
}
return result;
}
/// \brief Assign a fixed type to this equivalence class.
void assignFixedType(Type type,
constraints::SavedTypeVariableBindings *record) {
assert((!getFixedType(0) || getFixedType(0)->isEqual(type)) &&
"Already has a fixed type!");
auto rep = getRepresentative(record);
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().ParentOrFixed = type.getPointer();
}
/// \brief Print the type variable to the given output stream.
void print(llvm::raw_ostream &OS);
};
namespace constraints {
/// \brief Describes the kind of constraint placed on one or more types.
enum class ConstraintKind : char {
/// \brief The two types must be bound to the same type. This is the only
/// truly symmetric constraint.
Bind,
/// \brief The two types must be bound to the same type, dropping
/// lvalueness when comparing a type variable to a type.
Equal,
/// \brief The first type is a "trivial" subtype of the second type,
/// meaning that it is a subtype that is also guaranteed to have the same
/// in-memory representation.
TrivialSubtype,
/// \brief The first type is a subtype of the second type, i.e., a value
/// of the type of the first type can be used wherever a value of the
/// second type is expected.
Subtype,
/// \brief The first type is convertible to the second type.
Conversion,
/// \brief The first type can be converted to the second type or can be
/// used as an argument to a constructor for the second (non-reference)
/// type.
Construction,
/// \brief The first type must conform to the second type (which is a
/// protocol type).
ConformsTo,
/// \brief Both types are function types with the same input and output types.
/// Note, we do not require the function type attributes to match.
ApplicableFunction,
/// \brief The first type has a member with the given name, and the
/// type of that member, when referenced as a value, is the second type.
ValueMember,
/// \brief The first type has a type member with the given name, and the
/// type of that member, when referenced as a type, is the second type.
TypeMember,
/// \brief The first type must be an archetype.
Archetype
};
/// \brief Classification of the different kinds of constraints.
enum class ConstraintClassification : char {
/// \brief A relational constraint, which relates two types.
Relational,
/// \brief A member constraint, which names a member of a type and assigns
/// it a reference type.
Member,
/// \brief An archetype constraint, which simply requires that the type
/// variable be bound to an archetype.
Archetype
};
/// \brief Locates a given constraint within the expression being
/// type-checked, which may refer down into subexpressions and parts of
/// the types of those subexpressions.
///
/// Each locator as anchored at some expression, e.g., (3, (x, 3.14)),
/// and contains a path that digs further into the type of that expression.
/// For example, the path "tuple element #1" -> "tuple element #0" with the
/// above expression would refer to 'x'. If 'x' had function type, the
/// path could be further extended with either "-> argument" or "-> result",
/// to indicate constraints on its argument or result type.
class ConstraintLocator : public llvm::FoldingSetNode {
public:
/// \brief Describes the kind of a a particular path element, e.g.,
/// "tuple element", "call result", "base of member lookup", etc.
enum PathElementKind : unsigned char {
/// \brief The argument of function application.
ApplyArgument,
/// \brief The function being applied.
ApplyFunction,
/// \brief An archetype being opened.
///
/// Also contains the archetype itself.
Archetype,
/// \brief The argument type of a function.
FunctionArgument,
/// \brief The result type of a function.
FunctionResult,
/// \brief A tuple element referenced by position.
TupleElement,
/// \brief A tuple element referenced by name.
NamedTupleElement,
/// \brief A generic argument.
/// FIXME: Add support for named generic arguments?
GenericArgument,
/// \brief A member.
/// FIXME: Do we need the actual member name here?
Member,
/// \brief An unresolved member.
UnresolvedMember,
/// \brief The base of a member expression.
MemberRefBase,
/// \brief The lookup for a subscript member.
SubscriptMember,
/// \brief The index of a subscript expression.
SubscriptIndex,
/// \brief The result of a subscript expression.
SubscriptResult,
/// \brief An argument to string interpolation.
InterpolationArgument,
/// \brief The lookup for a constructor member.
ConstructorMember,
/// \brief Address of subexpression.
AddressOf,
/// \brief Rvalue adjustment.
RvalueAdjustment,
/// \brief The result of a closure.
ClosureResult,
/// \brief The parent of a nested type.
ParentType,
/// \brief The instance of a metatype type.
InstanceType,
/// \brief The element of an array type.
ArrayElementType,
/// \brief The object type of an lvalue type.
LvalueObjectType,
/// \brief The scalar type of a tuple type.
ScalarToTuple,
/// \brief The load of an lvalue.
Load,
/// \brief The lookup for a conversion member.
ConversionMember,
/// \brief The conversion result.
ConversionResult,
/// \brief The 'then' branch of a ternary expression.
IfThen,
/// \brief The 'else' branch of a ternary expression.
IfElse,
/// \brief The source of an assignment.
AssignSource,
/// \brief The destination of an assignment
AssignDest
};
/// \brief Determine whether the given path element kind has an associated
/// value.
static bool pathElementHasNumericValue(PathElementKind kind) {
switch (kind) {
case ApplyArgument:
case ApplyFunction:
case Archetype:
case FunctionArgument:
case FunctionResult:
case Member:
case MemberRefBase:
case UnresolvedMember:
case SubscriptIndex:
case SubscriptMember:
case SubscriptResult:
case ConstructorMember:
case AddressOf:
case RvalueAdjustment:
case ClosureResult:
case ParentType:
case InstanceType:
case ArrayElementType:
case LvalueObjectType:
case ScalarToTuple:
case Load:
case ConversionMember:
case ConversionResult:
case IfThen:
case IfElse:
case AssignSource:
case AssignDest:
return false;
case GenericArgument:
case InterpolationArgument:
case NamedTupleElement:
case TupleElement:
return true;
}
}
template<unsigned N> struct incomplete;
/// \brief One element in the path of a locator, which can include both
/// a kind (PathElementKind) and a value used to describe specific
/// kinds further (e.g., the position of a tuple element).
class PathElement {
/// \brief Describes the kind of data stored here.
enum StoredKind : unsigned char {
StoredArchetype,
StoredKindAndValue
};
/// \brief The type of storage used for a kind and numeric value.
typedef Fixnum<29> KindAndValueStorage;
/// \brief The actual storage for the path element, which involves both a
/// kind and (potentially) a value.
///
/// The current storage involves a two-bit "storage kind", which selects
/// amount the possible value stores. The value stores can either be an
/// archetype (for archetype path elements) or an unsigned value that
/// stores both the specific kind and the (optional) numeric value of that
/// kind. Use \c encodeStorage and \c decodeStorage to work with this value.
llvm::PointerIntPair<llvm::PointerUnion<ArchetypeType *,
KindAndValueStorage>,
2, StoredKind> storage;
/// \brief Encode a path element kind and a value into the storage format.
static KindAndValueStorage encodeStorage(PathElementKind kind, unsigned value) {
unsigned result = (value << 8) | (unsigned)kind;
return result;
}
/// \brief Decode a storage value into path element kind and value.
static std::pair<PathElementKind, unsigned>
decodeStorage(KindAndValueStorage storage) {
return { (PathElementKind)((unsigned)storage & 0xFF), storage >> 8 };
}
PathElement(PathElementKind kind, unsigned value)
: storage(encodeStorage(kind, value), StoredKindAndValue) { }
friend class ConstraintLocator;
public:
PathElement(PathElementKind kind)
: storage(encodeStorage(kind, 0), StoredKindAndValue)
{
assert(!pathElementHasNumericValue(kind) &&"Path element requires value");
}
PathElement(ArchetypeType *archetype)
: storage(archetype, StoredArchetype) { }
/// \brief Retrieve a path element for a tuple element referred to by
/// its position.
static PathElement getTupleElement(unsigned position) {
return PathElement(TupleElement, position);
}
/// \brief Retrieve a path element for a tuple element referred to by
/// its name.
static PathElement getNamedTupleElement(unsigned position) {
return PathElement(NamedTupleElement, position);
}
/// \brief Retrieve a path element for a generic argument referred to by
/// its position.
static PathElement getGenericArgument(unsigned position) {
return PathElement(GenericArgument, position);
}
/// \brief Retrieve a path element for an argument to string
/// interpolation.
static PathElement getInterpolationArgument(unsigned position) {
return PathElement(InterpolationArgument, position);
}
/// \brief Retrieve the kind of path element.
PathElementKind getKind() const {
switch (storage.getInt()) {
case StoredArchetype:
return Archetype;
case StoredKindAndValue:
return decodeStorage(storage.getPointer().get<KindAndValueStorage>())
.first;
}
}
/// \brief Retrieve the value associated with this path element,
/// if it has one.
unsigned getValue() const {
assert(pathElementHasNumericValue(getKind()) &&
"No value in path element!");
return decodeStorage(storage.getPointer().get<KindAndValueStorage>())
.second;
}
/// \brief Retrieve the actual archetype for an archetype path element.
ArchetypeType *getArchetype() const {
assert(getKind() == Archetype && "Not an archetype path element");
return storage.getPointer().get<ArchetypeType *>();
}
};
/// \brief Retrieve the expression that anchors this locator.
Expr *getAnchor() const { return anchor; }
/// \brief Retrieve the path that extends from the anchor to a specific
/// subcomponent.
ArrayRef<PathElement> getPath() const {
// FIXME: Alignment.
return llvm::makeArrayRef(reinterpret_cast<const PathElement *>(this + 1),
numPathElements);
}
/// \brief Determines whether this locator has a "simple" path, without
/// any transformations that break apart types.
bool hasSimplePath() const {
for (auto elt : getPath()) {
switch (elt.getKind()) {
case AddressOf:
case ApplyArgument:
case ApplyFunction:
case ArrayElementType:
case ClosureResult:
case ConstructorMember:
case ConversionMember:
case ConversionResult:
case FunctionArgument:
case FunctionResult:
case InstanceType:
case Load:
case LvalueObjectType:
case Member:
case MemberRefBase:
case UnresolvedMember:
case ParentType:
case RvalueAdjustment:
case ScalarToTuple:
case SubscriptIndex:
case SubscriptMember:
case SubscriptResult:
case IfThen:
case IfElse:
case AssignSource:
case AssignDest:
continue;
case Archetype:
case GenericArgument:
case InterpolationArgument:
case NamedTupleElement:
case TupleElement:
return false;
}
}
return true;
}
/// \brief Produce a profile of this locator, for use in a folding set.
static void Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
ArrayRef<PathElement> path) {
id.AddPointer(anchor);
id.AddInteger(path.size());
for (auto elt : path) {
id.AddInteger(elt.getKind());
if (pathElementHasNumericValue(elt.getKind()))
id.AddInteger(elt.getValue());
else if (elt.getKind() == ConstraintLocator::Archetype)
id.AddPointer(elt.getArchetype()->getCanonicalType().getPointer());
}
}
/// \brief Produce a profile of this locator, for use in a folding set.
void Profile(llvm::FoldingSetNodeID &id) {
Profile(id, anchor, getPath());
}
/// \brief Produce a debugging dump of this locator.
void dump(SourceManager *SM) LLVM_ATTRIBUTE_USED;
private:
/// \brief Initialize a constraint locator with an anchor and a path.
ConstraintLocator(Expr *anchor, ArrayRef<PathElement> path)
: anchor(anchor), numPathElements(path.size()) {
// FIXME: Alignment.
std::copy(path.begin(), path.end(),
reinterpret_cast<PathElement *>(this + 1));
}
/// \brief Create a new locator from an anchor and an array of path
/// elements.
///
/// Note that this routine only handles the allocation and initialization
/// of the locator. The ConstraintSystem object is responsible for
/// uniquing via the FoldingSet.
static ConstraintLocator *create(llvm::BumpPtrAllocator &allocator,
Expr *anchor,
ArrayRef<PathElement> path) {
// FIXME: Alignment.
unsigned size = sizeof(ConstraintLocator)
+ path.size() * sizeof(PathElement);
void *mem = allocator.Allocate(size, alignof(ConstraintLocator));
return new (mem) ConstraintLocator(anchor, path);
}
/// \brief The expression at which this locator is anchored.
Expr *anchor;
/// \brief The number of path elements in this locator.
///
/// The actual path elements are stored after the locator.
unsigned numPathElements;
friend class ConstraintSystem;
};
typedef ConstraintLocator::PathElement LocatorPathElt;
/// \brief A simple stack-only builder object that constructs a
/// constraint locator without allocating memory.
///
/// Use this object to build a path when passing components down the
/// stack, e.g., when recursively breaking apart types as in \c matchTypes().
class ConstraintLocatorBuilder {
/// \brief The constraint locator that this builder extends or the
/// previous builder in the chain.
llvm::PointerUnion<ConstraintLocator *, ConstraintLocatorBuilder *>
previous;
/// \brief The current path element, if there is one.
Optional<LocatorPathElt> element;
ConstraintLocatorBuilder(llvm::PointerUnion<ConstraintLocator *,
ConstraintLocatorBuilder *>
previous,
LocatorPathElt element)
: previous(previous), element(element) { }
public:
ConstraintLocatorBuilder(ConstraintLocator *locator)
: previous(locator), element() { }
/// \brief Retrieve a new path with the given path element added to it.
ConstraintLocatorBuilder withPathElement(LocatorPathElt newElt) {
if (!element)
return ConstraintLocatorBuilder(previous, newElt);
return ConstraintLocatorBuilder(this, newElt);
}
/// \brief Determine whether this builder has an empty path.
bool hasEmptyPath() const {
return !element;
}
/// \brief Retrieve the base constraint locator, on which this builder's
/// path is based.
ConstraintLocator *getBaseLocator() const {
for (auto prev = this;
prev;
prev = prev->previous.dyn_cast<ConstraintLocatorBuilder *>()) {
if (auto locator = prev->previous.dyn_cast<ConstraintLocator *>())
return locator;
}
return nullptr;
}
/// \brief Retrieve the components of the complete locator, which includes
/// the anchor expression and the path.
Expr *getLocatorParts(SmallVectorImpl<LocatorPathElt> &path) const {
for (auto prev = this;
prev;
prev = prev->previous.dyn_cast<ConstraintLocatorBuilder *>()) {
// If there is an element at this level, add it.
if (prev->element)
path.push_back(*prev->element);
if (auto locator = prev->previous.dyn_cast<ConstraintLocator *>()) {
// We found the end of the chain. Reverse the path we've built up,
// then prepend the locator's path.
std::reverse(path.begin(), path.end());
path.insert(path.begin(),
locator->getPath().begin(),
locator->getPath().end());
return locator->getAnchor();
}
}
// We only get here if there was no locator; fail gracefully.
path.clear();
return nullptr;
}
/// Attempt to simplify this locator to a single expression.
Expr *trySimplifyToExpr() const;
};
struct ResolvedOverloadSetListItem;
/// \brief Describes a failure.
class Failure : public llvm::FoldingSetNode {
public:
/// \brief The various kinds of failures that can occur
enum FailureKind {
/// \brief Tuple types with different numbers of elements.
TupleSizeMismatch,
/// \brief Tuple element names mismatch when they need to match.
TupleNameMismatch,
/// \brief Tuple element name matched, but at a different position.
TupleNamePositionMismatch,
/// \brief One tuple type is variadic, the other is not.
TupleVariadicMismatch,
/// \brief Unused element in tuple.
TupleUnused,
/// \brief Autoclosure function type mismatch.
FunctionAutoclosureMismatch,
/// \brief Noreturn attribute function type mismatch.
FunctionNoReturnMismatch,
/// \brief Types are not the same.
TypesNotEqual,
/// \brief Types are not trivial subtypes.
TypesNotTrivialSubtypes,
/// \brief Types are not subtypes.
TypesNotSubtypes,
/// \brief Types are not convertible.
TypesNotConvertible,
/// \brief Types are not constructible.
TypesNotConstructible,
/// \brief Function types mismatch.
FunctionTypesMismatch,
/// \brief Lvalue type qualifiers mismatch.
LValueQualifiers,
/// \brief The first type doesn't conform to a protocol in the second
/// type.
DoesNotConformToProtocol,
/// \brief The first type does not have a member with the given name.
DoesNotHaveMember,
/// \brief The type is not an archetype.
IsNotArchetype,
/// \brief The type is not allowed to be an l-value.
IsForbiddenLValue,
};
private:
/// \brief The kind of failure this describes.
FailureKind kind : 8;
/// \brief A value, if used.
unsigned value : 32;
/// Describes the location of this failure.
ConstraintLocator *locator;
/// The resolved overload sets that led to this failure.
ResolvedOverloadSetListItem *resolvedOverloadSets;
/// \brief The first type.
Type first;
/// \brief The second value, which may be one of several things (type,
/// member name, etc.).
union {
TypeBase *type;
void *name;
} second;
public:
/// \brief Retrieve the failure kind.
FailureKind getKind() const { return kind; }
/// \brief Retrieve the failure locator.
ConstraintLocator *getLocator() const {
return locator;
}
/// Retrieve the resolved overload sets active when this failure occurred.
ResolvedOverloadSetListItem *getResolvedOverloadSets() const {
return resolvedOverloadSets;
}
/// \brief Retrieve the first type.
Type getFirstType() const { return first; }
/// \brief Retrieve the second type.
Type getSecondType() const {
return second.type;
}
/// \brief Retrieve the name.
Identifier getName() const {
return Identifier::getFromOpaquePointer(second.name);
}
/// \brief Retrieve the value.
unsigned getValue() const { return value; }
/// \brief Profile the given failure.
void Profile(llvm::FoldingSetNodeID &id) {
switch (kind) {
case FunctionTypesMismatch:
case FunctionAutoclosureMismatch:
case FunctionNoReturnMismatch:
case LValueQualifiers:
case TupleNameMismatch:
case TupleNamePositionMismatch:
case TupleSizeMismatch:
case TupleUnused:
case TupleVariadicMismatch:
case TypesNotConstructible:
case TypesNotConvertible:
case TypesNotEqual:
case TypesNotSubtypes:
case TypesNotTrivialSubtypes:
case DoesNotConformToProtocol:
case IsForbiddenLValue:
return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(),
getSecondType());
case DoesNotHaveMember:
return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(),
getName());
case IsNotArchetype:
return Profile(id, locator, kind, resolvedOverloadSets, getFirstType());
}
}
/// \brief Dump a debug representation of this failure.
void dump(SourceManager *SM) LLVM_ATTRIBUTE_USED;
private:
friend class ConstraintSystem;
/// \brief Construct a failure involving one type.
Failure(ConstraintLocator *locator, FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type)
: kind(kind), value(0), locator(locator),
resolvedOverloadSets(resolvedOverloadSets), first(type)
{
second.type = nullptr;
}
/// \brief Construct a failure involving two types and an optional value.
Failure(ConstraintLocator *locator, FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type1, Type type2, unsigned value = 0)
: kind(kind), value(value), locator(locator),
resolvedOverloadSets(resolvedOverloadSets), first(type1)
{
second.type = type2.getPointer();
}
/// \brief Construct a failure involving a type and a name.
Failure(ConstraintLocator *locator, FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type, Identifier name)
: kind(kind), value(0), locator(locator),
resolvedOverloadSets(resolvedOverloadSets), first(type)
{
second.name = name.getAsOpaquePointer();
}
/// \brief Profile a failure involving one type.
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type) {
id.AddPointer(locator);
id.AddInteger(kind);
id.AddPointer(resolvedOverloadSets);
id.AddPointer(type.getPointer());
}
/// \brief Profile a failure involving two types.
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type1, Type type2) {
id.AddPointer(locator);
id.AddInteger(kind);
id.AddPointer(resolvedOverloadSets);
id.AddPointer(type1.getPointer());
id.AddPointer(type2.getPointer());
}
/// \brief Profile a failure involving two types and a value.
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type1, Type type2, unsigned value) {
id.AddPointer(locator);
id.AddInteger(kind);
id.AddPointer(resolvedOverloadSets);
id.AddPointer(type1.getPointer());
id.AddPointer(type2.getPointer());
id.AddInteger(value);
}
/// \brief Profile a failure involving a type and a name.
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
FailureKind kind,
ResolvedOverloadSetListItem *resolvedOverloadSets,
Type type, Identifier name) {
id.AddPointer(locator);
id.AddInteger(kind);
id.AddPointer(resolvedOverloadSets);
id.AddPointer(type.getPointer());
id.AddPointer(name.getAsOpaquePointer());
}
/// \brief Create a new Failure object with the given arguments, allocated
/// from the given bump pointer allocator.
template<typename ...Args>
static Failure *create(llvm::BumpPtrAllocator &allocator,
ConstraintLocator *locator, FailureKind kind,
Args &&...args) {
void *mem = allocator.Allocate(sizeof(Failure), alignof(Failure));
return new (mem) Failure(locator, kind, args...);
}
};
/// \brief A constraint between two type variables.
class Constraint {
/// \brief The kind of constraint.
ConstraintKind Kind : 8;
/// \brief The first type.
Type First;
/// \brief The second type.
Type Second;
/// \brief If non-null, the name of a member of the first type is that
/// being related to the second type.
Identifier Member;
/// \brief The locator that describes where in the expression this
/// constraint applies.
ConstraintLocator *Locator;
/// \brief Constraints are always allocated within a given constraint
/// system.
void *operator new(size_t) = delete;
public:
Constraint(ConstraintKind Kind, Type First, Type Second, Identifier Member,
ConstraintLocator *locator)
: Kind(Kind), First(First), Second(Second), Member(Member),
Locator(locator)
{
switch (Kind) {
case ConstraintKind::Bind:
case ConstraintKind::Equal:
case ConstraintKind::TrivialSubtype:
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::Construction:
case ConstraintKind::ConformsTo:
assert(Member.empty() && "Relational constraint cannot have a member");
break;
case ConstraintKind::ApplicableFunction:
assert(First->is<FunctionType>()
&& "The left-hand side type should be a function type");
assert(Member.empty() && "Relational constraint cannot have a member");
break;
case ConstraintKind::TypeMember:
case ConstraintKind::ValueMember:
assert(!Member.empty() && "Member constraint has no member");
break;
case ConstraintKind::Archetype:
assert(Member.empty() && "Archetype constraint cannot have a member");
assert(Second.isNull() && "Archetype constraint with second type");
break;
}
}
/// \brief Determine the kind of constraint.
ConstraintKind getKind() const { return Kind; }
/// \brief Determine the classification of this constraint, providing
/// a broader categorization than \c getKind().
ConstraintClassification getClassification() const {
switch (Kind) {
case ConstraintKind::Bind:
case ConstraintKind::Equal:
case ConstraintKind::TrivialSubtype:
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::Construction:
case ConstraintKind::ConformsTo:
case ConstraintKind::ApplicableFunction:
return ConstraintClassification::Relational;
case ConstraintKind::ValueMember:
case ConstraintKind::TypeMember:
return ConstraintClassification::Member;
case ConstraintKind::Archetype:
return ConstraintClassification::Archetype;
}
}
/// \brief Retrieve the first type in the constraint.
Type getFirstType() const { return First; }
/// \brief Retrieve the second type in the constraint.
Type getSecondType() const {
return Second;
}
/// \brief Retrieve the protocol in a conformance constraint.
ProtocolDecl *getProtocol() const {
assert(Kind==ConstraintKind::ConformsTo && "Not a conformance constraint");
return Second->castTo<ProtocolType>()->getDecl();
}
/// \brief Retrieve the name of the member for a member constraint.
Identifier getMember() const {
assert(Kind == ConstraintKind::ValueMember ||
Kind == ConstraintKind::TypeMember);
return Member;
}
/// \brief Determine whether this constraint kind has a second type.
static bool hasMember(ConstraintKind kind) {
return kind == ConstraintKind::ValueMember
|| kind == ConstraintKind::TypeMember;
}
/// \brief Retrieve the locator for this constraint.
ConstraintLocator *getLocator() const { return Locator; }
void print(llvm::raw_ostream &Out, SourceManager *sm) const;
void dump(SourceManager *SM) const LLVM_ATTRIBUTE_USED;
void *operator new(size_t bytes, ConstraintSystem& cs,
size_t alignment = alignof(Constraint)) {
return ::operator new (bytes, cs, alignment);
}
inline void operator delete(void *, const ConstraintSystem &cs, size_t) {}
};
/// \brief The kind of overload choice.
enum class OverloadChoiceKind : int {
/// \brief The overload choice selects a particular declaration from a
/// set of declarations.
Decl,
/// \brief The overload choice selects a particular declaration that was
/// found via dynamic lookup and, therefore, might not actually be
/// available at runtime.
DeclViaDynamic,
/// \brief The overload choice selects a particular declaration from a
/// set of declarations and treats it as a type.
TypeDecl,
/// \brief The overload choice equates the member type with the
/// base type. Used for unresolved member expressions like ".none" that
/// refer to enum members with unit type.
BaseType,
/// \brief The overload choice equates the member type with a function
/// of arbitrary input type whose result type is the base type. Used for
/// unresolved member expressions like ".internal" that refer to enum
/// members with non-unit type.
FunctionReturningBaseType,
/// \brief The overload choice equates the member type with a function
/// from the base type to itself.
IdentityFunction,
/// \brief The overload choice indexes into a tuple. Index zero will
/// have the value of this enumerator, index one will have the value of this
/// enumerator + 1, and so on. Thus, this enumerator must always be last.
TupleIndex
};
/// \brief Describes a particular choice within an overload set.
///
///
class OverloadChoice {
/// \brief The base type to be used when referencing the declaration
/// along with a bit indicating whether this overload was immediately
/// specialized.
llvm::PointerIntPair<Type, 1, bool> BaseAndSpecialized;
/// \brief Either the declaration pointer (if the low bit is clear) or the
/// overload choice kind shifted by 1 with the low bit set.
uintptr_t DeclOrKind;
public:
OverloadChoice() : BaseAndSpecialized(nullptr, false), DeclOrKind() { }
OverloadChoice(Type base, ValueDecl *value, bool isSpecialized)
: BaseAndSpecialized(base, isSpecialized) {
assert((reinterpret_cast<uintptr_t>(value) & (uintptr_t)0x03) == 0
&& "Badly aligned decl");
DeclOrKind = reinterpret_cast<uintptr_t>(value);
}
OverloadChoice(Type base, TypeDecl *type, bool isSpecialized)
: BaseAndSpecialized(base, isSpecialized) {
assert((reinterpret_cast<uintptr_t>(type) & (uintptr_t)0x03) == 0
&& "Badly aligned decl");
DeclOrKind = reinterpret_cast<uintptr_t>(type) | 0x01;
}
OverloadChoice(Type base, OverloadChoiceKind kind)
: BaseAndSpecialized(base, false),
DeclOrKind((uintptr_t)kind << 2 | (uintptr_t)0x03) {
assert(base && "Must have a base type for overload choice");
assert(kind != OverloadChoiceKind::Decl && "wrong constructor for decl");
}
OverloadChoice(Type base, unsigned index)
: BaseAndSpecialized(base, false),
DeclOrKind(((uintptr_t)index
+ (uintptr_t)OverloadChoiceKind::TupleIndex) << 2
| (uintptr_t)0x03) {
assert(base->getRValueType()->is<TupleType>() && "Must have tuple type");
}
/// Retrieve an overload choice for a declaration that was found via
/// dynamic lookup.
static OverloadChoice getDeclViaDynamic(Type base, ValueDecl *value) {
OverloadChoice result;
result.BaseAndSpecialized.setPointer(base);
result.DeclOrKind = reinterpret_cast<uintptr_t>(value) | 0x02;
return result;
}
/// \brief Retrieve the base type used to refer to the declaration.
Type getBaseType() const { return BaseAndSpecialized.getPointer(); }
/// \brief Determine whether the referenced declaration was immediately
/// specialized with <...>.
///
/// This value only has meaning when there is no base type.
bool isSpecialized() const { return BaseAndSpecialized.getInt(); }
/// \brief Determines the kind of overload choice this is.
OverloadChoiceKind getKind() const {
switch (DeclOrKind & 0x03) {
case 0x00: return OverloadChoiceKind::Decl;
case 0x01: return OverloadChoiceKind::TypeDecl;
case 0x02: return OverloadChoiceKind::DeclViaDynamic;
case 0x03: {
uintptr_t value = DeclOrKind >> 2;
if (value >= (uintptr_t)OverloadChoiceKind::TupleIndex)
return OverloadChoiceKind::TupleIndex;
return (OverloadChoiceKind)value;
}
default: llvm_unreachable("basic math has escaped me");
}
}
/// \brief Retrieve the declaraton that corresponds to this overload choice.
ValueDecl *getDecl() const {
assert((getKind() == OverloadChoiceKind::Decl ||
getKind() == OverloadChoiceKind::DeclViaDynamic ||
getKind() == OverloadChoiceKind::TypeDecl) && "Not a declaration");
return reinterpret_cast<ValueDecl *>(DeclOrKind & ~(uintptr_t)0x03);
}
/// \brief Retrieve the tuple index that corresponds to this overload
/// choice.
unsigned getTupleIndex() const {
assert(getKind() == OverloadChoiceKind::TupleIndex);
return (DeclOrKind >> 2) - (uintptr_t)OverloadChoiceKind::TupleIndex;
}
/// \brief Retrieves an opaque choice that ignores the base type.
void *getOpaqueChoiceSimple() const {
return reinterpret_cast<void*>(DeclOrKind);
}
};
/// \brief An overload set, which is a set of overloading choices from which
/// only one can be selected.
class OverloadSet {
/// \brief ID number that uniquely identifies this overload set.
unsigned ID;
/// \brief The number of choices in the overload set.
unsigned NumChoices;
/// \brief The locator for this overload set.
ConstraintLocator *Locator;
/// \brief The type bound by this overload set.
Type BoundType;
/// \brief Overload sets are always allocated within a given constraint
/// system.
void *operator new(size_t) = delete;
OverloadSet(unsigned ID, ConstraintLocator *locator,
Type boundType, ArrayRef<OverloadChoice> choices)
: ID(ID), NumChoices(choices.size()), Locator(locator),
BoundType(boundType) {
memcpy(this+1, choices.data(), sizeof(OverloadChoice)*choices.size());
}
public:
/// \brief Retrieve the locator that identifies where this overload set
/// same from.
ConstraintLocator *getLocator() const { return Locator; }
/// \brief Retrieve the ID associated with this overload set.
unsigned getID() const { return ID; }
/// \brief Retrieve the set of choices provided by this overload set.
ArrayRef<OverloadChoice> getChoices() const {
return { reinterpret_cast<const OverloadChoice *>(this + 1),
NumChoices };
}
/// \brief Retrieve the type that is bound (via a same-type
/// constraint) by this overload set.
Type getBoundType() const { return BoundType; }
/// \brief Create a new overload set, using (and copying) the given choices.
static OverloadSet *getNew(ConstraintSystem &CS,
Type boundType,
ConstraintLocator *locator,
ArrayRef<OverloadChoice> choices);
};
/// \brief A representative type variable with the list of constraints
/// that apply to it.
struct TypeVariableConstraints {
TypeVariableConstraints(TypeVariableType *typeVar) : TypeVar(typeVar) {}
/// \brief Whether there are any non-concrete constraints placed on this
/// type variable that aren't represented by the stored constraints.
bool HasNonConcreteConstraints = false;
/// \brief Whether this type variable is either fully bound by either an
/// overload set or a member constraint.
bool FullyBound = false;
/// \brief The representative type variable.
TypeVariableType *TypeVar;
/// \brief The set of constraints "above" the type variable.
SmallVector<std::pair<Constraint *, Type>, 4> Above;
/// \brief The set of constraints "below" the type variable.
SmallVector<std::pair<Constraint *, Type>, 4> Below;
/// \brief The set of protocol conformance constraints directly applicable
/// to the type variable.
SmallVector<Constraint *, 4> ConformsToConstraints;
/// \brief The set of archetype constraints directly
/// applicable to the type variable T.
SmallVector<Constraint *, 4> KindConstraints;
};
/// \brief The kind of type matching to perform in matchTypes().
enum class TypeMatchKind : char {
/// \brief Bind the types together directly.
BindType,
/// \brief Require the types to match exactly, but strips lvalueness from
/// a type when binding to a type variable.
SameType,
/// \brief Require the first type to be a "trivial" subtype of the second
/// type or be an exact match.
TrivialSubtype,
/// \brief Require the first type to be a subtype of the second type
/// (or be an exact match or trivial subtype).
Subtype,
/// \brief Requires the first type to be convertible to the second type,
/// which includes exact matches and both forms of subtyping.
Conversion
};
/// \brief The result of comparing two constraint systems that are a solutions
/// to the given set of constraints.
enum class SolutionCompareResult {
/// \brief The two solutions are incomparable, because, e.g., because one
/// solution has some better decisions and some worse decisions than the
/// other.
Incomparable,
/// \brief The two solutions are identical.
Identical,
/// \brief The first solution is better than the second.
Better,
/// \brief The second solution is better than the first.
Worse
};
/// \brief A complete solution to a constraint system.
///
/// A solution to a constraint system consists of type variable bindings to
/// concrete types for every type variable that is used in the constraint
/// system along with a set of mappings from each constraint locator
/// involving an overload set to the selected overload.
class Solution {
/// \brief The constraint system this solution solves.
ConstraintSystem *constraintSystem;
/// \brief The fixed score for this solution.
mutable Optional<int> fixedScore;
public:
/// \brief Create a solution for the given constraint system.
Solution(ConstraintSystem &cs) : constraintSystem(&cs) {}
// Solution is a non-copyable type for performance reasons.
Solution(const Solution &other) = delete;
Solution &operator=(const Solution &other) = delete;
Solution(Solution &&other)
: constraintSystem(other.constraintSystem),
typeBindings(std::move(other.typeBindings)),
overloadChoices(std::move(other.overloadChoices))
{
}
Solution &operator=(Solution &&other) {
constraintSystem = other.constraintSystem;
typeBindings = std::move(other.typeBindings);
overloadChoices = std::move(other.overloadChoices);
return *this;
}
/// \brief Retrieve the constraint system that this solution solves.
ConstraintSystem &getConstraintSystem() const { return *constraintSystem; }
/// \brief The set of type bindings.
llvm::SmallDenseMap<TypeVariableType *, Type> typeBindings;
/// \brief The set of overload choices along with their types.
llvm::SmallDenseMap<ConstraintLocator *,
std::pair<OverloadChoice, Type>> overloadChoices;
/// \brief Simplify the given type by substituting all occurrences of
/// type variables for their fixed types.
Type simplifyType(TypeChecker &tc, Type type) const;
/// \brief Coerce the given expression to the given type.
///
/// This operation cannot fail.
///
/// \param expr The expression to coerce.
/// \param toType The type to coerce the expression to.
/// \param locator Locator used to describe the location of this expression.
///
/// \returns the coerced expression, which will have type \c ToType.
Expr *coerceToType(Expr *expr, Type toType, ConstraintLocator *locator) const;
/// \brief Convert the given expression to a logic value.
///
/// This operation cannot fail.
///
/// \param expr The expression to coerce. The type of this expression
/// must conform to the LogicValue protocol.
///
/// \param locator Locator used to describe the location of this expression.
///
/// \returns the expression converted to a logic value (Builtin i1).
Expr *convertToLogicValue(Expr *expr, ConstraintLocator *locator) const;
/// \brief Convert the given expression to an array bound.
///
/// This operation cannot fail.
///
/// \param expr The expression to coerce. The type of this expression
/// must conform to the ArrayBound protocol.
///
/// \param locator Locator used to describe the location of this expression.
///
/// \returns the expression converted to an array bound (Builtin integral
/// type).
Expr *convertToArrayBound(Expr *expr, ConstraintLocator *locator) const;
/// \brief Generate a specialized instance of a polymorphic expression.
///
/// \param expr The polymorphic expression.
/// \param polyFn The unopened polymorphic type of the expression.
/// \param openedType The opened specialized type to instantiate.
///
/// \returns A SpecializeExpr containing the expression specialized to the
/// opened type.
Expr *specialize(Expr *expr,
PolymorphicFunctionType *polyFn,
Type openedType) const;
/// Compute the set of substitutions required to map the given polymorphic
/// function type to the provided "opened" type.
///
/// \param polyFn The polymorphic function type.
///
/// \param openedType The type to which this reference to the given
/// polymorphic function type was opened.
///
/// \param substitutions Will be populated with the set of substitutions
/// to be applied to the polymorphic function type.
///
/// \returns The opened type after applying the computed substitutions.
Type computeSubstitutions(PolymorphicFunctionType *polyFn,
Type openedType,
SmallVectorImpl<Substitution> &substitutions) const;
/// \brief Retrieve the fixed score of this solution, which considers
/// the number of user-defined conversions.
int getFixedScore() const;
/// \brief Retrieve the fixed type for the given type variable.
Type getFixedType(TypeVariableType *typeVar) const;
/// \brief Dump this solution to standard error.
void dump(SourceManager *SM) const LLVM_ATTRIBUTE_USED;
};
/// \brief Describes the differences between several solutions to the same
/// constraint system.
class SolutionDiff {
public:
/// \brief A difference between two overloads.
struct OverloadDiff {
/// \brief The locator that describes where the overload comes from.
ConstraintLocator *locator;
/// \brief The choices that each solution made.
SmallVector<OverloadChoice, 2> choices;
};
/// \brief A difference between two type variable bindings.
struct TypeBindingDiff {
/// \brief The type variable.
TypeVariableType *typeVar;
/// \brief The bindings that each solution made.
SmallVector<Type, 2> bindings;
};
/// \brief The differences between the overload choices between the
/// solutions.
SmallVector<OverloadDiff, 4> overloads;
/// \brief The differences between the type variable bindings of the
/// solutions.
SmallVector<TypeBindingDiff, 4> typeBindings;
/// \brief Compute the differences between the given set of solutions.
///
/// \param solutions The set of solutions.
explicit SolutionDiff(ArrayRef<Solution> solutions);
};
/// Describes one resolved overload set within the list of overload sets
/// resolved by the solver.
struct ResolvedOverloadSetListItem {
/// The previously resolved overload set in the list.
ResolvedOverloadSetListItem *Previous;
/// The overload set resolved by this item.
OverloadSet *Set;
/// The index of the choice to which the overload set was resolved.
unsigned ChoiceIndex;
/// The type of the referenced choice.
Type ImpliedType;
// Make vanilla new/delete illegal for overload set items.
void *operator new(size_t Bytes) = delete;
void operator delete(void *Data) = delete;
// Only allow allocation of list items using the allocator in the
// constraint system.
void *operator new(size_t bytes, ConstraintSystem &cs,
unsigned alignment
= alignof(ResolvedOverloadSetListItem));
};
/// \brief Describes a system of constraints on type variables, the
/// solution of which assigns concrete types to each of the type variables.
/// Constraint systems are typically generated given an (untyped) expression.
class ConstraintSystem {
public:
TypeChecker &TC;
DeclContext *DC;
private:
Constraint *failedConstraint = nullptr;
/// \brief Allocator used for all of the related constraint systems.
llvm::BumpPtrAllocator Allocator;
/// \brief Arena used for memory management of constraint-checker-related
/// allocations.
ConstraintCheckerArenaRAII Arena;
/// \brief Counter for type variables introduced.
unsigned TypeCounter = 0;
/// \brief Counter for the overload sets introduced.
unsigned OverloadSetCounter = 0;
/// \brief Cached member lookups.
llvm::DenseMap<std::pair<Type, Identifier>, Optional<LookupResult>>
MemberLookups;
/// \brief Folding set containing all of the locators used in this
/// constraint system.
llvm::FoldingSet<ConstraintLocator> ConstraintLocators;
/// \brief Folding set containing all of the failures that have occurred
/// while building and initially simplifying this constraint system.
///
/// These failures are unavoidable, in the sense that they occur before
/// we have made any (potentially incorrect) assumptions at all.
SmallVector<Failure *, 1> unavoidableFailures;
/// \brief Failures that occured while solving.
///
/// FIXME: We really need to track overload sets and type variable bindings
/// to make any sense of this data. Also, it probably belongs within
/// SolverState.
llvm::FoldingSet<Failure> failures;
/// \brief The overload sets that have been resolved along the current path.
ResolvedOverloadSetListItem *resolvedOverloadSets = nullptr;
SmallVector<TypeVariableType *, 16> TypeVariables;
SmallVector<Constraint *, 16> Constraints;
SmallVector<OverloadSet *, 4> UnresolvedOverloadSets;
llvm::DenseMap<ConstraintLocator *, OverloadSet *> GeneratedOverloadSets;
typedef llvm::PointerUnion<TypeVariableType *, TypeBase *>
RepresentativeOrFixed;
// Valid everywhere, for debugging
SmallVector<Constraint *, 16> SolvedConstraints;
/// \brief Describes the current solver state.
struct SolverState {
/// \brief Depth of the solution stack.
unsigned depth = 0;
/// \brief Whether to record failures or not.
bool recordFailures = false;
/// \brief The overload sets that were generated along the current path,
/// indexed by locator.
SmallVector<ConstraintLocator *, 4> generatedOverloadSets;
/// \brief The set of constraints that were generated along the current
/// path.
SmallVector<Constraint *, 32> generatedConstraints;
/// \brief The set of constraints that have been retired along the
/// current path.
SmallVector<Constraint *, 32> retiredConstraints;
/// \brief The set of type variable bindings that have changed while
/// processing this constraint system.
SavedTypeVariableBindings savedBindings;
};
/// \brief The current solver state.
///
/// This will be non-null when we're actively solving the constraint
/// system, and carries temporary state related to the current path
/// we're exploring.
SolverState *solverState = nullptr;
unsigned assignTypeVariableID() {
return TypeCounter++;
}
unsigned assignOverloadSetID() {
return OverloadSetCounter++;
}
friend class OverloadSet;
public:
/// \brief Introduces a new solver scope, which any changes to the
/// solver state or constraint system are temporary and will be undone when
/// this object is destroyed.
///
///
class SolverScope {
ConstraintSystem &cs;
/// \brief The current resolved overload set list.
ResolvedOverloadSetListItem *resolvedOverloadSets;
/// \brief The length of \c TypeVariables.
unsigned numTypeVariables;
/// \brief The length of \c UnresolvedOverloadSets.
unsigned numUnresolvedOverloadSets;
/// \brief The length of \c generatedOverloadSets.
unsigned numGeneratedOverloadSets;
/// \brief The length of \c SavedBindings.
unsigned numSavedBindings;
/// \brief The length of \c generatedConstraints.
unsigned numGeneratedConstraints;
/// \brief The length of \c retiredConstraints.
unsigned numRetiredConstraints;
SolverScope(const SolverScope &) = delete;
SolverScope &operator=(const SolverScope &) = delete;
public:
explicit SolverScope(ConstraintSystem &cs);
~SolverScope();
};
ConstraintSystem(TypeChecker &tc, DeclContext *dc);
~ConstraintSystem();
/// \brief Retrieve the type checker associated with this constraint system.
TypeChecker &getTypeChecker() const { return TC; }
/// \brief Retrieve the AST context.
ASTContext &getASTContext() const { return TC.Context; }
private:
/// \brief Determine whether this constraint system has any free type
/// variables.
bool hasFreeTypeVariables();
/// \brief Finalize this constraint system; we're done attempting to solve
/// it.
///
/// \returns the solution.
Solution finalize();
/// \brief Restore the type variable bindings to what they were before
/// we attempted to solve this constraint system.
///
/// \param numBindings The number of bindings to restore, from the end of
/// the saved-binding stack.
void restoreTypeVariableBindings(unsigned numBindings);
/// \brief Retrieve the set of saved type variable bindings, if available.
///
/// \returns null when we aren't currently solving the system.
SavedTypeVariableBindings *getSavedBindings() const {
return solverState? &solverState->savedBindings : nullptr;
}
public:
/// \brief Lookup for a member with the given name in the given base type.
///
/// This routine caches the results of member lookups in the top constraint
/// system, to avoid.
///
/// FIXME: This caching should almost certainly be performed at the
/// translation unit level, since type checking occurs after name binding,
/// and no new names are introduced after name binding.
///
/// \returns A reference to the member-lookup result.
LookupResult &lookupMember(Type base, Identifier name);
/// \brief Retrieve an unresolved overload set.
OverloadSet *getUnresolvedOverloadSet(unsigned Idx) const {
return UnresolvedOverloadSets[Idx];
}
/// \brief Create a new type variable.
TypeVariableType *createTypeVariable(ConstraintLocator *locator,
unsigned options) {
auto tv = TypeVariableType::getNew(TC.Context, assignTypeVariableID(),
locator, options);
TypeVariables.push_back(tv);
return tv;
}
/// \brief Retrieve the constraint locator for the given anchor and
/// path, uniqued.
ConstraintLocator *
getConstraintLocator(Expr *anchor,
ArrayRef<ConstraintLocator::PathElement> path);
/// \brief Retrieve the constraint locator for the given anchor and
/// path element.
ConstraintLocator *
getConstraintLocator(Expr *anchor, ConstraintLocator::PathElement pathElt) {
return getConstraintLocator(anchor, llvm::makeArrayRef(pathElt));
}
/// \brief Extend the given constraint locator with a path element.
ConstraintLocator *
getConstraintLocator(ConstraintLocator *locator,
ConstraintLocator::PathElement pathElt) {
return getConstraintLocator(ConstraintLocatorBuilder(locator)
.withPathElement(pathElt));
}
/// \brief Retrieve the constraint locator described by the given
/// builder.
ConstraintLocator *
getConstraintLocator(const ConstraintLocatorBuilder &builder);
private:
/// \brief Record failure with already-simplified arguments.
template<typename ...Args>
void recordFailureSimplified(ConstraintLocator *locator,
Failure::FailureKind kind,
Args &&...args) {
// If there is no solver state, this failure is unavoidable.
if (!solverState) {
auto failure = Failure::create(getAllocator(), locator, kind,
resolvedOverloadSets,
std::forward<Args>(args)...);
// Debug output.
if (TC.Context.LangOpts.DebugConstraintSolver) {
llvm::errs().indent(2);
failure->dump(&TC.Context.SourceMgr);
}
unavoidableFailures.push_back(failure);
return;
}
// Check whether we've recorded this failure already.
llvm::FoldingSetNodeID id;
Failure::Profile(id, locator, kind, resolvedOverloadSets, args...);
void *insertPos = nullptr;
auto failure = failures.FindNodeOrInsertPos(id, insertPos);
if (!failure) {
// Allocate a new failure and record it.
failure = Failure::create(getAllocator(), locator, kind,
resolvedOverloadSets, args...);
failures.InsertNode(failure, insertPos);
}
// Debug output.
if (TC.Context.LangOpts.DebugConstraintSolver) {
llvm::errs().indent(solverState->depth * 2 + 2);
failure->dump(&TC.Context.SourceMgr);
}
return;
}
/// \brief Simplifies an argument to the failure by simplifying the type.
Type simplifyFailureArg(Type type) {
// FIXME: Should also map type variables back to their corresponding
// archetypes here.
return simplifyType(type);
}
/// \brief Simplifies an argument to the failure by simplifying the type.
Type simplifyFailureArg(TypeBase *type) {
return simplifyType(type);
}
/// \brief Simplifies an argument to the failure (a no-op).
unsigned simplifyFailureArg(unsigned arg) {
return arg;
}
/// \brief Simplifies an argument to the failure (a no-op).
Identifier simplifyFailureArg(Identifier arg) {
return arg;
}
public:
/// \brief Whether we should be recording failures.
bool shouldRecordFailures() {
return !solverState || solverState->recordFailures ||
TC.Context.LangOpts.DebugConstraintSolver;
}
/// \brief Record a failure at the given location with the given kind,
/// along with any additional arguments to be passed to the failure
/// constructor.
template<typename ...Args>
void recordFailure(ConstraintLocator *locator, Failure::FailureKind kind,
Args &&...args) {
// If we don't want to record failures, don't.
if (!shouldRecordFailures())
return;
recordFailureSimplified(locator, kind,
simplifyFailureArg(std::forward<Args>(args))...);
}
/// \brief Try to diagnose the problem that caused this constraint system
/// to fail.
///
/// \returns true if a diagnostic was produced, false otherwise.
bool diagnose();
/// \brief Add a newly-allocated constraint after attempting to simplify
/// it.
///
/// \param isExternallySolved Whether this constraint is being solved
/// as an eager simplification, outside of the simplify() loop.
///
/// \param simplifyExisting Whether we're simplifying an existing
/// constraint rather than introducing a new constraint.
///
/// \returns true if this constraint was solved.
bool addConstraint(Constraint *constraint,
bool isExternallySolved = false,
bool simplifyExisting = false);
/// \brief Add a constraint to the constraint system.
void addConstraint(ConstraintKind kind, Type first, Type second,
ConstraintLocator *locator = nullptr) {
assert(first && "Missing first type");
assert(second && "Missing second type");
addConstraint(new (*this) Constraint(kind, first, second, Identifier(),
locator));
}
/// \brief Add a value member constraint to the constraint system.
void addValueMemberConstraint(Type baseTy, Identifier name, Type memberTy,
ConstraintLocator *locator = nullptr) {
assert(baseTy);
assert(memberTy);
assert(!name.empty());
addConstraint(new (*this) Constraint(ConstraintKind::ValueMember,
baseTy, memberTy, name, locator));
}
/// \brief Add a type member constraint to the constraint system.
void addTypeMemberConstraint(Type baseTy, Identifier name, Type memberTy,
ConstraintLocator *locator = nullptr) {
assert(baseTy);
assert(memberTy);
assert(!name.empty());
addConstraint(new (*this) Constraint(ConstraintKind::TypeMember,
baseTy, memberTy, name, locator));
}
/// \brief Add an archetype constraint.
void addArchetypeConstraint(Type baseTy, ConstraintLocator *locator = nullptr) {
assert(baseTy);
addConstraint(new (*this) Constraint(ConstraintKind::Archetype,
baseTy, Type(), Identifier(),
locator));
}
/// \brief Retrieve the representative of the equivalence class containing
/// this type variable.
TypeVariableType *getRepresentative(TypeVariableType *typeVar) {
return typeVar->getImpl().getRepresentative(getSavedBindings());
}
/// \brief Merge the equivalence sets of the two type variables.
///
/// Note that both \c typeVar1 and \c typeVar2 must be the
/// representatives of their equivalence classes, and must be
/// distinct.
void mergeEquivalenceClasses(TypeVariableType *typeVar1,
TypeVariableType *typeVar2) {
assert(typeVar1 == getRepresentative(typeVar1) &&
"typeVar1 is not the representative");
assert(typeVar2 == getRepresentative(typeVar2) &&
"typeVar2 is not the representative");
assert(typeVar1 != typeVar2 && "cannot merge type with itself");
typeVar1->getImpl().mergeEquivalenceClasses(typeVar2, getSavedBindings());
}
/// \brief Retrieve the fixed type corresponding to the given type variable,
/// or a null type if there is no fixed type.
Type getFixedType(TypeVariableType *typeVar) {
return typeVar->getImpl().getFixedType(getSavedBindings());
}
/// \brief Assign a fixed type to the given type variable.
void assignFixedType(TypeVariableType *typeVar, Type type) {
typeVar->getImpl().assignFixedType(type, getSavedBindings());
}
/// \brief "Open" the given type by replacing any occurrences of archetypes
/// (including those implicit in unbound generic types) with fresh type
/// variables.
///
/// \param type The type to open.
/// \returns The opened type, or \c type if there are no archetypes in it.
Type openType(Type type) {
llvm::DenseMap<ArchetypeType *, TypeVariableType *> replacements;
return openType(type, { }, replacements);
}
/// \brief "Open" the given type by replacing any occurrences of archetypes
/// (including those implicit in unbound generic types) with fresh type
/// variables.
///
/// \param type The type to open.
///
/// \param archetypes The set of archetypes we're opening.
///
/// \param replacements The mapping from opened archetypes to the type
/// variables to which they were opened.
///
/// \returns The opened type, or \c type if there are no archetypes in it.
Type openType(Type type, ArrayRef<ArchetypeType *> archetypes,
llvm::DenseMap<ArchetypeType *, TypeVariableType *> &replacements);
/// \brief "Open" the given binding type by replacing any occurrences of
/// archetypes (including those implicit in unbound generic types) with
/// fresh type variables.
///
/// This variant of \c openType() tweaks the result from \c openType() to
/// prefer arrays to slices.
/// FIXME: This is a bit of a hack.
///
/// \param type The type to open.
/// \returns The opened type, or \c type if there are no archetypes in it.
Type openBindingType(Type type);
/// \brief "Open" the type of a declaration context, which must be a type or
/// extension.
///
/// \param dc The context to open.
///
/// \param replacements Will receive the set of type variable replacements
/// for each of the archetypes in \c dc.
///
/// \param genericParams If non-null, will receive the set of generic
/// parameters opened up by this routine.
///
/// \returns The opened type of the base.
Type openTypeOfContext(
DeclContext *dc,
llvm::DenseMap<ArchetypeType *, TypeVariableType *> &replacements,
GenericParamList **genericParams);
/// \brief Retrieve the type of a reference to the given value declaration.
///
/// For references to polymorphic function types, this routine "opens up"
/// the type by replacing each instance of an archetype with a fresh type
/// variable.
///
/// \param decl The declarations whose type is being computed.
///
/// \param isTypeReference Whether it's a reference to this declaration
/// as a type.
///
/// \param isSpecialized Whether this declaration is immediately specialized.
Type getTypeOfReference(ValueDecl *decl,
bool isTypeReference,
bool isSpecialized);
/// \brief Retrieve the type of a reference to the given value declaration,
/// as a member with a base of the given type.
///
/// For references to polymorphic function types, this routine "opens up"
/// the type by replacing each instance of an archetype with a fresh type
/// variable.
///
/// \param isTypeReference Indicates that we want to refer to the declared
/// type of the type declaration rather than referring to it as a value.
///
/// \param isDynamicResult Indicates that this declaration was found via
/// dynamic lookup.
Type getTypeOfMemberReference(Type baseTy, ValueDecl *decl,
bool isTypeReference,
bool isDynamicResult);
/// \brief Add a new overload set to the list of unresolved overload
/// sets.
void addOverloadSet(OverloadSet *ovl);
/// \brief Find the overload set generated by the given locator, if any.
OverloadSet *getGeneratedOverloadSet(ConstraintLocator *locator);
/// \brief Retrieve the allocator used by this constraint system.
llvm::BumpPtrAllocator &getAllocator() { return Allocator; }
template <typename It>
ArrayRef<typename std::iterator_traits<It>::value_type>
allocateCopy(It start, It end) {
typedef typename std::iterator_traits<It>::value_type T;
T *result = (T*)getAllocator().Allocate(sizeof(T)*(end-start),
__alignof__(T));
unsigned i;
for (i = 0; start != end; ++start, ++i)
new (result+i) T(*start);
return ArrayRef<T>(result, i);
}
template<typename T>
ArrayRef<T> allocateCopy(ArrayRef<T> array) {
return allocateCopy(array.begin(), array.end());
}
/// \brief Generate constraints for the given (unchecked) expression.
///
/// \returns a possibly-sanitized expression, or null if an error occurred.
Expr *generateConstraints(Expr *E);
/// \brief Generate constraints for the given top-level expression,
/// assuming that its children are already type-checked.
///
/// \returns a possibly-sanitized expression, or null if an error occurred.
Expr *generateConstraintsShallow(Expr *E);
/// \brief Generate constraints for binding the given pattern to the
/// value of the given expression.
///
/// \returns a possibly-sanitized initializer, or null if an error occurred.
Type generateConstraints(Pattern *P, ConstraintLocatorBuilder locator);
/// \brief The result of attempting to resolve a constraint or set of
/// constraints.
enum class SolutionKind : char {
/// \brief The constraint has been trivially solved, by not introducing
/// any additional constraints.
TriviallySolved,
/// \brief The constraint has been solved completely, and provides no
/// more information.
Solved,
/// \brief The constraint could not be solved at this point.
Unsolved,
/// \brief The constraint uncovers an inconsistency in the system.
Error
};
/// \brief Enumerates all of the 'direct' supertypes of the given type.
///
/// The direct supertype S of a type T is a supertype of T (e.g., T < S)
/// such that there is no type U where T < U and U < S.
SmallVector<Type, 4> enumerateDirectSupertypes(Type type);
/// \brief Compute the rvalue type of the given expression, which is the
/// destination of an assignment statement.
Type computeAssignDestType(Expr *dest, SourceLoc equalLoc);
private:
/// \brief Flags that direct type matching.
enum TypeMatchFlags {
TMF_None = 0,
/// \brief Indicates that we are in a context where we should be
/// generating constraints for any unsolvable problems.
///
/// This flag is automatically introduced when type matching destructures
/// a type constructor (tuple, function type, etc.), solving that
/// constraint while potentially generating others.
TMF_GenerateConstraints = 0x01
};
/// \brief Subroutine of \c matchTypes(), which matches up two tuple types.
///
/// \returns an empty optional if the scalar-to-tuple conversion should be
/// used instead. Otherwise, returns the solution result.
Optional<SolutionKind> matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator,
bool &trivial);
/// \brief Subroutine of \c matchTypes(), which matches up two function
/// types.
SolutionKind matchFunctionTypes(FunctionType *func1, FunctionType *func2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator,
bool &trivial);
/// \brief Attempt to match up types \c type1 and \c type2, which in effect
/// is solving the given type constraint between these two types.
///
/// \param type1 The first type, which is on the left of the type relation.
///
/// \param type2 The second type, which is on the right of the type relation.
///
/// \param kind The kind of type match being performed, e.g., exact match,
/// trivial subtyping, subtyping, or conversion.
///
/// \param flags A set of flags composed from the TMF_* constants, which
/// indicates how
///
/// \param locator The locator that will be used to track the location of
/// the specific types being matched.
///
/// \param trivial Will be set false if any non-trivial subtyping or
/// conversion is applied.
///
/// \returns the result of attempting to solve this constraint.
SolutionKind matchTypes(Type type1, Type type2, TypeMatchKind kind,
unsigned flags, ConstraintLocatorBuilder locator,
bool &trivial);
public:
/// \brief Determine whether a given type is a subtype of another.
///
/// This operation is meant to be used only with concrete types.
bool isSubtypeOf(Type type1, Type type2, bool &isTrivial) {
isTrivial = true;
switch (matchTypes(type1, type2, TypeMatchKind::Subtype, TMF_None,
nullptr, isTrivial)) {
case SolutionKind::Error:
return false;
case SolutionKind::Solved:
case SolutionKind::TriviallySolved:
return true;
case SolutionKind::Unsolved:
llvm_unreachable("couldn't solve subtype problem");
}
}
/// \brief Determine whether a given type is convertible to.
///
/// This operation is meant to be used only with concrete types.
bool isConvertibleTo(Type type1, Type type2, bool &isTrivial) {
isTrivial = true;
switch (matchTypes(type1, type2, TypeMatchKind::Conversion, TMF_None,
nullptr, isTrivial)) {
case SolutionKind::Error:
return false;
case SolutionKind::Solved:
case SolutionKind::TriviallySolved:
return true;
case SolutionKind::Unsolved:
llvm_unreachable("couldn't solve subtype problem");
}
}
/// \brief Resolve the given overload set to the choice with the given
/// index within this constraint system.
void resolveOverload(OverloadSet *ovl, unsigned idx);
/// \brief Simplify a type, by replacing type variables with either their
/// fixed types (if available) or their representatives.
///
/// The resulting types can be compared canonically, so long as additional
/// type equivalence requirements aren't introduced between comparisons.
Type simplifyType(Type type){
llvm::SmallPtrSet<TypeVariableType *, 16> substituting;
return simplifyType(type, substituting);
}
private:
/// \brief Simplify a type, by replacing type variables with either their
/// fixed types (if available) or their representatives.
///
/// \param type the type to be simplified.
///
/// \param substituting the set of type variables that we're already
/// substituting for. These type variables will not be substituted again,
/// to avoid infinite recursion.
///
/// The resulting types can be compared canonically, so long as additional
/// type equivalence requirements aren't introduced between comparisons.
Type simplifyType(Type type,
llvm::SmallPtrSet<TypeVariableType *, 16> &substituting);
/// \brief Attempt to simplify the given construction constraint.
///
/// \param valueType The type being constructed.
///
/// \param argType The type of the argument, used to call \c
/// valueType's constructor.
///
/// \param flags Flags that indicate how the constraint should be
/// simplified.
///
/// \param locator Locator describing where this construction
/// occurred.
SolutionKind simplifyConstructionConstraint(Type valueType, Type argType,
unsigned flags,
ConstraintLocator *locator);
/// \brief Attempt to simplify the given conformance constraint.
///
/// \param type The type being testing.
/// \param protocol The protocol to which the type should conform.
/// \param locator Locator describing where this constraint occurred.
SolutionKind simplifyConformsToConstraint(Type type, ProtocolDecl *protocol,
ConstraintLocatorBuilder locator);
/// \brief Attempt to simplify the given member constraint.
SolutionKind simplifyMemberConstraint(const Constraint &constraint);
/// \brief Attempt to simplify the ApplicableFunction constraint.
SolutionKind simplifyApplicableFnConstraint(const Constraint &constraint);
/// \brief Attempt to simplify the given archetype constraint.
SolutionKind simplifyArchetypeConstraint(const Constraint &constraint);
/// \brief Simplify the given constaint.
SolutionKind simplifyConstraint(const Constraint &constraint);
public:
/// \brief Walks through the list of constraints, collecting the constraints
/// that directly apply to each representative type variable.
///
/// \param typeVarConstraints will be populated with a list of
/// representative type variables and the constraints that apply directly
/// to them.
void collectConstraintsForTypeVariables(
SmallVectorImpl<TypeVariableConstraints> &typeVarConstraints);
public:
/// \brief Simplify the system of constraints, by breaking down complex
/// constraints into simpler constraints.
///
/// The result of simplification is a constraint system that consisting of
/// only simple constraints relating type variables to each other or
/// directly to fixed types. There are no constraints that involve
/// type constructors on both sides. the simplified constraint system may,
/// of course, include type variables for which we have constraints but
/// no fixed type. Such type variables are left to the solver to bind.
///
/// \returns true if an error occurred, false otherwise.
bool simplify();
/// \brief Solve the system of constraints.
///
/// \param solutions The set of solutions to this system of constraints.
/// \param allowFreeTypeVariables Whether to allow free type variables in
/// the solution.
///
/// \returns true if an error occurred, false otherwise.
bool solve(SmallVectorImpl<Solution> &solutions,
bool allowFreeTypeVariables = false);
private:
// \brief Compare two solutions to the same set of constraints.
///
/// \param cs The constraint system.
/// \param solutions All of the solutions to the system.
/// \param diff The differences among the solutions.
/// \param idx1 The index of the first solution.
/// \param idx2 The index of the second solution.
static SolutionCompareResult compareSolutions(ConstraintSystem &cs,
ArrayRef<Solution> solutions,
const SolutionDiff &diff,
unsigned idx1,
unsigned idx2);
public:
/// \brief Given a set of viable solutions, find the best
/// solution.
///
/// \returns the best solution, or null if there is no best solution.
Solution *findBestSolution(SmallVectorImpl<Solution> &solutions);
/// \brief Apply a given solution to the expression, producing a fully
/// type-checked expression.
Expr *applySolution(const Solution &solution, Expr *expr);
/// \brief Apply a given solution to the expression to the top-level
/// expression, producing a fully type-checked expression.
Expr *applySolutionShallow(const Solution &solution, Expr *expr);
void dump();
};
/// \brief Adjust lvalue types within the type of a reference to a declaration.
///
/// For an lvalue type, this routine adds the 'implicit' and 'nonheap' bits to
/// the lvalue.
///
/// For the function type of an assignment operator, makes the first argument
/// an implicit byref(settable).
Type adjustLValueForReference(Type type, bool isAssignment,
ASTContext &context);
/// \brief Compute the shuffle required to map from a given tuple type to
/// another tuple type.
///
/// \param fromTuple The tuple type we're converting from.
///
/// \param toTuple The tuple type we're converting to.
///
/// \param sources Will be populated with information about the source of each
/// of the elements for the result tuple. The indices into this array are the
/// indices of the tuple type we're converting to, while the values are
/// either one of the \c TupleShuffleExpr constants or are an index into the
/// source tuple.
///
/// \param variadicArgs Will be populated with all of the variadic arguments
/// that will be placed into the variadic tuple element (i.e., at the index
/// \c where \c consumed[i] is \c TupleShuffleExpr::FirstVariadic). The values
/// are indices into the source tuple.
///
/// \param sourceLabelsAreMandatory True if labels in the source type are
/// mandatory to match; false means to make an effort to match them, but
/// they can also be dropped.
///
/// \returns true if no tuple conversion is possible, false otherwise.
bool computeTupleShuffle(TupleType *fromTuple, TupleType *toTuple,
SmallVectorImpl<int> &sources,
SmallVectorImpl<unsigned> &variadicArgs,
bool sourceLabelsAreMandatory);
/// Given that an expression has tuple type, are labels in that type
/// mandatory or advistory? Mandatory labels must be matched in the
/// destination type; optional labels can be matched with unlabeled
/// elements.
bool hasMandatoryTupleLabels(Expr *expr);
/// Simplify the given locator by zeroing in on the most specific
/// subexpression described by the locator.
///
/// This routine can also find the corresponding "target" locator, which
/// typically provides the other end of a relational constraint. For example,
/// if the primary locator refers to a function argument, the target locator
/// will be set to refer to the corresponding function parameter.
///
/// \param cs The constraint system in which the locator will be simplified.
///
/// \param locator The locator to simplify.
///
/// \param range1 Will be populated with an "interesting" range.
///
/// \param range2 Will be populated with a second "interesting" range.
///
/// \param targetLocator If non-null, will be set to a locator that describes
/// the target of the input locator.
///
/// \return the simplified locator.
ConstraintLocator *simplifyLocator(ConstraintSystem &cs,
ConstraintLocator *locator,
SourceRange &range1,
SourceRange &range2,
ConstraintLocator **targetLocator = nullptr);
void simplifyLocator(Expr *&anchor,
ArrayRef<LocatorPathElt> &path,
Expr *&targetAnchor,
SmallVectorImpl<LocatorPathElt> &targetPath,
SourceRange &range1, SourceRange &range2);
/// Describes the kind of entity to which a locator was resolved.
enum class ResolvedLocatorKind : uint8_t {
/// The locator could not be resolved.
Unresolved,
/// The locator refers to a function.
Function,
/// The locator refers to a constructor.
Constructor,
/// The locator refers to a parameter of a function.
Parameter
};
/// The entity to which a locator resolved.
class ResolvedLocator {
ResolvedLocatorKind kind;
ValueDecl *decl;
public:
ResolvedLocator() : kind(ResolvedLocatorKind::Unresolved) { }
ResolvedLocator(FuncDecl *func)
: kind(ResolvedLocatorKind::Function), decl(func)
{
}
ResolvedLocator(ConstructorDecl *constructor)
: kind(ResolvedLocatorKind::Constructor), decl(constructor)
{
}
ResolvedLocator(VarDecl *param)
: kind(ResolvedLocatorKind::Parameter), decl(param)
{
}
/// Determine the kind of entity to which the locator resolved.
ResolvedLocatorKind getKind() const { return kind; }
/// Retrieve the declaration to which the locator resolved.
ValueDecl *getDecl() const { return decl; }
explicit operator bool() const {
return getKind() != ResolvedLocatorKind::Unresolved;
}
};
/// Resolve a locator to the specific declaration it references, if possible.
///
/// \param cs The constraint system in which the locator will be resolved.
///
/// \param locator The locator to resolve.
///
/// \param findOvlChoice A function that searches for the overload choice
/// associated with the given locator, or an empty optional if there is no such
/// overload.
///
/// \returns the entity to which the locator resolved.
///
/// FIXME: It would be more natural to express the result as a locator.
ResolvedLocator resolveLocatorToDecl(
ConstraintSystem &cs,
ConstraintLocator *locator,
std::function<Optional<OverloadChoice>(ConstraintLocator *)>
findOvlChoice);
} // end namespace constraints
template<typename ...Args>
TypeVariableType *TypeVariableType::getNew(const ASTContext &C, unsigned ID,
Args &&...args) {
// Allocate memory
void *mem = C.Allocate(sizeof(TypeVariableType) + sizeof(Implementation),
alignof(TypeVariableType),
AllocationArena::ConstraintSolver);
// Construct the type variable.
auto *result = ::new (mem) TypeVariableType(C, ID);
// Construct the implementation object.
new (result+1) TypeVariableType::Implementation(std::forward<Args>(args)...);
return result;
}
} // end namespace swift
#endif // LLVM_SWIFT_SEMA_CONSTRAINT_SYSTEM_H