mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
2163 lines
75 KiB
C++
2163 lines
75 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/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 <cstddef>
|
|
|
|
namespace swift {
|
|
|
|
class Expr;
|
|
enum class LiteralKind : char;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
} // end namespace constraints
|
|
|
|
/// \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 {
|
|
/// \brief The unique number assigned to this type variable.
|
|
unsigned ID;
|
|
|
|
/// \brief The archetype that this type variable describes.
|
|
ArchetypeType *Archetype;
|
|
|
|
/// \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(unsigned ID)
|
|
: ID(ID), Archetype(nullptr),
|
|
ParentOrFixed(getTypeVariable()) { }
|
|
|
|
explicit Implementation(unsigned ID, Expr *TheExpr)
|
|
: ID(ID), Archetype(nullptr),
|
|
ParentOrFixed(getTypeVariable()) { }
|
|
|
|
explicit Implementation(unsigned ID, ArchetypeType *Archetype)
|
|
: ID(ID), Archetype(Archetype),
|
|
ParentOrFixed(getTypeVariable()) { }
|
|
|
|
/// \brief Retrieve the unique ID corresponding to this type variable.
|
|
unsigned getID() const { return ID; }
|
|
|
|
/// \brief Retrieve the archetype that this type variable replaced.
|
|
ArchetypeType *getArchetype() const { return Archetype; }
|
|
|
|
/// \brief Retrieve the type variable associated with this implementation.
|
|
TypeVariableType *getTypeVariable() {
|
|
return reinterpret_cast<TypeVariableType *>(this) - 1;
|
|
}
|
|
|
|
/// \brief Record the current type-variable binding.
|
|
void recordBinding(constraints::SavedTypeVariableBindings &record) {
|
|
record.push_back(constraints::SavedTypeVariableBinding(getTypeVariable()));
|
|
}
|
|
|
|
/// \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);
|
|
rep->getImpl().recordBinding(record);
|
|
rep->getImpl().ParentOrFixed = getTypeVariable();
|
|
} else {
|
|
auto rep = getRepresentative(&record);
|
|
rep->getImpl().recordBinding(record);
|
|
rep->getImpl().ParentOrFixed = other;
|
|
}
|
|
}
|
|
|
|
/// \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);
|
|
rep->getImpl().recordBinding(record);
|
|
rep->getImpl().ParentOrFixed = type.getPointer();
|
|
}
|
|
|
|
/// \brief Print the type variable to the given output stream.
|
|
void print(llvm::raw_ostream &Out);
|
|
};
|
|
|
|
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 the rvalue of the second type.
|
|
EqualRvalue,
|
|
/// \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 is the type of a literal. There is no second
|
|
/// type.
|
|
Literal,
|
|
/// \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 literal constraint, which specifies that a type must be
|
|
/// able to be created from a particular kind of literal.
|
|
Literal,
|
|
|
|
/// \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 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 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 an explicit closure expression.
|
|
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 Determine whether the given path element kind has an associated
|
|
/// value.
|
|
static bool pathElementHasValue(PathElementKind kind) {
|
|
switch (kind) {
|
|
case ApplyArgument:
|
|
case ApplyFunction:
|
|
case FunctionArgument:
|
|
case FunctionResult:
|
|
case Member:
|
|
case MemberRefBase:
|
|
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:
|
|
return false;
|
|
|
|
case GenericArgument:
|
|
case InterpolationArgument:
|
|
case NamedTupleElement:
|
|
case TupleElement:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// \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 The kind of path element.
|
|
PathElementKind kind : 8;
|
|
|
|
///\ brief The value of the path element, if applicable.
|
|
unsigned value : 24;
|
|
|
|
PathElement(PathElementKind kind, unsigned value)
|
|
: kind(kind), value(value) { }
|
|
|
|
friend class ConstraintLocator;
|
|
|
|
public:
|
|
PathElement(PathElementKind kind) : kind(kind), value(0) {
|
|
assert(!pathElementHasValue(kind) && "Path element requires value");
|
|
}
|
|
|
|
/// \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 { return kind; }
|
|
|
|
/// \brief Retrieve the value associated with this path element,
|
|
/// if it has one.
|
|
unsigned getValue() const {
|
|
assert(pathElementHasValue(kind) && "No value in path element!");
|
|
return value;
|
|
}
|
|
};
|
|
|
|
/// \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 ParentType:
|
|
case RvalueAdjustment:
|
|
case ScalarToTuple:
|
|
case SubscriptIndex:
|
|
case SubscriptMember:
|
|
case SubscriptResult:
|
|
case IfThen:
|
|
case IfElse:
|
|
case AssignSource:
|
|
continue;
|
|
|
|
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 (pathElementHasValue(elt.getKind()))
|
|
id.AddInteger(elt.getValue());
|
|
}
|
|
}
|
|
|
|
/// \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(llvm::SourceMgr *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(llvm::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;
|
|
}
|
|
};
|
|
|
|
/// \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 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 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 a literal type.
|
|
IsNotLiteralType,
|
|
};
|
|
|
|
private:
|
|
/// \brief The kind of failure this describes.
|
|
FailureKind kind : 8;
|
|
|
|
/// \brief A value, if used.
|
|
unsigned value : 32;
|
|
|
|
/// \brief Describes the location of this failure.
|
|
ConstraintLocator *locator;
|
|
|
|
/// \brief The first type.
|
|
Type first;
|
|
|
|
/// \brief The second value, which may be one of several things (type,
|
|
/// member name, literal kind, etc.).
|
|
union {
|
|
TypeBase *type;
|
|
void *name;
|
|
LiteralKind literal;
|
|
} second;
|
|
|
|
public:
|
|
/// \brief Retrieve the failure kind.
|
|
FailureKind getKind() const { return kind; }
|
|
|
|
/// \brief Retrieve the failure locator.
|
|
ConstraintLocator *getLocator() const {
|
|
return locator;
|
|
}
|
|
|
|
/// \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 literal kind.
|
|
LiteralKind getLiteralKind() const {
|
|
return second.literal;
|
|
}
|
|
|
|
/// \brief Retrieve the value.
|
|
unsigned getValue() const { return value; }
|
|
|
|
/// \brief Profile the given failure.
|
|
void Profile(llvm::FoldingSetNodeID &id) {
|
|
switch (kind) {
|
|
case FunctionAutoclosureMismatch:
|
|
case LValueQualifiers:
|
|
case TupleNameMismatch:
|
|
case TupleNamePositionMismatch:
|
|
case TupleSizeMismatch:
|
|
case TupleUnused:
|
|
case TupleVariadicMismatch:
|
|
case TypesNotConstructible:
|
|
case TypesNotConvertible:
|
|
case TypesNotEqual:
|
|
case TypesNotSubtypes:
|
|
case TypesNotTrivialSubtypes:
|
|
case DoesNotConformToProtocol:
|
|
return Profile(id, locator, kind, getFirstType(), getSecondType());
|
|
|
|
case DoesNotHaveMember:
|
|
return Profile(id, locator, kind, getFirstType(), getName());
|
|
|
|
case IsNotArchetype:
|
|
return Profile(id, locator, kind, getFirstType());
|
|
|
|
case IsNotLiteralType:
|
|
return Profile(id, locator, kind, getFirstType(), getLiteralKind());
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class ConstraintSystem;
|
|
|
|
/// \brief Construct a failure involving one type.
|
|
Failure(ConstraintLocator *locator, FailureKind kind, Type type)
|
|
: kind(kind), value(0), locator(locator), first(type)
|
|
{
|
|
second.type = nullptr;
|
|
}
|
|
|
|
/// \brief Construct a failure involving two types and an optional value.
|
|
Failure(ConstraintLocator *locator, FailureKind kind,
|
|
Type type1, Type type2, unsigned value = 0)
|
|
: kind(kind), value(value), locator(locator), first(type1)
|
|
{
|
|
second.type = type2.getPointer();
|
|
}
|
|
|
|
/// \brief Construct a failure involving a type and a name.
|
|
Failure(ConstraintLocator *locator, FailureKind kind,
|
|
Type type, Identifier name)
|
|
: kind(kind), value(0), locator(locator), first(type)
|
|
{
|
|
second.name = name.getAsOpaquePointer();
|
|
}
|
|
|
|
/// \brief Construct a failure involving a type and a literal kind.
|
|
Failure(ConstraintLocator *locator, FailureKind kind, Type type,
|
|
LiteralKind literal)
|
|
: kind(kind), value(0), locator(locator), first(type)
|
|
{
|
|
second.literal = literal;
|
|
}
|
|
|
|
/// \brief Profile a failure involving one type.
|
|
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
|
|
FailureKind kind, Type type) {
|
|
id.AddPointer(locator);
|
|
id.AddInteger(kind);
|
|
id.AddPointer(type.getPointer());
|
|
}
|
|
|
|
/// \brief Profile a failure involving two types.
|
|
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
|
|
FailureKind kind, Type type1, Type type2) {
|
|
id.AddPointer(locator);
|
|
id.AddInteger(kind);
|
|
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, Type type1, Type type2,
|
|
unsigned value) {
|
|
id.AddPointer(locator);
|
|
id.AddInteger(kind);
|
|
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, Type type, Identifier name) {
|
|
id.AddPointer(locator);
|
|
id.AddInteger(kind);
|
|
id.AddPointer(type.getPointer());
|
|
id.AddPointer(name.getAsOpaquePointer());
|
|
}
|
|
|
|
/// \brief Profile a failure involving a type and a literal kind.
|
|
static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator,
|
|
FailureKind kind, Type type, LiteralKind literal) {
|
|
id.AddPointer(locator);
|
|
id.AddInteger(kind);
|
|
id.AddPointer(type.getPointer());
|
|
id.AddInteger(static_cast<unsigned>(literal));
|
|
}
|
|
|
|
/// \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 For a literal-type constraint, the kind of literal we're
|
|
/// expecting.
|
|
LiteralKind Literal : 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::EqualRvalue:
|
|
case ConstraintKind::TrivialSubtype:
|
|
case ConstraintKind::Subtype:
|
|
case ConstraintKind::Conversion:
|
|
case ConstraintKind::Construction:
|
|
assert(Member.empty() && "Relational constraint cannot have a member");
|
|
break;
|
|
|
|
case ConstraintKind::Literal:
|
|
llvm_unreachable("Wrong constructor for literal constraint");
|
|
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;
|
|
}
|
|
}
|
|
|
|
Constraint(Type type, LiteralKind literal, ConstraintLocator *locator)
|
|
: Kind(ConstraintKind::Literal), Literal(literal), First(type),
|
|
Locator(locator) { }
|
|
|
|
/// \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::EqualRvalue:
|
|
case ConstraintKind::TrivialSubtype:
|
|
case ConstraintKind::Subtype:
|
|
case ConstraintKind::Conversion:
|
|
case ConstraintKind::Construction:
|
|
return ConstraintClassification::Relational;
|
|
|
|
case ConstraintKind::Literal:
|
|
return ConstraintClassification::Literal;
|
|
|
|
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 {
|
|
assert(Kind != ConstraintKind::Literal &&
|
|
"No second type for literal constraints");
|
|
return Second;
|
|
}
|
|
|
|
/// \brief Determine whether this constraint kind has a second type.
|
|
static bool hasSecondType(ConstraintKind kind) {
|
|
return kind != ConstraintKind::Literal;
|
|
}
|
|
|
|
/// \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 Determine the kind of literal for a literal constraint.
|
|
LiteralKind getLiteralKind() const {
|
|
assert(Kind == ConstraintKind::Literal && "Not a literal constraint!");
|
|
return Literal;
|
|
}
|
|
|
|
/// \brief Retrieve the locator for this constraint.
|
|
ConstraintLocator *getLocator() const { return Locator; }
|
|
|
|
void print(llvm::raw_ostream &Out, llvm::SourceMgr *sm);
|
|
|
|
void dump(llvm::SourceMgr *sm) 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 equates the member type with the
|
|
/// base type. Used for unresolved member expressions like ".none" that
|
|
/// refer to oneof 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 oneof
|
|
/// 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.
|
|
Type Base;
|
|
|
|
/// \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() : Base(), DeclOrKind() { }
|
|
|
|
OverloadChoice(Type base, ValueDecl *value) : Base(base) {
|
|
DeclOrKind = reinterpret_cast<uintptr_t>(value);
|
|
assert((DeclOrKind & (uintptr_t)0x01) == 0 && "Badly aligned decl");
|
|
}
|
|
|
|
OverloadChoice(Type base, OverloadChoiceKind kind)
|
|
: Base(base), DeclOrKind((uintptr_t)kind << 1 | (uintptr_t)0x01) {
|
|
assert(base && "Must have a base type for overload choice");
|
|
assert(kind != OverloadChoiceKind::Decl && "wrong constructor for decl");
|
|
}
|
|
|
|
OverloadChoice(Type base, unsigned index)
|
|
: Base(base),
|
|
DeclOrKind(((uintptr_t)index
|
|
+ (uintptr_t)OverloadChoiceKind::TupleIndex) << 1
|
|
| (uintptr_t)0x01) {
|
|
assert(base->getRValueType()->is<TupleType>() && "Must have tuple type");
|
|
}
|
|
|
|
/// \brief Retrieve the base type used to refer to the declaration.
|
|
Type getBaseType() const { return Base; }
|
|
|
|
/// \brief Determines the kind of overload choice this is.
|
|
OverloadChoiceKind getKind() const {
|
|
if (DeclOrKind & 0x01) {
|
|
uintptr_t value = DeclOrKind >> 1;
|
|
if (value >= (uintptr_t)OverloadChoiceKind::TupleIndex)
|
|
return OverloadChoiceKind::TupleIndex;
|
|
|
|
return (OverloadChoiceKind)value;
|
|
}
|
|
|
|
return OverloadChoiceKind::Decl;
|
|
}
|
|
|
|
/// \brief Retrieve the declaraton that corresponds to this overload choice.
|
|
ValueDecl *getDecl() const {
|
|
assert(getKind() == OverloadChoiceKind::Decl && "Not a declaration");
|
|
return reinterpret_cast<ValueDecl *>(DeclOrKind);
|
|
}
|
|
|
|
/// \brief Retrieve the tuple index that corresponds to this overload
|
|
/// choice.
|
|
unsigned getTupleIndex() const {
|
|
assert(getKind() == OverloadChoiceKind::TupleIndex);
|
|
return (DeclOrKind >> 1) - (uintptr_t)OverloadChoiceKind::TupleIndex;
|
|
}
|
|
};
|
|
|
|
/// \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)
|
|
: HasNonConcreteConstraints(false), TypeVar(typeVar) {}
|
|
|
|
/// \brief Whether there are any non-concrete constraints placed on this
|
|
/// type variable that aren't represented by the stored \c Constraints.
|
|
bool HasNonConcreteConstraints;
|
|
|
|
/// \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 archetype and literal 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 type of the first to match the rvalue type of the
|
|
/// second.
|
|
SameTypeRvalue,
|
|
/// \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 potential binding of a type variable to another type.
|
|
class PotentialBinding {
|
|
llvm::PointerIntPair<TypeVariableType *, 1, bool> typeVarAndOpen;
|
|
Type type;
|
|
|
|
public:
|
|
PotentialBinding(TypeVariableType *typeVar, Type type, bool openType)
|
|
: typeVarAndOpen(typeVar, openType), type(type) { }
|
|
|
|
/// \brief Retrieve the type variable.
|
|
TypeVariableType *getTypeVariable() const {
|
|
return typeVarAndOpen.getPointer();
|
|
}
|
|
|
|
/// \brief Retrieve the type to which the type variable will be bound.
|
|
Type getType() const { return type; }
|
|
|
|
/// \brief Determine whether the type to which the type variable
|
|
/// will be bound should be opened.
|
|
bool shouldOpenType() const { return typeVarAndOpen.getInt(); }
|
|
};
|
|
|
|
/// \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;
|
|
|
|
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.
|
|
///
|
|
/// \returns the coerced expression, which will have type \c ToType.
|
|
Expr *coerceToType(Expr *expr, Type toType) 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 Dump this solution to standard error.
|
|
void dump(llvm::SourceMgr *sm) const LLVM_ATTRIBUTE_USED;
|
|
};
|
|
|
|
/// \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 {
|
|
TypeChecker &TC;
|
|
ConstraintSystem *Parent = nullptr;
|
|
Constraint *failedConstraint = nullptr;
|
|
|
|
/// \brief Contains state that is shared among all of the child constraint
|
|
/// systems for a given type-checking problem.
|
|
struct SharedStateType {
|
|
/// \brief Allocator used for all of the related constraint systems.
|
|
llvm::BumpPtrAllocator Allocator;
|
|
|
|
/// \brief Arena used for memory management of constraint-checker-related
|
|
/// allocations.
|
|
///
|
|
/// This arena will automatically be destroyed when the top constraint
|
|
/// system is destroyed.
|
|
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>, std::unique_ptr<MemberLookup>>
|
|
MemberLookups;
|
|
|
|
/// \brief Cached literal checks. The key is a canonical type + literal
|
|
/// kind. The value is a tristate of 0 -> uncomputed, 1 -> computed
|
|
/// false, 2 -> computed true.
|
|
llvm::DenseMap<std::pair<CanType, unsigned>, unsigned> LiteralChecks;
|
|
|
|
/// \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 exploring this constraint system.
|
|
llvm::FoldingSet<Failure> Failures;
|
|
|
|
SharedStateType(TypeChecker &tc) : Arena(tc.Context, Allocator) {}
|
|
};
|
|
|
|
/// \brief The state shared among all of the related constraint systems.
|
|
SharedStateType *SharedState;
|
|
|
|
// ---Track the state space we've already explored---
|
|
/// \brief The number of child systems that are still active, i.e., haven't
|
|
/// been found to be unsolvable.
|
|
unsigned NumActiveChildren = 0;
|
|
|
|
/// \brief Whether we have resolved an overload by creating child systems.
|
|
bool ResolvedOverloadsInChildSystems = false;
|
|
|
|
/// \brief Keeps track of the attempted type variable bindings we have
|
|
/// performed in child systems.
|
|
llvm::DenseMap<TypeVariableType *, llvm::SmallPtrSet<CanType, 16>>
|
|
ExploredTypeBindings;
|
|
|
|
/// \brief Keeps track of type variable bindings we should try next,
|
|
/// assuming that none of the current set of type bindings pans out.
|
|
///
|
|
/// These bindings tend to be for supertypes of type variable bindings
|
|
/// we've already attempted.
|
|
SmallVector<PotentialBinding, 16> PotentialBindings;
|
|
|
|
// Valid everywhere
|
|
|
|
/// \brief A mapping from each overload set that is resolved in this
|
|
/// constraint system to a pair (index, type), where index is the index of
|
|
/// the overload choice (within the overload set) and type is the type
|
|
/// implied by that overload.
|
|
llvm::DenseMap<OverloadSet *, std::pair<unsigned, Type>> ResolvedOverloads;
|
|
|
|
/// \brief The type variable for which we are assuming a given particular
|
|
/// type.
|
|
TypeVariableType *assumedTypeVar = nullptr;
|
|
|
|
enum { Active, Unsolvable, Solved } State = Active;
|
|
|
|
SmallVector<TypeVariableType *, 16> TypeVariables;
|
|
SmallVector<Constraint *, 16> Constraints;
|
|
llvm::SmallPtrSet<Constraint *, 4> ExternallySolved;
|
|
SmallVector<OverloadSet *, 4> UnresolvedOverloadSets;
|
|
llvm::DenseMap<ConstraintLocator *, OverloadSet *> GeneratedOverloadSets;
|
|
SmallVector<std::unique_ptr<ConstraintSystem>, 2> Children;
|
|
|
|
/// \brief The set of type variable bindings that have changed while
|
|
/// processing this constraint system.
|
|
SavedTypeVariableBindings SavedBindings;
|
|
|
|
typedef llvm::PointerUnion<TypeVariableType *, TypeBase *>
|
|
RepresentativeOrFixed;
|
|
|
|
// Valid everywhere, for debugging
|
|
SmallVector<Constraint *, 16> SolvedConstraints;
|
|
|
|
unsigned assignTypeVariableID() {
|
|
return SharedState->TypeCounter++;
|
|
}
|
|
|
|
unsigned assignOverloadSetID() {
|
|
return SharedState->OverloadSetCounter++;
|
|
}
|
|
friend class OverloadSet;
|
|
|
|
public:
|
|
ConstraintSystem(TypeChecker &tc);
|
|
|
|
/// \brief Creates a child constraint system that selects a
|
|
/// particular overload from an unresolved overload set.
|
|
///
|
|
/// \param parent The parent constraint system.
|
|
///
|
|
/// \param overloadSetIdx The index into the parent's unresolved
|
|
/// overload set, selecting the overload to be resolved.
|
|
///
|
|
/// \param overloadChoiceIdx The index into the unresolved
|
|
/// overload set identified by \p overloadSetIdx. This index
|
|
/// selects which overload choice this child system will explore.
|
|
ConstraintSystem(ConstraintSystem *parent,
|
|
unsigned overloadSetIdx,
|
|
unsigned overloadChoiceIdx);
|
|
|
|
/// \brief Creates a child constraint system that binds a given
|
|
/// type variable to a given type.
|
|
///
|
|
/// \param parent The parent constraint system.
|
|
///
|
|
/// \param binding The type variable binding we will be exploring
|
|
/// within this child system.
|
|
ConstraintSystem(ConstraintSystem *parent, const PotentialBinding &binding);
|
|
|
|
~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; }
|
|
|
|
/// \brief Retrieve the constraints.
|
|
ArrayRef<Constraint *> getConstraints() const { return Constraints; }
|
|
|
|
/// \brief Retrieve the top-level constraint system.
|
|
ConstraintSystem &getTopConstraintSystem() {
|
|
ConstraintSystem *cs = this;
|
|
while (cs->Parent)
|
|
cs = cs->Parent;
|
|
return *cs;
|
|
}
|
|
|
|
/// \brief Retrieve the depth of this constraint system, i.e., the
|
|
/// number of hops from this constraint system to the top-level constraint
|
|
/// system.
|
|
unsigned getConstraintSystemDepth() const {
|
|
unsigned depth = 0;
|
|
const ConstraintSystem *cs = this;
|
|
while (cs->Parent) {
|
|
++depth;
|
|
cs = cs->Parent;
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
/// \brief Determine whether this constraint system has any child
|
|
/// constraint systems, active or not.
|
|
bool hasChildren() const { return !Children.empty(); }
|
|
|
|
/// \brief Determine whether this constraint system has any active
|
|
/// child constraint systems.
|
|
bool hasActiveChildren() const { return NumActiveChildren > 0; }
|
|
|
|
/// \brief Whether this system has resolved an overload by creating
|
|
/// child systems.
|
|
bool hasResolvedOverloadsInChildSystems() const {
|
|
return ResolvedOverloadsInChildSystems;
|
|
}
|
|
|
|
/// \brief Determine whether this constraint system has any free type
|
|
/// variables.
|
|
bool hasFreeTypeVariables();
|
|
|
|
/// \brief Retrieve the constraint that caused this system to fail.
|
|
Constraint *getFailedConstraint() const { return failedConstraint; }
|
|
|
|
/// \brief Create a new constraint system that is derived from this
|
|
/// constraint system, referencing the rules of the parent system but
|
|
/// also introducing its own (likely dependent) constraints.
|
|
///
|
|
/// The new constraint system will be immediately simplified, and deleted
|
|
/// if simplification fails.
|
|
///
|
|
/// \returns the new constraint system, or null if simplification failed.
|
|
template<typename ...Args>
|
|
ConstraintSystem *createDerivedConstraintSystem(Args &&...args){
|
|
++NumActiveChildren;
|
|
auto result = new ConstraintSystem(this, std::forward<Args>(args)...);
|
|
|
|
// Attempt simplification of the resulting constraint system.
|
|
if (result->simplify()) {
|
|
// The constraint system constraints an error. Delete it now and
|
|
// return a null pointer to indicate failure.
|
|
result->restoreTypeVariableBindings();
|
|
delete result;
|
|
return nullptr;
|
|
}
|
|
|
|
// The system may be solvable. Record and return it.
|
|
Children.push_back(std::unique_ptr<ConstraintSystem>(result));
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
/// \brief Indicates that the given child constraint system is inactive
|
|
/// (i.e., unsolvable).
|
|
void markChildInactive(ConstraintSystem *childCS);
|
|
|
|
/// \brief Indicates that this constraint system is unsolvable.
|
|
void markUnsolvable() {
|
|
State = Unsolvable;
|
|
if (Parent)
|
|
Parent->markChildInactive(this);
|
|
}
|
|
|
|
/// \brief Finalize this constraint system; we're done attempting to solve
|
|
/// it.
|
|
///
|
|
/// \returns an empty solution if this constraint system is unsolvable.
|
|
Optional<Solution> finalize();
|
|
|
|
private:
|
|
/// \brief Remove any inactive (== unsolvable) children.
|
|
void removeInactiveChildren();
|
|
|
|
/// \brief Create the solution based on this constraint system.
|
|
Solution createSolution();
|
|
|
|
/// \brief Clear out any 'intermediate' data that is no longer useful when
|
|
/// all of the child systems are standalone.
|
|
void clearIntermediateData();
|
|
|
|
/// \brief Restore the type variable bindings to what they were before
|
|
/// we attempted to solve this constraint system.
|
|
void restoreTypeVariableBindings();
|
|
|
|
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.
|
|
MemberLookup &lookupMember(Type base, Identifier name);
|
|
|
|
/// \brief Retrieve an unresolved overload set.
|
|
OverloadSet *getUnresolvedOverloadSet(unsigned Idx) const {
|
|
return UnresolvedOverloadSets[Idx];
|
|
}
|
|
|
|
/// \brief Determine the number of unresolved overload sets in
|
|
/// this constraint system.
|
|
unsigned getNumUnresolvedOverloadSets() const {
|
|
return UnresolvedOverloadSets.size();
|
|
}
|
|
|
|
/// \brief Determine whether this constraint system has any potential
|
|
/// bindings.
|
|
bool hasPotentialBindings() const {
|
|
return !PotentialBindings.empty();
|
|
}
|
|
|
|
/// \brief Create a new type variable.
|
|
template<typename ...Args>
|
|
TypeVariableType *createTypeVariable(Args &&...args) {
|
|
auto tv = TypeVariableType::getNew(TC.Context, assignTypeVariableID(),
|
|
std::forward<Args>(args)...);
|
|
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);
|
|
|
|
/// \brief Record failure with already-simplified arguments.
|
|
template<typename ...Args>
|
|
void recordFailureSimplified(ConstraintLocator *locator,
|
|
Failure::FailureKind kind,
|
|
Args &&...args) {
|
|
// Check whether we've recorded this failure already. If so, we're done.
|
|
llvm::FoldingSetNodeID id;
|
|
Failure::Profile(id, locator, kind, args...);
|
|
auto &failures = SharedState->Failures;
|
|
void *insertPos = nullptr;
|
|
if (failures.FindNodeOrInsertPos(id, insertPos))
|
|
return;
|
|
|
|
// Allocate a new failure and record it.
|
|
auto failure = Failure::create(getAllocator(), locator, kind, args...);
|
|
failures.InsertNode(failure, insertPos);
|
|
}
|
|
|
|
/// \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).
|
|
LiteralKind simplifyFailureArg(LiteralKind arg) {
|
|
return arg;
|
|
}
|
|
|
|
/// \brief Simplifies an argument to the failure (a no-op).
|
|
Identifier simplifyFailureArg(Identifier arg) {
|
|
return arg;
|
|
}
|
|
|
|
/// \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) {
|
|
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.
|
|
///
|
|
/// \returns true if this constraint was solved.
|
|
bool addConstraint(Constraint *constraint,
|
|
bool isExternallySolved = 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 first type");
|
|
addConstraint(new (*this) Constraint(kind, first, second, Identifier(),
|
|
locator));
|
|
}
|
|
|
|
///\ brief Add a literal constraint to the constraint system.
|
|
void addLiteralConstraint(Type type, LiteralKind kind,
|
|
ConstraintLocator *locator = nullptr) {
|
|
assert(type && "missing type for literal constraint");
|
|
addConstraint(new (*this) Constraint(type, kind, 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());
|
|
|
|
// The type of the type member is the metatype of the declared type.
|
|
Type memberMetaTy = MetaTypeType::get(memberTy, getASTContext());
|
|
|
|
addConstraint(new (*this) Constraint(ConstraintKind::TypeMember,
|
|
baseTy, memberMetaTy, 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(&SavedBindings);
|
|
}
|
|
|
|
/// \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, SavedBindings);
|
|
}
|
|
|
|
/// \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(&SavedBindings);
|
|
}
|
|
|
|
/// \brief Assign a fixed type to the given type variable.
|
|
void assignFixedType(TypeVariableType *typeVar, Type type) {
|
|
typeVar->getImpl().assignFixedType(type, SavedBindings);
|
|
}
|
|
|
|
/// \brief Determine whether we have already explored type bindings for
|
|
/// the given type variable via child systems.
|
|
bool haveExploredTypeVar(TypeVariableType *typeVar) {
|
|
return ExploredTypeBindings.count(typeVar) > 0;
|
|
}
|
|
|
|
/// \brief Add a new potential binding of a type variable to a particular
|
|
/// type, to be explored by a child system.
|
|
void addPotentialBinding(const PotentialBinding &binding) {
|
|
PotentialBindings.push_back(binding);
|
|
}
|
|
|
|
/// \brief Indicate a design to explore a specific binding for the given
|
|
/// type variable.
|
|
///
|
|
/// \returns true if this type variable binding should be explored,
|
|
/// or false if it has already been explored.
|
|
bool exploreBinding(TypeVariableType *typeVar, Type binding) {
|
|
return ExploredTypeBindings[typeVar].insert(binding->getCanonicalType());
|
|
}
|
|
|
|
/// \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
|
|
/// 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 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.
|
|
Type getTypeOfReference(ValueDecl *decl);
|
|
|
|
/// \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.
|
|
Type getTypeOfMemberReference(Type baseTy, ValueDecl *decl,
|
|
bool isTypeReference);
|
|
|
|
/// \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 Find the overload choice that was assumed by this constraint
|
|
/// system (or one of its parents), along with the type it was given.
|
|
Optional<std::pair<OverloadChoice, Type>>
|
|
getSelectedOverloadFromSet(OverloadSet *ovl);
|
|
|
|
/// \brief Retrieve the allocator used by this constraint system.
|
|
llvm::BumpPtrAllocator &getAllocator() { return SharedState->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 true if an error occurred.
|
|
bool generateConstraints(Expr *E);
|
|
|
|
/// \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
|
|
};
|
|
|
|
private:
|
|
/// \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 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 Record failures when they occur.
|
|
TMF_RecordFailures = 0x02
|
|
};
|
|
|
|
/// \brief Subroutine of \c matchTypes(), which matches up two tuple types.
|
|
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 literal constraint.
|
|
SolutionKind simplifyLiteralConstraint(Type type, LiteralKind kind,
|
|
ConstraintLocator *locator);
|
|
|
|
/// \brief Attempt to simplify the given member constraint.
|
|
SolutionKind simplifyMemberConstraint(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.
|
|
///
|
|
/// \returns true if an error occurred, false otherwise.
|
|
bool solve(SmallVectorImpl<Solution> &solutions);
|
|
|
|
/// \brief Determine whether this constraint system is fully solved, with
|
|
/// no free variables.
|
|
bool isSolved() const { return State == Solved; }
|
|
|
|
private:
|
|
/// \brief Determine whether the given \p type matches the default literal
|
|
/// type for a literal constraint placed on the type variable \p tv.
|
|
bool typeMatchesDefaultLiteralConstraint(TypeVariableType *tv,
|
|
Type type);
|
|
|
|
// \brief Compare two solutions to the same set of constraints.
|
|
static SolutionCompareResult compareSolutions(ConstraintSystem &cs,
|
|
const Solution &sol1,
|
|
const Solution &sol2);
|
|
|
|
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);
|
|
|
|
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.
|
|
///
|
|
/// \returns true if no tuple conversion is possible, false otherwise.
|
|
bool computeTupleShuffle(TupleType *fromTuple, TupleType *toTuple,
|
|
SmallVectorImpl<int> &sources,
|
|
SmallVectorImpl<unsigned> &variadicArgs);
|
|
|
|
} // end namespace constraints
|
|
|
|
template<typename ...Args>
|
|
TypeVariableType *TypeVariableType::getNew(ASTContext &C, 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);
|
|
|
|
// 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
|