Files
swift-mirror/lib/Sema/CSSimplify.cpp
Doug Gregor 97a2df25c5 Add a new conversion and type-matching kind for argument tuples.
We're going to give argument-tuple handling special behavior; separate
it out first.

Swift SVN r17095
2014-04-30 15:32:50 +00:00

2380 lines
85 KiB
C++

//===--- CSSimplify.cpp - Constraint Simplification -----------------------===//
//
// 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 implements simplifications of constraints within the constraint
// system.
//
//===----------------------------------------------------------------------===//
#include "ConstraintSystem.h"
using namespace swift;
using namespace constraints;
static bool hasMandatoryTupleLabels(const ConstraintLocatorBuilder &locator) {
if (Expr *e = locator.trySimplifyToExpr())
return hasMandatoryTupleLabels(e);
return false;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
unsigned subFlags = flags | TMF_GenerateConstraints;
// Equality and subtyping have fairly strict requirements on tuple matching,
// requiring element names to either match up or be disjoint.
if (kind < TypeMatchKind::Conversion) {
if (tuple1->getFields().size() != tuple2->getFields().size()) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::TupleSizeMismatch, tuple1, tuple2);
}
return SolutionKind::Error;
}
for (unsigned i = 0, n = tuple1->getFields().size(); i != n; ++i) {
const auto &elt1 = tuple1->getFields()[i];
const auto &elt2 = tuple2->getFields()[i];
// If the names don't match, we may have a conflict.
if (elt1.getName() != elt2.getName()) {
// Same-type requirements require exact name matches.
if (kind == TypeMatchKind::SameType) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(
locator.withPathElement(
LocatorPathElt::getNamedTupleElement(i))),
Failure::TupleNameMismatch, tuple1, tuple2);
}
return SolutionKind::Error;
}
// For subtyping constraints, just make sure that this name isn't
// used at some other position.
if (elt2.hasName()) {
int matched = tuple1->getNamedElementId(elt2.getName());
if (matched != -1) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(
locator.withPathElement(
LocatorPathElt::getNamedTupleElement(i))),
Failure::TupleNamePositionMismatch, tuple1, tuple2);
}
return SolutionKind::Error;
}
}
}
// Variadic bit must match.
if (elt1.isVararg() != elt2.isVararg()) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(
locator.withPathElement(
LocatorPathElt::getNamedTupleElement(i))),
Failure::TupleVariadicMismatch, tuple1, tuple2);
}
return SolutionKind::Error;
}
// Compare the element types.
switch (matchTypes(elt1.getType(), elt2.getType(), kind, subFlags,
locator.withPathElement(
LocatorPathElt::getTupleElement(i)))) {
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
case SolutionKind::Unsolved:
break;
}
}
return SolutionKind::Solved;
}
assert(kind >= TypeMatchKind::Conversion);
// Compute the element shuffles for conversions.
SmallVector<int, 16> sources;
SmallVector<unsigned, 4> variadicArguments;
if (computeTupleShuffle(tuple1, tuple2, sources, variadicArguments,
::hasMandatoryTupleLabels(locator))) {
// FIXME: Record why the tuple shuffle couldn't be computed.
if (shouldRecordFailures()) {
if (tuple1->getNumElements() != tuple2->getNumElements()) {
recordFailure(getConstraintLocator(locator),
Failure::TupleSizeMismatch, tuple1, tuple2);
}
}
return SolutionKind::Error;
}
// Check each of the elements.
bool hasVarArg = false;
for (unsigned idx2 = 0, n = sources.size(); idx2 != n; ++idx2) {
// Default-initialization always allowed for conversions.
if (sources[idx2] == TupleShuffleExpr::DefaultInitialize) {
continue;
}
// Variadic arguments handled below.
if (sources[idx2] == TupleShuffleExpr::FirstVariadic) {
hasVarArg = true;
continue;
}
assert(sources[idx2] >= 0);
unsigned idx1 = sources[idx2];
// Match up the types.
const auto &elt1 = tuple1->getFields()[idx1];
const auto &elt2 = tuple2->getFields()[idx2];
switch (matchTypes(elt1.getType(), elt2.getType(), kind, subFlags,
locator.withPathElement(
LocatorPathElt::getTupleElement(idx1)))) {
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
case SolutionKind::Unsolved:
break;
}
}
// If we have variadic arguments to check, do so now.
if (hasVarArg) {
const auto &elt2 = tuple2->getFields().back();
auto eltType2 = elt2.getVarargBaseTy();
for (unsigned idx1 : variadicArguments) {
switch (matchTypes(tuple1->getElementType(idx1), eltType2, kind, subFlags,
locator.withPathElement(
LocatorPathElt::getTupleElement(idx1)))) {
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
case SolutionKind::Unsolved:
break;
}
}
}
return SolutionKind::Solved;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchScalarToTupleTypes(Type type1, TupleType *tuple2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
int scalarFieldIdx = tuple2->getFieldForScalarInit();
assert(scalarFieldIdx >= 0 && "Invalid tuple for scalar-to-tuple");
const auto &elt = tuple2->getFields()[scalarFieldIdx];
auto scalarFieldTy = elt.isVararg()? elt.getVarargBaseTy() : elt.getType();
return matchTypes(type1, scalarFieldTy, kind, flags,
locator.withPathElement(ConstraintLocator::ScalarToTuple));
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchTupleToScalarTypes(TupleType *tuple1, Type type2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
assert(tuple1->getNumElements() == 1 && "Wrong number of elements");
assert(!tuple1->getFields()[0].isVararg() && "Should not be variadic");
return matchTypes(tuple1->getElementType(0),
type2, kind, flags,
locator.withPathElement(
LocatorPathElt::getTupleElement(0)));
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
// An @auto_closure function type can be a subtype of a
// non-@auto_closure function type.
if (func1->isAutoClosure() != func2->isAutoClosure()) {
if (func2->isAutoClosure() || kind < TypeMatchKind::Subtype) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::FunctionAutoclosureMismatch, func1, func2);
}
return SolutionKind::Error;
}
}
// A @noreturn function type can be a subtype of a non-@noreturn function
// type.
if (func1->isNoReturn() != func2->isNoReturn()) {
if (func2->isNoReturn() || kind < TypeMatchKind::SameType) {
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::FunctionNoReturnMismatch, func1, func2);
}
return SolutionKind::Error;
}
}
// Determine how we match up the input/result types.
TypeMatchKind subKind;
switch (kind) {
case TypeMatchKind::BindType:
case TypeMatchKind::SameType:
subKind = kind;
break;
case TypeMatchKind::Subtype:
case TypeMatchKind::Conversion:
case TypeMatchKind::ArgumentTupleConversion:
case TypeMatchKind::OperatorConversion:
subKind = TypeMatchKind::Subtype;
break;
}
unsigned subFlags = flags | TMF_GenerateConstraints;
// Input types can be contravariant (or equal).
SolutionKind result = matchTypes(func2->getInput(), func1->getInput(),
subKind, subFlags,
locator.withPathElement(
ConstraintLocator::FunctionArgument));
if (result == SolutionKind::Error)
return SolutionKind::Error;
// Result type can be covariant (or equal).
switch (matchTypes(func1->getResult(), func2->getResult(), subKind,
subFlags,
locator.withPathElement(
ConstraintLocator::FunctionResult))) {
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
result = SolutionKind::Solved;
break;
case SolutionKind::Unsolved:
result = SolutionKind::Unsolved;
break;
}
return result;
}
/// \brief Map a failed type-matching kind to a failure kind, generically.
static Failure::FailureKind getRelationalFailureKind(TypeMatchKind kind) {
switch (kind) {
case TypeMatchKind::BindType:
case TypeMatchKind::SameType:
return Failure::TypesNotEqual;
case TypeMatchKind::Subtype:
return Failure::TypesNotSubtypes;
case TypeMatchKind::Conversion:
case TypeMatchKind::OperatorConversion:
case TypeMatchKind::ArgumentTupleConversion:
return Failure::TypesNotConvertible;
}
llvm_unreachable("unhandled type matching kind");
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchSuperclassTypes(Type type1, Type type2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
auto classDecl2 = type2->getClassOrBoundGenericClass();
bool done = false;
for (auto super1 = TC.getSuperClassOf(type1);
!done && super1;
super1 = TC.getSuperClassOf(super1)) {
if (super1->getClassOrBoundGenericClass() != classDecl2)
continue;
return matchTypes(super1, type2, TypeMatchKind::SameType,
TMF_GenerateConstraints, locator);
}
// Record this failure.
// FIXME: Specialize diagnostic.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
getRelationalFailureKind(kind), type1, type2);
}
return SolutionKind::Error;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
ConstraintLocatorBuilder locator) {
// Handle nominal types that are not directly generic.
if (auto nominal1 = type1->getAs<NominalType>()) {
auto nominal2 = type2->castTo<NominalType>();
assert((bool)nominal1->getParent() == (bool)nominal2->getParent() &&
"Mismatched parents of nominal types");
if (!nominal1->getParent())
return SolutionKind::Solved;
// Match up the parents, exactly.
return matchTypes(nominal1->getParent(), nominal2->getParent(),
TypeMatchKind::SameType, TMF_GenerateConstraints,
locator.withPathElement(ConstraintLocator::ParentType));
}
auto bound1 = type1->castTo<BoundGenericType>();
auto bound2 = type2->castTo<BoundGenericType>();
// Match up the parents, exactly, if there are parents.
assert((bool)bound1->getParent() == (bool)bound2->getParent() &&
"Mismatched parents of bound generics");
if (bound1->getParent()) {
switch (matchTypes(bound1->getParent(), bound2->getParent(),
TypeMatchKind::SameType, TMF_GenerateConstraints,
locator.withPathElement(ConstraintLocator::ParentType))){
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
case SolutionKind::Unsolved:
break;
}
}
// Match up the generic arguments, exactly.
auto args1 = bound1->getGenericArgs();
auto args2 = bound2->getGenericArgs();
assert(args1.size() == args2.size() && "Mismatched generic args");
for (unsigned i = 0, n = args1.size(); i != n; ++i) {
switch (matchTypes(args1[i], args2[i], TypeMatchKind::SameType,
TMF_GenerateConstraints,
locator.withPathElement(
LocatorPathElt::getGenericArgument(i)))) {
case SolutionKind::Error:
return SolutionKind::Error;
case SolutionKind::Solved:
case SolutionKind::Unsolved:
break;
}
}
return SolutionKind::Solved;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
TypeMatchKind kind, unsigned flags,
ConstraintLocatorBuilder locator) {
SmallVector<ProtocolDecl *, 4> protocols;
type2->getAnyExistentialTypeProtocols(protocols);
for (auto proto : protocols) {
switch (simplifyConformsToConstraint(type1, proto, locator, false)) {
case SolutionKind::Solved:
break;
case SolutionKind::Unsolved:
// Add the constraint.
addConstraint(ConstraintKind::ConformsTo, type1,
proto->getDeclaredType());
break;
case SolutionKind::Error:
return SolutionKind::Error;
}
}
return SolutionKind::Solved;
}
/// \brief Map a type-matching kind to a constraint kind.
static ConstraintKind getConstraintKind(TypeMatchKind kind) {
switch (kind) {
case TypeMatchKind::BindType:
return ConstraintKind::Bind;
case TypeMatchKind::SameType:
return ConstraintKind::Equal;
case TypeMatchKind::Subtype:
return ConstraintKind::Subtype;
case TypeMatchKind::Conversion:
return ConstraintKind::Conversion;
case TypeMatchKind::ArgumentTupleConversion:
return ConstraintKind::ArgumentTupleConversion;
case TypeMatchKind::OperatorConversion:
return ConstraintKind::OperatorConversion;
}
llvm_unreachable("unhandled type matching kind");
}
/// Determine whether we should attempt a user-defined conversion.
static bool shouldTryUserConversion(ConstraintSystem &cs, Type type) {
// Strip the l-value qualifier if present.
type = type->getRValueType();
// If this isn't a type that can have user-defined conversions, there's
// nothing to do.
if (!type->getNominalOrBoundGenericNominal() && !type->is<ArchetypeType>())
return false;
// If there are no user-defined conversions, there's nothing to do.
// FIXME: lame name!
auto &ctx = cs.getASTContext();
auto name = ctx.getIdentifier("__conversion");
return static_cast<bool>(cs.lookupMember(type, name));
}
/// If the given type has user-defined conversions, introduce new
/// relational constraint between the result of performing the user-defined
/// conversion and an arbitrary other type.
static ConstraintSystem::SolutionKind
tryUserConversion(ConstraintSystem &cs, Type type, ConstraintKind kind,
Type otherType, ConstraintLocatorBuilder locator) {
assert(kind != ConstraintKind::Construction &&
kind != ConstraintKind::Conversion &&
kind != ConstraintKind::ArgumentTupleConversion &&
kind != ConstraintKind::OperatorConversion &&
"Construction/conversion constraints create potential cycles");
// If this isn't a type that can have user-defined conversions, there's
// nothing to do.
if (!shouldTryUserConversion(cs, type))
return ConstraintSystem::SolutionKind::Unsolved;
auto memberLocator = cs.getConstraintLocator(
locator.withPathElement(
ConstraintLocator::ConversionMember));
auto inputTV = cs.createTypeVariable(
cs.getConstraintLocator(memberLocator,
ConstraintLocator::ApplyArgument),
/*options=*/0);
auto outputTV = cs.createTypeVariable(
cs.getConstraintLocator(memberLocator,
ConstraintLocator::ApplyFunction),
/*options=*/0);
auto &ctx = cs.getASTContext();
auto name = ctx.getIdentifier("__conversion");
// The conversion function will have function type TI -> TO, for fresh
// type variables TI and TO.
cs.addValueMemberConstraint(type, name,
FunctionType::get(inputTV, outputTV),
memberLocator);
// A conversion function must accept an empty parameter list ().
// Note: This should never fail, because the declaration checker
// should ensure that conversions have no non-defaulted parameters.
cs.addConstraint(ConstraintKind::ArgumentTupleConversion,
TupleType::getEmpty(ctx),
inputTV, cs.getConstraintLocator(locator));
// Relate the output of the conversion function to the other type, using
// the provided constraint kind.
// If the type we're converting to is existential, we can also have an
// existential conversion here, so introduce a disjunction.
auto resultLocator = cs.getConstraintLocator(
locator.withPathElement(
ConstraintLocator::ConversionResult));
if (otherType->isExistentialType()) {
Constraint *constraints[2] = {
Constraint::create(cs, kind, outputTV, otherType, Identifier(),
resultLocator),
Constraint::createRestricted(cs, ConstraintKind::Conversion,
ConversionRestrictionKind::Existential,
outputTV, otherType, resultLocator)
};
cs.addConstraint(Constraint::createDisjunction(cs, constraints,
resultLocator));
} else {
cs.addConstraint(kind, outputTV, otherType, resultLocator);
}
// We're adding a user-defined conversion.
cs.increaseScore(SK_UserConversion);
return ConstraintSystem::SolutionKind::Solved;
}
/// Determine whether this is a function type accepting no arguments as input.
static bool isFunctionTypeAcceptingNoArguments(Type type) {
// The type must be a function type.
auto fnType = type->getAs<AnyFunctionType>();
if (!fnType)
return false;
// Only tuple arguments make sense.
auto tupleTy = fnType->getInput()->getAs<TupleType>();
if (!tupleTy) return false;
// Look for any non-defaulted, non-variadic elements.
for (const auto &elt : tupleTy->getFields()) {
// Defaulted arguments are okay.
if (elt.getDefaultArgKind() != DefaultArgumentKind::None)
continue;
// Variadic arguments are okay.
if (elt.isVararg())
continue;
return false;
}
return true;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
unsigned flags,
ConstraintLocatorBuilder locator) {
// If we have type variables that have been bound to fixed types, look through
// to the fixed type.
TypeVariableType *typeVar1;
type1 = getFixedTypeRecursive(type1, typeVar1,
kind == TypeMatchKind::SameType);
auto desugar1 = type1->getDesugaredType();
TypeVariableType *typeVar2;
type2 = getFixedTypeRecursive(type2, typeVar2,
kind == TypeMatchKind::SameType);
auto desugar2 = type2->getDesugaredType();
// If the types are obviously equivalent, we're done.
if (desugar1 == desugar2)
return SolutionKind::Solved;
// If either (or both) types are type variables, unify the type variables.
if (typeVar1 || typeVar2) {
switch (kind) {
case TypeMatchKind::BindType:
case TypeMatchKind::SameType: {
if (typeVar1 && typeVar2) {
auto rep1 = getRepresentative(typeVar1);
auto rep2 = getRepresentative(typeVar2);
if (rep1 == rep2) {
// We already merged these two types, so this constraint is
// trivially solved.
return SolutionKind::Solved;
}
// If exactly one of the type variables can bind to an lvalue, we
// can't merge these two type variables.
if (rep1->getImpl().canBindToLValue()
!= rep2->getImpl().canBindToLValue()) {
if (flags & TMF_GenerateConstraints) {
// Add a new constraint between these types. We consider the current
// type-matching problem to the "solved" by this addition, because
// this new constraint will be solved at a later point.
// Obviously, this must not happen at the top level, or the
// algorithm would not terminate.
addConstraint(getConstraintKind(kind), rep1, rep2,
getConstraintLocator(locator));
return SolutionKind::Solved;
}
return SolutionKind::Unsolved;
}
// Merge the equivalence classes corresponding to these two variables.
mergeEquivalenceClasses(rep1, rep2);
return SolutionKind::Solved;
}
// Provide a fixed type for the type variable.
bool wantRvalue = kind == TypeMatchKind::SameType;
if (typeVar1) {
// If we want an rvalue, get the rvalue.
if (wantRvalue)
type2 = type2->getRValueType();
// If the left-hand type variable cannot bind to an lvalue,
// but we still have an lvalue, fail.
if (!typeVar1->getImpl().canBindToLValue()) {
if (type2->is<LValueType>()) {
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::IsForbiddenLValue, type1, type2);
}
return SolutionKind::Error;
}
// Okay. Bind below.
}
assignFixedType(typeVar1, type2);
return SolutionKind::Solved;
}
// If we want an rvalue, get the rvalue.
if (wantRvalue)
type1 = type1->getRValueType();
if (!typeVar2->getImpl().canBindToLValue()) {
if (type1->is<LValueType>()) {
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::IsForbiddenLValue, type1, type2);
}
return SolutionKind::Error;
}
// Okay. Bind below.
}
assignFixedType(typeVar2, type1);
return SolutionKind::Solved;
}
case TypeMatchKind::Subtype:
case TypeMatchKind::Conversion:
case TypeMatchKind::ArgumentTupleConversion:
case TypeMatchKind::OperatorConversion:
if (flags & TMF_GenerateConstraints) {
// Add a new constraint between these types. We consider the current
// type-matching problem to the "solved" by this addition, because
// this new constraint will be solved at a later point.
// Obviously, this must not happen at the top level, or the algorithm
// would not terminate.
addConstraint(getConstraintKind(kind), type1, type2,
getConstraintLocator(locator));
return SolutionKind::Solved;
}
// We couldn't solve this constraint. If only one of the types is a type
// variable, perhaps we can do something with it below.
if (typeVar1 && typeVar2)
return typeVar1 == typeVar2 ? SolutionKind::Solved
: SolutionKind::Unsolved;
break;
}
}
llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
bool concrete = !typeVar1 && !typeVar2;
// Decompose parallel structure.
unsigned subFlags = (flags | TMF_GenerateConstraints) & ~TMF_ApplyingFix;
if (desugar1->getKind() == desugar2->getKind()) {
switch (desugar1->getKind()) {
#define SUGARED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
llvm_unreachable("Type has not been desugared completely");
#define ARTIFICIAL_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
llvm_unreachable("artificial type in constraint");
#define BUILTIN_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
case TypeKind::Module:
if (desugar1 == desugar2) {
return SolutionKind::Solved;
}
// Record this failure.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
getRelationalFailureKind(kind), type1, type2);
}
return SolutionKind::Error;
case TypeKind::Error:
return SolutionKind::Error;
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type in type checker");
case TypeKind::TypeVariable:
case TypeKind::Archetype:
// Nothing to do here; handle type variables and archetypes below.
break;
case TypeKind::Tuple: {
// Try the tuple-to-tuple conversion.
conversionsOrFixes.push_back(ConversionRestrictionKind::TupleToTuple);
break;
}
case TypeKind::Enum:
case TypeKind::Struct:
case TypeKind::Class: {
auto nominal1 = cast<NominalType>(desugar1);
auto nominal2 = cast<NominalType>(desugar2);
if (nominal1->getDecl() == nominal2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
break;
}
case TypeKind::DynamicSelf:
// FIXME: Deep equality? What is the rule between two DynamicSelfs?
break;
case TypeKind::Protocol:
// Nothing to do here; try existential and user-defined conversions below.
break;
case TypeKind::Metatype:
case TypeKind::ExistentialMetatype: {
auto meta1 = cast<AnyMetatypeType>(desugar1);
auto meta2 = cast<AnyMetatypeType>(desugar2);
// metatype<B> < metatype<A> if A < B and both A and B are classes.
TypeMatchKind subKind = TypeMatchKind::SameType;
if (isa<MetatypeType>(desugar1) &&
kind != TypeMatchKind::SameType &&
(meta1->getInstanceType()->mayHaveSuperclass() ||
meta2->getInstanceType()->getClassOrBoundGenericClass()))
subKind = std::min(kind, TypeMatchKind::Subtype);
return matchTypes(meta1->getInstanceType(), meta2->getInstanceType(),
subKind, subFlags,
locator.withPathElement(
ConstraintLocator::InstanceType));
}
case TypeKind::Function:
return matchFunctionTypes(cast<FunctionType>(desugar1),
cast<FunctionType>(desugar2),
kind, flags, locator);
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction:
llvm_unreachable("Polymorphic function type should have been opened");
case TypeKind::ProtocolComposition:
// Existential types handled below.
break;
case TypeKind::LValue:
return matchTypes(cast<LValueType>(desugar1)->getObjectType(),
cast<LValueType>(desugar2)->getObjectType(),
TypeMatchKind::SameType, subFlags,
locator.withPathElement(
ConstraintLocator::ArrayElementType));
case TypeKind::InOut:
// If the RHS is an inout type, the LHS must be an @lvalue type.
if (kind >= TypeMatchKind::OperatorConversion) {
if (shouldRecordFailures())
recordFailure(getConstraintLocator(locator),
Failure::IsForbiddenLValue, type1, type2);
return SolutionKind::Error;
}
return matchTypes(cast<InOutType>(desugar1)->getObjectType(),
cast<InOutType>(desugar2)->getObjectType(),
TypeMatchKind::SameType, subFlags,
locator.withPathElement(ConstraintLocator::ArrayElementType));
case TypeKind::UnboundGeneric:
llvm_unreachable("Unbound generic type should have been opened");
case TypeKind::BoundGenericClass:
case TypeKind::BoundGenericEnum:
case TypeKind::BoundGenericStruct: {
auto bound1 = cast<BoundGenericType>(desugar1);
auto bound2 = cast<BoundGenericType>(desugar2);
if (bound1->getDecl() == bound2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
break;
}
}
}
if (concrete && kind >= TypeMatchKind::Subtype) {
auto tuple1 = type1->getAs<TupleType>();
auto tuple2 = type2->getAs<TupleType>();
// Detect when the source and destination are both permit scalar
// conversions, but the source has a name and the destination does not have
// the same name.
bool tuplesWithMismatchedNames = false;
if (tuple1 && tuple2) {
int scalar1 = tuple1->getFieldForScalarInit();
int scalar2 = tuple2->getFieldForScalarInit();
if (scalar1 >= 0 && scalar2 >= 0) {
auto name1 = tuple1->getFields()[scalar1].getName();
auto name2 = tuple2->getFields()[scalar2].getName();
tuplesWithMismatchedNames = !name1.empty() && name1 != name2;
}
}
if (tuple2 && !tuplesWithMismatchedNames) {
// A scalar type is a trivial subtype of a one-element, non-variadic tuple
// containing a single element if the scalar type is a subtype of
// the type of that tuple's element.
//
// A scalar type can be converted to a tuple so long as there is at
// most one non-defaulted element.
if ((tuple2->getFields().size() == 1 &&
!tuple2->getFields()[0].isVararg()) ||
(kind >= TypeMatchKind::Conversion &&
tuple2->getFieldForScalarInit() >= 0)) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::ScalarToTuple);
// FIXME: Prohibits some user-defined conversions for tuples.
goto commit_to_conversions;
}
}
if (tuple1 && !tuplesWithMismatchedNames) {
// A single-element tuple can be a trivial subtype of a scalar.
if (tuple1->getFields().size() == 1 &&
!tuple1->getFields()[0].isVararg()) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::TupleToScalar);
}
}
// Subclass-to-superclass conversion.
if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass() &&
type2->getClassOrBoundGenericClass() &&
type1->getClassOrBoundGenericClass()
!= type2->getClassOrBoundGenericClass()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::Superclass);
}
// Array supertype conversions.
if (kind >= TypeMatchKind::Conversion) {
if ((isArrayType(desugar1) && isArrayType(desugar2)) ||
(isSliceType(desugar1) && isSliceType(desugar2)) ||
(isNativeArrayType(desugar1) && isNativeArrayType(desugar2))) {
conversionsOrFixes.push_back(ConversionRestrictionKind::
ArrayUpcast);
}
}
}
if (concrete && kind >= TypeMatchKind::Conversion) {
// An lvalue of type T1 can be converted to a value of type T2 so long as
// T1 is convertible to T2 (by loading the value).
if (type1->is<LValueType>())
conversionsOrFixes.push_back(
ConversionRestrictionKind::LValueToRValue);
// An expression can be converted to an auto-closure function type, creating
// an implicit closure.
if (auto function2 = type2->getAs<FunctionType>()) {
if (function2->isAutoClosure())
return matchTypes(type1, function2->getResult(), kind, subFlags,
locator.withPathElement(ConstraintLocator::Load));
}
}
if (concrete && kind >= TypeMatchKind::OperatorConversion) {
// If the RHS is an inout type, the LHS must be an @lvalue type.
if (auto *iot = type2->getAs<InOutType>()) {
return matchTypes(type1, LValueType::get(iot->getObjectType()),
kind, subFlags,
locator.withPathElement(
ConstraintLocator::ArrayElementType));
}
}
// For a subtyping relation involving a conversion to an existential
// metatype, match the child types.
if (concrete && kind >= TypeMatchKind::Subtype) {
if (auto meta1 = type1->getAs<MetatypeType>()) {
if (auto meta2 = type2->getAs<ExistentialMetatypeType>()) {
return matchTypes(meta1->getInstanceType(),
meta2->getInstanceType(),
TypeMatchKind::Subtype, subFlags,
locator.withPathElement(
ConstraintLocator::InstanceType));
}
}
}
// For a subtyping relation involving two existential types or subtyping of
// a class existential type, or a conversion from any type to an
// existential type, check whether the first type conforms to each of the
// protocols in the second type.
if (concrete && kind >= TypeMatchKind::Subtype &&
type2->isExistentialType()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::Existential);
}
// A value of type T can be converted to type U? if T is convertible to U.
// A value of type T? can be converted to type U? if T is convertible to U.
// The above conversions also apply to unchecked optional types, except
// that there is no implicit conversion from T? to T!.
{
BoundGenericType *boundGenericType2;
if (concrete && kind >= TypeMatchKind::Subtype &&
(boundGenericType2 = type2->getAs<BoundGenericType>())) {
auto decl2 = boundGenericType2->getDecl();
if (auto optionalKind2 = decl2->classifyAsOptionalType()) {
assert(boundGenericType2->getGenericArgs().size() == 1);
BoundGenericType *boundGenericType1 = type1->getAs<BoundGenericType>();
if (boundGenericType1) {
auto decl1 = boundGenericType1->getDecl();
if (decl1 == decl2) {
assert(boundGenericType1->getGenericArgs().size() == 1);
conversionsOrFixes.push_back(
ConversionRestrictionKind::OptionalToOptional);
} else if (optionalKind2 == OTK_Optional &&
decl1 == TC.Context.getUncheckedOptionalDecl()) {
assert(boundGenericType1->getGenericArgs().size() == 1);
conversionsOrFixes.push_back(
ConversionRestrictionKind::UncheckedOptionalToOptional);
} else if (optionalKind2 == OTK_UncheckedOptional &&
kind >= TypeMatchKind::Conversion &&
decl1 == TC.Context.getOptionalDecl()) {
assert(boundGenericType1->getGenericArgs().size() == 1);
conversionsOrFixes.push_back(
ConversionRestrictionKind::OptionalToUncheckedOptional);
}
}
conversionsOrFixes.push_back(
ConversionRestrictionKind::ValueToOptional);
}
}
}
// A value of type T! can be (unsafely) forced to U if T
// is convertible to U.
{
Type objectType1;
if (concrete && kind >= TypeMatchKind::Conversion &&
(objectType1 = lookThroughUncheckedOptionalType(type1))) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::ForceUnchecked);
}
}
// A nominal type can be converted to another type via a user-defined
// conversion function.
if (concrete && kind >= TypeMatchKind::Conversion &&
shouldTryUserConversion(*this, type1)) {
conversionsOrFixes.push_back(ConversionRestrictionKind::User);
}
commit_to_conversions:
// When we hit this point, we're committed to the set of potential
// conversions recorded thus far.
//
//
// FIXME: One should only jump to this label in the case where we want to
// cut off other potential conversions because we know none of them apply.
// Gradually, those gotos should go away as we can handle more kinds of
// conversions via disjunction constraints.
// If we should attempt fixes, add those to the list. They'll only be visited
// if there are no other possible solutions.
if (shouldAttemptFixes() && !typeVar1 && !typeVar2 &&
!(flags & TMF_ApplyingFix) && kind >= TypeMatchKind::Conversion) {
Type objectType1 = type1->getRValueObjectType();
// If the source type is a function type that could be applied with (),
// try it.
if (isFunctionTypeAcceptingNoArguments(objectType1)) {
conversionsOrFixes.push_back(FixKind::NullaryCall);
}
// If we have an optional type, try to force-unwrap it.
// FIXME: Should we also try '?'?
if (objectType1->getOptionalObjectType()) {
conversionsOrFixes.push_back(FixKind::ForceOptional);
}
// If we have a value of type AnyObject that we're trying to convert to
// a class, force a downcast.
if (objectType1->isAnyObject() &&
type2->getClassOrBoundGenericClass()) {
conversionsOrFixes.push_back(FixKind::ForceDowncast);
}
// If we're converting an lvalue to an inout type, add the missing '&'.
if (type2->getRValueType()->is<InOutType>() && type1->is<LValueType>()) {
conversionsOrFixes.push_back(FixKind::AddressOf);
}
}
if (conversionsOrFixes.empty()) {
// If one of the types is a type variable, we leave this unsolved.
if (typeVar1 || typeVar2)
return SolutionKind::Unsolved;
// If we are supposed to record failures, do so.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
getRelationalFailureKind(kind), type1, type2);
}
return SolutionKind::Error;
}
// Where there is more than one potential conversion, create a disjunction
// so that we'll explore all of the options.
if (conversionsOrFixes.size() > 1) {
auto fixedLocator = getConstraintLocator(locator);
SmallVector<Constraint *, 2> constraints;
for (auto potential : conversionsOrFixes) {
auto constraintKind = getConstraintKind(kind);
if (auto restriction = potential.getRestriction()) {
// Determine the constraint kind. For a deep equality constraint, only
// perform equality.
if (*restriction == ConversionRestrictionKind::DeepEquality)
constraintKind = ConstraintKind::Equal;
constraints.push_back(
Constraint::createRestricted(*this, constraintKind, *restriction,
type1, type2, fixedLocator));
continue;
}
// If the first thing we found is a fix, add a "don't fix" marker.
if (conversionsOrFixes.empty()) {
constraints.push_back(
Constraint::createFixed(*this, constraintKind, FixKind::None,
type1, type2, fixedLocator));
}
auto fix = *potential.getFix();
constraints.push_back(
Constraint::createFixed(*this, constraintKind, fix, type1, type2,
fixedLocator));
}
addConstraint(Constraint::createDisjunction(*this, constraints,
fixedLocator));
return SolutionKind::Solved;
}
// For a single potential conversion, directly recurse, so that we
// don't allocate a new constraint or constraint locator.
// Handle restrictions.
if (auto restriction = conversionsOrFixes[0].getRestriction()) {
ConstraintRestrictions.push_back({type1, type2, *restriction});
return simplifyRestrictedConstraint(*restriction, type1, type2,
kind, subFlags, locator);
}
// Handle fixes.
auto fix = *conversionsOrFixes[0].getFix();
return simplifyFixConstraint(fix, type1, type2, kind, subFlags, locator);
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyConstructionConstraint(Type valueType, Type argType,
unsigned flags,
ConstraintLocator *locator) {
// Desugar the value type.
auto desugarValueType = valueType->getDesugaredType();
// If we have a type variable that has been bound to a fixed type,
// look through to that fixed type.
auto desugarValueTypeVar = dyn_cast<TypeVariableType>(desugarValueType);
if (desugarValueTypeVar) {
if (auto fixed = getFixedType(desugarValueTypeVar)) {
valueType = fixed;
desugarValueType = fixed->getDesugaredType();
desugarValueTypeVar = nullptr;
}
}
switch (desugarValueType->getKind()) {
#define SUGARED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
llvm_unreachable("Type has not been desugared completely");
#define ARTIFICIAL_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
llvm_unreachable("artificial type in constraint");
case TypeKind::Error:
return SolutionKind::Error;
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type");
case TypeKind::TypeVariable:
return SolutionKind::Unsolved;
case TypeKind::Tuple: {
// Tuple construction is simply tuple conversion.
return matchTypes(argType, valueType, TypeMatchKind::Conversion,
flags|TMF_GenerateConstraints, locator);
}
case TypeKind::Enum:
case TypeKind::Struct:
case TypeKind::Class:
case TypeKind::BoundGenericClass:
case TypeKind::BoundGenericEnum:
case TypeKind::BoundGenericStruct:
case TypeKind::Archetype:
case TypeKind::DynamicSelf:
case TypeKind::ProtocolComposition:
case TypeKind::Protocol:
// Break out to handle the actual construction below.
break;
case TypeKind::PolymorphicFunction:
llvm_unreachable("Polymorphic function type should have been opened");
case TypeKind::UnboundGeneric:
llvm_unreachable("Unbound generic type should have been opened");
#define BUILTIN_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
case TypeKind::ExistentialMetatype:
case TypeKind::Metatype:
case TypeKind::Function:
case TypeKind::LValue:
case TypeKind::InOut:
case TypeKind::Module:
// If we are supposed to record failures, do so.
if (shouldRecordFailures()) {
recordFailure(locator, Failure::TypesNotConstructible,
valueType, argType);
}
return SolutionKind::Error;
}
auto ctors = TC.lookupConstructors(valueType, DC);
if (!ctors) {
// If we are supposed to record failures, do so.
if (shouldRecordFailures()) {
recordFailure(locator, Failure::TypesNotConstructible,
valueType, argType);
}
return SolutionKind::Error;
}
auto &context = getASTContext();
auto name = context.Id_init;
auto applyLocator = getConstraintLocator(locator,
ConstraintLocator::ApplyArgument);
auto tv = createTypeVariable(applyLocator,
TVO_CanBindToLValue|TVO_PrefersSubtypeBinding);
// The constructor will have function type T -> T2, for a fresh type
// variable T. Note that these constraints specifically require a
// match on the result type because the constructors for enums and struct
// types always return a value of exactly that type.
addValueMemberConstraint(valueType, name,
FunctionType::get(tv, valueType),
getConstraintLocator(
locator,
ConstraintLocator::ConstructorMember));
// The first type must be convertible to the constructor's argument type.
addConstraint(ConstraintKind::ArgumentTupleConversion, argType, tv,
applyLocator);
return SolutionKind::Solved;
}
ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
Type type,
ProtocolDecl *protocol,
ConstraintLocatorBuilder locator,
bool allowNonConformingExistential) {
// Dig out the fixed type to which this type refers.
TypeVariableType *typeVar;
type = getFixedTypeRecursive(type, typeVar, /*wantRValue=*/true);
// If we hit a type variable without a fixed type, we can't
// solve this yet.
if (typeVar)
return SolutionKind::Unsolved;
// If existential types don't need to conform (i.e., they only need to
// contain the protocol), check that separately.
if (allowNonConformingExistential && type->isExistentialType()) {
SmallVector<ProtocolDecl *, 4> protocols;
type->getAnyExistentialTypeProtocols(protocols);
for (auto ap : protocols) {
// If this isn't the protocol we're looking for, continue looking.
if (ap == protocol || ap->inheritsFrom(protocol))
return SolutionKind::Solved;
}
} else {
// Check whether this type conforms to the protocol.
if (TC.conformsToProtocol(type, protocol, DC))
return SolutionKind::Solved;
}
// If possible, redirect the coercion from String to NSString.
if (TC.isBridgedDynamicConversion(protocol->getDeclaredType(), type)) {
auto NSStringType = TC.getNSStringType(DC);
if (!NSStringType.isNull()) {
simplifyRestrictedConstraint(ConversionRestrictionKind::User,
type,
NSStringType,
TypeMatchKind::Conversion,
TMF_GenerateConstraints,
locator);
return SolutionKind::Solved;
}
}
// There's nothing more we can do; fail.
recordFailure(getConstraintLocator(locator),
Failure::DoesNotConformToProtocol, type,
protocol->getDeclaredType());
return SolutionKind::Error;
}
/// Determine the kind of checked cast to perform from the given type to
/// the given type.
///
/// This routine does not attempt to check whether the cast can actually
/// succeed; that's the caller's responsibility.
static CheckedCastKind getCheckedCastKind(Type fromType, Type toType) {
// Classify the from/to types.
bool toArchetype = toType->is<ArchetypeType>();
bool fromArchetype = fromType->is<ArchetypeType>();
bool toExistential = toType->isExistentialType();
bool fromExistential = fromType->isExistentialType();
// We can only downcast to an existential if the destination protocols are
// objc and the source type is an objc class or an existential bounded by objc
// protocols.
if (toExistential) {
return CheckedCastKind::ConcreteToUnrelatedExistential;
}
// A downcast can:
// - convert an archetype to a (different) archetype type.
if (fromArchetype && toArchetype) {
return CheckedCastKind::ArchetypeToArchetype;
}
// - convert from an existential to an archetype or conforming concrete
// type.
if (fromExistential) {
if (toArchetype) {
return CheckedCastKind::ExistentialToArchetype;
}
return CheckedCastKind::ExistentialToConcrete;
}
// - convert an archetype to a concrete type fulfilling its constraints.
if (fromArchetype) {
return CheckedCastKind::ArchetypeToConcrete;
}
if (toArchetype) {
// - convert from a superclass to an archetype.
if (toType->castTo<ArchetypeType>()->getSuperclass()) {
return CheckedCastKind::SuperToArchetype;
}
// - convert a concrete type to an archetype for which it fulfills
// constraints.
return CheckedCastKind::ConcreteToArchetype;
}
// The remaining case is a class downcast.
assert(!fromArchetype && "archetypes should have been handled above");
assert(!toArchetype && "archetypes should have been handled above");
assert(!fromExistential && "existentials should have been handled above");
assert(!toExistential && "existentials should have been handled above");
return CheckedCastKind::Downcast;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyCheckedCastConstraint(
Type fromType, Type toType,
ConstraintLocatorBuilder locator) {
// Dig out the fixed type to which this type refers.
TypeVariableType *typeVar1;
fromType = getFixedTypeRecursive(fromType, typeVar1, /*wantRValue=*/true);
// If we hit a type variable without a fixed type, we can't
// solve this yet.
if (typeVar1)
return SolutionKind::Unsolved;
// Dig out the fixed type to which this type refers.
TypeVariableType *typeVar2;
toType = getFixedTypeRecursive(toType, typeVar2, /*wantRValue=*/true);
// If we hit a type variable without a fixed type, we can't
// solve this yet.
if (typeVar2)
return SolutionKind::Unsolved;
switch (getCheckedCastKind(fromType, toType)) {
case CheckedCastKind::ArchetypeToArchetype:
case CheckedCastKind::ConcreteToUnrelatedExistential:
case CheckedCastKind::ExistentialToArchetype:
case CheckedCastKind::SuperToArchetype:
return SolutionKind::Solved;
case CheckedCastKind::ArchetypeToConcrete:
case CheckedCastKind::ConcreteToArchetype:
// FIXME: Check substitutability.
return SolutionKind::Solved;
case CheckedCastKind::Downcast:
addConstraint(ConstraintKind::Subtype, toType, fromType,
getConstraintLocator(locator));
return SolutionKind::Solved;
case CheckedCastKind::ExistentialToConcrete:
addConstraint(ConstraintKind::Subtype, toType, fromType);
return SolutionKind::Solved;
case CheckedCastKind::Coercion:
case CheckedCastKind::Unresolved:
llvm_unreachable("Not a valid result");
}
}
/// Determine whether the given type is the Self type of the protocol.
static bool isProtocolSelf(Type type) {
if (auto genericParam = type->getAs<GenericTypeParamType>())
return genericParam->getDepth() == 0;
return false;
}
/// Determine whether the given type contains a reference to the 'Self' type
/// of a protocol.
static bool containsProtocolSelf(Type type) {
// If the type is not dependent, it doesn't refer to 'Self'.
if (!type->isDependentType())
return false;
return type.findIf([](Type type) -> bool {
return isProtocolSelf(type);
});
}
/// Determine whether the given protocol member's signature prevents
/// it from being used in an existential reference.
static bool isUnavailableInExistential(TypeChecker &tc, ValueDecl *decl) {
Type type = decl->getInterfaceType();
// For a function or constructor, skip the implicit 'this'.
if (auto afd = dyn_cast<AbstractFunctionDecl>(decl)) {
type = type->castTo<AnyFunctionType>()->getResult();
// Allow functions to return Self, but not have Self anywhere in
// their argument types.
for (unsigned i = 1, n = afd->getNumParamPatterns(); i != n; ++i) {
// Check whether the input type contains Self anywhere.
auto fnType = type->castTo<AnyFunctionType>();
if (containsProtocolSelf(fnType->getInput()))
return true;
type = fnType->getResult();
}
// Look through one level of optional on the result type.
if (auto valueType = type->getAnyOptionalObjectType())
type = valueType;
if (isProtocolSelf(type) || type->is<DynamicSelfType>())
return false;
return containsProtocolSelf(type);
}
return containsProtocolSelf(type);
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyMemberConstraint(const Constraint &constraint) {
// Resolve the base type, if we can. If we can't resolve the base type,
// then we can't solve this constraint.
Type baseTy = simplifyType(constraint.getFirstType());
Type baseObjTy = baseTy->getRValueType();
// Try to look through UncheckedOptional<T>; the result is always an r-value.
if (auto objTy = lookThroughUncheckedOptionalType(baseObjTy)) {
increaseScore(SK_ForceUnchecked);
baseTy = baseObjTy = objTy;
}
// Dig out the instance type.
bool isMetatype = false;
Type instanceTy = baseObjTy;
if (auto baseObjMeta = baseObjTy->getAs<AnyMetatypeType>()) {
instanceTy = baseObjMeta->getInstanceType();
isMetatype = true;
}
if (instanceTy->is<TypeVariableType>())
return SolutionKind::Unsolved;
// If the base type is a tuple type, look for the named or indexed member
// of the tuple.
DeclName name = constraint.getMember();
Type memberTy = constraint.getSecondType();
if (auto baseTuple = baseObjTy->getAs<TupleType>()) {
// Tuples don't have compound-name members.
if (!name.isSimpleName()) {
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
StringRef nameStr = name.getBaseName().str();
int fieldIdx = -1;
// Resolve a number reference into the tuple type.
unsigned Value = 0;
if (!nameStr.getAsInteger(10, Value) &&
Value < baseTuple->getFields().size()) {
fieldIdx = Value;
} else {
fieldIdx = baseTuple->getNamedElementId(name.getBaseName());
}
if (fieldIdx == -1) {
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
// Add an overload set that selects this field.
OverloadChoice choice(baseTy, fieldIdx);
addBindOverloadConstraint(memberTy, choice, constraint.getLocator());
return SolutionKind::Solved;
}
// FIXME: If the base type still involves type variables, we want this
// constraint to be unsolved. This effectively requires us to solve the
// left-hand side of a dot expression before we look for members.
bool isExistential = instanceTy->isExistentialType();
if (name.isSimpleName(TC.Context.Id_init)) {
// Constructors have their own approach to name lookup.
auto ctors = TC.lookupConstructors(baseObjTy, DC);
if (!ctors) {
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
// Introduce a new overload set.
SmallVector<OverloadChoice, 4> choices;
for (auto constructor : ctors) {
// If the constructor is invalid, skip it.
// FIXME: Note this as invalid, in case we don't find a solution,
// so we don't let errors cascade further.
TC.validateDecl(constructor, true);
if (constructor->isInvalid())
continue;
// If our base is an existential type, we can't make use of any
// constructor whose signature involves associated types.
// FIXME: Mark this as 'unavailable'.
if (isExistential &&
isUnavailableInExistential(getTypeChecker(), constructor))
continue;
choices.push_back(OverloadChoice(baseTy, constructor,
/*isSpecialized=*/false));
}
if (choices.empty()) {
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
addOverloadSet(memberTy, choices, constraint.getLocator());
return SolutionKind::Solved;
}
// If we want member types only, use member type lookup.
if (constraint.getKind() == ConstraintKind::TypeMember) {
// Types don't have compound names.
if (!name.isSimpleName()) {
// FIXME: Customize diagnostic to mention types and compound names.
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
auto lookup = TC.lookupMemberType(baseObjTy, name.getBaseName(), DC);
if (!lookup) {
// FIXME: Customize diagnostic to mention types.
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
// Form the overload set.
SmallVector<OverloadChoice, 4> choices;
for (auto result : lookup) {
// If the result is invalid, skip it.
// FIXME: Note this as invalid, in case we don't find a solution,
// so we don't let errors cascade further.
TC.validateDecl(result.first, true);
if (result.first->isInvalid())
continue;
choices.push_back(OverloadChoice(baseTy, result.first,
/*isSpecialized=*/false));
}
if (choices.empty()) {
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
auto locator = getConstraintLocator(constraint.getLocator());
addOverloadSet(memberTy, choices, locator);
return SolutionKind::Solved;
}
// Look for members within the base.
LookupResult &lookup = lookupMember(baseObjTy, name);
if (!lookup) {
// Check whether we actually performed a lookup with an integer value.
unsigned index;
if (name.isSimpleName()
&& !name.getBaseName().str().getAsInteger(10, index)) {
// ".0" on a scalar just refers to the underlying scalar value.
if (index == 0) {
OverloadChoice identityChoice(baseTy, OverloadChoiceKind::BaseType);
addBindOverloadConstraint(memberTy, identityChoice,
constraint.getLocator());
return SolutionKind::Solved;
}
// FIXME: Specialize diagnostic here?
}
recordFailure(constraint.getLocator(), Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
// The set of directly accessible types, which is only used when
// we're performing dynamic lookup into an existential type.
bool isDynamicLookup = false;
if (auto protoTy = instanceTy->getAs<ProtocolType>()) {
isDynamicLookup = protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::AnyObject);
}
// Record the fact that we found a mutating function for diagnostics.
bool FoundMutating = false;
// Introduce a new overload set to capture the choices.
SmallVector<OverloadChoice, 4> choices;
for (auto result : lookup) {
// If the result is invalid, skip it.
// FIXME: Note this as invalid, in case we don't find a solution,
// so we don't let errors cascade further.
TC.validateDecl(result, true);
if (result->isInvalid())
continue;
// If our base is an existential type, we can't make use of any
// member whose signature involves associated types.
// FIXME: Mark this as 'unavailable'.
if (isExistential && isUnavailableInExistential(getTypeChecker(), result))
continue;
// If we are looking for a metatype member, don't include members that can
// only be accessed on an instance of the object.
// FIXME: Mark as 'unavailable' somehow.
if (isMetatype && !(isa<FuncDecl>(result) || !result->isInstanceMember())) {
continue;
}
// If we aren't looking in a metatype, ignore static functions, static
// variables, and enum elements.
if (!isMetatype && !baseObjTy->is<ModuleType>() &&
!result->isInstanceMember())
continue;
// If we're doing dynamic lookup into a metatype of AnyObject and we've
// found an instance member, ignore it.
if (isDynamicLookup && isMetatype && result->isInstanceMember()) {
// FIXME: Mark as 'unavailable' somehow.
continue;
}
// If we have an rvalue base of struct or enum type, make sure that the
// result isn't mutating (only valid on lvalues).
if (!isMetatype && !baseObjTy->hasReferenceSemantics() &&
!baseTy->is<LValueType>() && result->isInstanceMember()) {
if (auto *FD = dyn_cast<FuncDecl>(result))
if (FD->isMutating()) {
FoundMutating = true;
continue;
}
// Subscripts are ok on rvalues so long as the getter is nonmutating.
if (auto *SD = dyn_cast<SubscriptDecl>(result))
if (SD->getGetter()->isMutating()) {
FoundMutating = true;
continue;
}
// Computed properties are ok on rvalues so long as the getter is
// nonmutating.
if (auto *VD = dyn_cast<VarDecl>(result))
if (auto *GD = VD->getGetter())
if (GD->isMutating()) {
FoundMutating = true;
continue;
}
}
// If we're looking into an existential type, check whether this
// result was found via dynamic lookup.
if (isDynamicLookup) {
assert(result->getDeclContext()->isTypeContext() && "Dynamic lookup bug");
// We found this declaration via dynamic lookup, record it as such.
choices.push_back(OverloadChoice::getDeclViaDynamic(baseTy, result));
continue;
}
choices.push_back(OverloadChoice(baseTy, result, /*isSpecialized=*/false));
}
if (choices.empty()) {
recordFailure(constraint.getLocator(),
FoundMutating ? Failure::DoesNotHaveNonMutatingMember :
Failure::DoesNotHaveMember,
baseObjTy, name);
return SolutionKind::Error;
}
auto locator = getConstraintLocator(constraint.getLocator());
addOverloadSet(memberTy, choices, locator);
return SolutionKind::Solved;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyArchetypeConstraint(const Constraint &constraint) {
// Resolve the base type, if we can. If we can't resolve the base type,
// then we can't solve this constraint.
Type baseTy = constraint.getFirstType()->getRValueType();
if (auto tv = dyn_cast<TypeVariableType>(baseTy.getPointer())) {
auto fixed = getFixedType(tv);
if (!fixed)
return SolutionKind::Unsolved;
// Continue with the fixed type.
baseTy = fixed->getRValueType();
}
if (baseTy->is<ArchetypeType>()) {
return SolutionKind::Solved;
}
// Record this failure.
recordFailure(constraint.getLocator(), Failure::IsNotArchetype, baseTy);
return SolutionKind::Error;
}
/// Simplify the given type for use in a type property constraint.
static Type simplifyForTypePropertyConstraint(ConstraintSystem &cs, Type type) {
if (auto tv = dyn_cast<TypeVariableType>(type.getPointer())) {
auto fixed = cs.getFixedType(tv);
if (!fixed)
return Type();
// Continue with the fixed type.
type = fixed;
}
return type;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyClassConstraint(const Constraint &constraint){
auto baseTy = simplifyForTypePropertyConstraint(*this,
constraint.getFirstType());
if (!baseTy)
return SolutionKind::Unsolved;
if (baseTy->getClassOrBoundGenericClass())
return SolutionKind::Solved;
if (auto archetype = baseTy->getAs<ArchetypeType>()) {
if (archetype->requiresClass())
return SolutionKind::Solved;
}
// Record this failure.
recordFailure(constraint.getLocator(), Failure::IsNotClass, baseTy);
return SolutionKind::Error;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyDynamicLookupConstraint(const Constraint &constraint){
auto baseTy = simplifyForTypePropertyConstraint(*this,
constraint.getFirstType());
if (!baseTy)
return SolutionKind::Unsolved;
// Look through implicit lvalue types.
baseTy = baseTy->getRValueType();
// Look through one level of optional type.
// FIXME: this is kindof specific to the use of this
// constraint for ForceValueExpr.
if (auto valueTy = baseTy->getAnyOptionalObjectType()) {
valueTy = simplifyForTypePropertyConstraint(*this, valueTy);
if (!valueTy)
return SolutionKind::Unsolved;
baseTy = valueTy;
}
if (auto protoTy = baseTy->getAs<ProtocolType>()) {
if (protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::AnyObject))
return SolutionKind::Solved;
}
// Record this failure.
recordFailure(constraint.getLocator(), Failure::IsNotArchetype, baseTy);
return SolutionKind::Error;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyDynamicTypeOfConstraint(const Constraint &constraint) {
// Solve forward.
TypeVariableType *typeVar2;
Type type2 = getFixedTypeRecursive(constraint.getSecondType(), typeVar2,
/*wantRValue=*/ true);
if (!typeVar2) {
Type dynamicType2;
if (type2->isAnyExistentialType()) {
dynamicType2 = ExistentialMetatypeType::get(type2);
} else {
dynamicType2 = MetatypeType::get(type2);
}
return matchTypes(constraint.getFirstType(), dynamicType2,
TypeMatchKind::BindType, TMF_GenerateConstraints,
constraint.getLocator());
}
// Okay, can't solve forward. See what we can do backwards.
TypeVariableType *typeVar1;
Type type1 = getFixedTypeRecursive(constraint.getFirstType(), typeVar1, true);
// If we have an existential metatype, that's good enough to solve
// the constraint.
if (auto metatype1 = type1->getAs<ExistentialMetatypeType>())
return matchTypes(metatype1->getInstanceType(), type2,
TypeMatchKind::BindType,
TMF_GenerateConstraints, constraint.getLocator());
// If we have a normal metatype, we can't solve backwards unless we
// know what kind of object it is.
if (auto metatype1 = type1->getAs<MetatypeType>()) {
TypeVariableType *instanceTypeVar1;
Type instanceType1 = getFixedTypeRecursive(metatype1->getInstanceType(),
instanceTypeVar1, true);
if (!instanceTypeVar1) {
return matchTypes(instanceType1, type2,
TypeMatchKind::BindType,
TMF_GenerateConstraints, constraint.getLocator());
}
// If it's definitely not either kind of metatype, then we can
// report failure right away.
} else if (!typeVar1) {
recordFailure(constraint.getLocator(), Failure::IsNotMetatype, type1);
return SolutionKind::Error;
}
return SolutionKind::Unsolved;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyApplicableFnConstraint(const Constraint &constraint) {
// By construction, the left hand side is a type that looks like the
// following: $T1 -> $T2.
Type type1 = constraint.getFirstType();
assert(type1->is<FunctionType>());
// Drill down to the concrete type on the right hand side.
TypeVariableType *typeVar2;
Type type2 = getFixedTypeRecursive(constraint.getSecondType(), typeVar2,
/*wantRValue=*/true);
auto desugar2 = type2->getDesugaredType();
// Try to look through UncheckedOptional<T>; the result is always an r-value.
if (auto objTy = lookThroughUncheckedOptionalType(desugar2)) {
type2 = objTy;
desugar2 = type2->getDesugaredType();
}
// Force the right-hand side to be an rvalue.
unsigned flags = TMF_GenerateConstraints;
// If the types are obviously equivalent, we're done.
if (type1.getPointer() == desugar2)
return SolutionKind::Solved;
// If right-hand side is a type variable, the constraint is unsolved.
if (typeVar2)
return SolutionKind::Unsolved;
// Strip the 'ApplyFunction' off the locator.
// FIXME: Perhaps ApplyFunction can go away entirely?
ConstraintLocatorBuilder locator = constraint.getLocator();
SmallVector<LocatorPathElt, 2> parts;
Expr *anchor = locator.getLocatorParts(parts);
assert(!parts.empty() && "Nonsensical applicable-function locator");
assert(parts.back().getKind() == ConstraintLocator::ApplyFunction);
assert(parts.back().getNewSummaryFlags() == 0);
parts.pop_back();
ConstraintLocatorBuilder outerLocator =
getConstraintLocator(anchor, parts, locator.getSummaryFlags());
retry:
// For a function, bind the output and convert the argument to the input.
auto func1 = type1->castTo<FunctionType>();
if (desugar2->getKind() == TypeKind::Function) {
auto func2 = cast<FunctionType>(desugar2);
assert(func1->getResult()->is<TypeVariableType>() &&
"the output of funct1 is a free variable by construction");
// If this application is part of an operator, then we allow an implicit
// lvalue to be compatible with inout arguments. This is used by
// assignment operators.
TypeMatchKind ArgConv = TypeMatchKind::Conversion;
if (isa<PrefixUnaryExpr>(anchor) || isa<PostfixUnaryExpr>(anchor) ||
isa<BinaryExpr>(anchor))
ArgConv = TypeMatchKind::OperatorConversion;
// The argument type must be convertible to the input type.
if (matchTypes(func1->getInput(), func2->getInput(),
ArgConv, flags,
outerLocator.withPathElement(
ConstraintLocator::ApplyArgument))
== SolutionKind::Error)
return SolutionKind::Error;
// The result types are equivalent.
if (matchTypes(func1->getResult(), func2->getResult(),
TypeMatchKind::BindType,
flags,
locator.withPathElement(ConstraintLocator::FunctionResult))
== SolutionKind::Error)
return SolutionKind::Error;
return SolutionKind::Solved;
}
// For a metatype, perform a construction.
if (auto meta2 = dyn_cast<AnyMetatypeType>(desugar2)) {
auto instanceTy2 = meta2->getInstanceType();
// Bind the result type to the instance type.
if (matchTypes(func1->getResult(), instanceTy2,
TypeMatchKind::BindType,
flags,
locator.withPathElement(ConstraintLocator::ApplyFunction))
== SolutionKind::Error)
return SolutionKind::Error;
// Construct the instance from the input arguments.
addConstraint(ConstraintKind::Construction, func1->getInput(), instanceTy2,
getConstraintLocator(outerLocator));
return SolutionKind::Solved;
}
// If we're coming from an optional type, unwrap the optional and try again.
if (auto objectType2 = desugar2->getOptionalObjectType()) {
// Increase the score before we attempt a fix.
increaseScore(SK_Fix);
if (worseThanBestSolution())
return SolutionKind::Error;
Fixes.push_back({FixKind::ForceOptional,getConstraintLocator(locator)});
type2 = objectType2;
desugar2 = type2->getDesugaredType();
goto retry;
}
// If this is a '()' call, drop the call.
if (shouldAttemptFixes() &&
func1->getInput()->isEqual(TupleType::getEmpty(getASTContext()))) {
// Increase the score before we attempt a fix.
increaseScore(SK_Fix);
if (worseThanBestSolution())
return SolutionKind::Error;
// We don't bother with a 'None' case, because at this point we won't get
// a better diagnostic from that case.
Fixes.push_back({FixKind::RemoveNullaryCall,
getConstraintLocator(locator)});
return matchTypes(func1->getResult(), type2,
TypeMatchKind::BindType,
flags | TMF_ApplyingFix | TMF_GenerateConstraints,
locator.withPathElement(
ConstraintLocator::FunctionResult));
}
// If we are supposed to record failures, do so.
if (shouldRecordFailures()) {
recordFailure(getConstraintLocator(locator),
Failure::FunctionTypesMismatch,
type1, type2);
}
return SolutionKind::Error;
}
/// \brief Retrieve the type-matching kind corresponding to the given
/// constraint kind.
static TypeMatchKind getTypeMatchKind(ConstraintKind kind) {
switch (kind) {
case ConstraintKind::Bind: return TypeMatchKind::BindType;
case ConstraintKind::Equal: return TypeMatchKind::SameType;
case ConstraintKind::Subtype: return TypeMatchKind::Subtype;
case ConstraintKind::Conversion: return TypeMatchKind::Conversion;
case ConstraintKind::ArgumentTupleConversion:
return TypeMatchKind::ArgumentTupleConversion;
case ConstraintKind::OperatorConversion:
return TypeMatchKind::OperatorConversion;
case ConstraintKind::ApplicableFunction:
llvm_unreachable("ApplicableFunction constraints don't involve "
"type matches");
case ConstraintKind::DynamicTypeOf:
llvm_unreachable("DynamicTypeOf constraints don't involve type matches");
case ConstraintKind::BindOverload:
llvm_unreachable("Overload binding constraints don't involve type matches");
case ConstraintKind::Construction:
llvm_unreachable("Construction constraints don't involve type matches");
case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
llvm_unreachable("Conformance constraints don't involve type matches");
case ConstraintKind::CheckedCast:
llvm_unreachable("Checked cast constraints don't involve type matches");
case ConstraintKind::ValueMember:
case ConstraintKind::TypeMember:
llvm_unreachable("Member constraints don't involve type matches");
case ConstraintKind::Archetype:
case ConstraintKind::Class:
case ConstraintKind::DynamicLookupValue:
llvm_unreachable("Type properties don't involve type matches");
case ConstraintKind::Conjunction:
case ConstraintKind::Disjunction:
llvm_unreachable("Con/disjunction constraints don't involve type matches");
}
}
/// Given that we have a conversion constraint between two types, and
/// that the given constraint-reduction rule applies between them at
/// the top level, apply it and generate any necessary recursive
/// constraints.
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restriction,
Type type1, Type type2,
TypeMatchKind matchKind,
unsigned flags,
ConstraintLocatorBuilder locator) {
// Add to the score based on context.
auto addContextualScore = [&] {
// Okay, we need to perform one or more conversions. If this
// conversion will cause a function conversion, score it as worse.
// This induces conversions to occur within closures instead of
// outside of them wherever possible.
if (locator.isFunctionConversion()) {
increaseScore(SK_FunctionConversion);
}
};
switch (restriction) {
// for $< in { <, <c, <oc }:
// T_i $< U_i ===> (T_i...) $< (U_i...)
case ConversionRestrictionKind::TupleToTuple:
return matchTupleTypes(type1->castTo<TupleType>(),
type2->castTo<TupleType>(),
matchKind, flags, locator);
// T <c U ===> T <c (U)
case ConversionRestrictionKind::ScalarToTuple:
return matchScalarToTupleTypes(type1,
type2->castTo<TupleType>(),
matchKind, flags, locator);
// for $< in { <, <c, <oc }:
// T $< U ===> (T) $< U
case ConversionRestrictionKind::TupleToScalar:
return matchTupleToScalarTypes(type1->castTo<TupleType>(),
type2,
matchKind, flags, locator);
case ConversionRestrictionKind::DeepEquality:
return matchDeepEqualityTypes(type1, type2, locator);
case ConversionRestrictionKind::Superclass:
addContextualScore();
return matchSuperclassTypes(type1, type2, matchKind, flags, locator);
case ConversionRestrictionKind::LValueToRValue:
return matchTypes(type1->getRValueType(), type2,
matchKind, flags, locator);
// for $< in { <, <c, <oc }:
// T $< U, U : P_i ===> T $< protocol<P_i...>
case ConversionRestrictionKind::Existential:
addContextualScore();
return matchExistentialTypes(type1, type2,
matchKind, flags, locator);
// for $< in { <, <c, <oc }:
// T $< U ===> T $< U?
case ConversionRestrictionKind::ValueToOptional: {
addContextualScore();
assert(matchKind >= TypeMatchKind::Subtype);
auto generic2 = type2->castTo<BoundGenericType>();
assert(generic2->getDecl()->classifyAsOptionalType());
return matchTypes(type1, generic2->getGenericArgs()[0],
matchKind, flags, locator);
}
// for $< in { <, <c, <oc }:
// T $< U ===> T? $< U?
// T $< U ===> T! $< U!
// T $< U ===> T! $< U?
// also:
// T <c U ===> T? <c U!
case ConversionRestrictionKind::OptionalToUncheckedOptional:
case ConversionRestrictionKind::UncheckedOptionalToOptional:
case ConversionRestrictionKind::OptionalToOptional: {
addContextualScore();
assert(matchKind >= TypeMatchKind::Subtype);
auto generic1 = type1->castTo<BoundGenericType>();
auto generic2 = type2->castTo<BoundGenericType>();
assert(generic1->getDecl()->classifyAsOptionalType());
assert(generic2->getDecl()->classifyAsOptionalType());
return matchTypes(generic1->getGenericArgs()[0],
generic2->getGenericArgs()[0],
matchKind, flags, locator);
}
// T <c U ===> T! <c U
//
// We don't want to allow this after user-defined conversions:
// - it gets really complex for users to understand why there's
// a dereference in their code
// - it would allow nil to be coerceable to a non-optional type
// Fortunately, user-defined conversions only allow subtype
// conversions on their results.
case ConversionRestrictionKind::ForceUnchecked: {
addContextualScore();
assert(matchKind >= TypeMatchKind::Conversion);
auto boundGenericType1 = type1->castTo<BoundGenericType>();
assert(boundGenericType1->getDecl()->classifyAsOptionalType()
== OTK_UncheckedOptional);
assert(boundGenericType1->getGenericArgs().size() == 1);
Type valueType1 = boundGenericType1->getGenericArgs()[0];
increaseScore(SK_ForceUnchecked);
return matchTypes(valueType1, type2,
matchKind, flags, locator);
}
// T < U ===> Array<T> <c Array<U>
case ConversionRestrictionKind::ArrayUpcast: {
increaseScore(SK_ArrayConversion);
addContextualScore();
assert(matchKind >= TypeMatchKind::Conversion);
Type baseType1;
Type baseType2;
auto t1 = type1->getDesugaredType();
auto t2 = type2->getDesugaredType();
if (auto sliceType1 = dyn_cast<ArraySliceType>(t1)) {
baseType1 = sliceType1->getBaseType();
} else {
auto arrayType1 = cast<BoundGenericStructType>(t1);
baseType1 = arrayType1->getGenericArgs()[0];
}
if (auto sliceType2 = dyn_cast<ArraySliceType>(t2)) {
baseType2 = sliceType2->getBaseType();
} else {
auto arrayType2 = cast<BoundGenericStructType>(t2);
baseType2 = arrayType2->getGenericArgs()[0];
}
// Allow assignments from Array<T> to Array<AnyObject> if T is a bridged
// type.
if (auto protoTy = baseType2->getAs<ProtocolType>()) {
if(protoTy->getDecl()->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
if (TC.isTriviallyRepresentableInObjC(DC, baseType1)) {
return SolutionKind::Solved;
}
}
}
return matchTypes(baseType1,
baseType2,
TypeMatchKind::Subtype,
flags,
locator);
}
// T' < U, hasMember(T, conversion, T -> T') ===> T <c U
case ConversionRestrictionKind::User:
addContextualScore();
assert(matchKind >= TypeMatchKind::Conversion);
return tryUserConversion(*this, type1,
ConstraintKind::Subtype,
type2,
locator);
}
llvm_unreachable("bad conversion restriction");
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyFixConstraint(Fix fix,
Type type1, Type type2,
TypeMatchKind matchKind,
unsigned flags,
ConstraintLocatorBuilder locator) {
auto &ctx = getASTContext();
if (ctx.LangOpts.DebugConstraintSolver) {
auto &log = ctx.TypeCheckerDebug->getStream();
log.indent(solverState? solverState->depth * 2 + 2 : 0)
<< "(attempting fix ";
fix.print(log);
log << " @";
getConstraintLocator(locator)->dump(&ctx.SourceMgr, log);
log << ")\n";
}
// Record the fix.
if (fix.getKind() != FixKind::None) {
Fixes.push_back({fix, getConstraintLocator(locator)});
// Increase the score. If this would make the current solution worse than
// the best solution we've seen already, stop now.
increaseScore(SK_Fix);
if (worseThanBestSolution())
return SolutionKind::Error;
}
// Try with the fix.
unsigned subFlags = flags | TMF_ApplyingFix | TMF_GenerateConstraints;
switch (fix.getKind()) {
case FixKind::None:
return matchTypes(type1, type2, matchKind, subFlags, locator);
case FixKind::NullaryCall:
// Assume that '()' was applied to the first type.
return matchTypes(type1->getRValueType()->castTo<AnyFunctionType>()
->getResult(),
type2, matchKind, subFlags, locator);
case FixKind::RemoveNullaryCall:
llvm_unreachable("Always applied directly");
case FixKind::ForceOptional:
// Assume that '!' was applied to the first type.
return matchTypes(type1->getRValueType()->getOptionalObjectType(), type2,
matchKind, subFlags, locator);
case FixKind::ForceDowncast:
// This one works whenever it is suggested.
return SolutionKind::Solved;
case FixKind::AddressOf:
// Assume that '&' was applied to the first type, turning an lvalue into
// an inout.
return matchTypes(InOutType::get(type1->getRValueType()), type2,
matchKind, subFlags, locator);
}
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
switch (constraint.getKind()) {
case ConstraintKind::Bind:
case ConstraintKind::Equal:
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentTupleConversion:
case ConstraintKind::OperatorConversion: {
// For relational constraints, match up the types.
auto matchKind = getTypeMatchKind(constraint.getKind());
// If there is a fix associated with this constraint, apply it before
// we continue.
if (auto fix = constraint.getFix()) {
return simplifyFixConstraint(*fix, constraint.getFirstType(),
constraint.getSecondType(), matchKind,
TMF_GenerateConstraints,
constraint.getLocator());
}
// If there is a restriction on this constraint, apply it directly rather
// than going through the general \c matchTypes() machinery.
if (auto restriction = constraint.getRestriction()) {
SolutionKind result = simplifyRestrictedConstraint(*restriction,
constraint.getFirstType(),
constraint.getSecondType(),
matchKind,
TMF_GenerateConstraints,
constraint.getLocator());
// If we actually solved something, record what we did.
switch(result) {
case SolutionKind::Error:
case SolutionKind::Unsolved:
break;
case SolutionKind::Solved:
ConstraintRestrictions.push_back(
std::make_tuple(constraint.getFirstType(),
constraint.getSecondType(), *restriction));
break;
}
return result;
}
return matchTypes(constraint.getFirstType(), constraint.getSecondType(),
matchKind,
TMF_None, constraint.getLocator());
}
case ConstraintKind::ApplicableFunction:
return simplifyApplicableFnConstraint(constraint);
case ConstraintKind::DynamicTypeOf:
return simplifyDynamicTypeOfConstraint(constraint);
case ConstraintKind::BindOverload:
resolveOverload(constraint.getLocator(), constraint.getFirstType(),
constraint.getOverloadChoice());
return SolutionKind::Solved;
case ConstraintKind::Construction:
return simplifyConstructionConstraint(constraint.getSecondType(),
constraint.getFirstType(),
TMF_None,
constraint.getLocator());
case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
return simplifyConformsToConstraint(
constraint.getFirstType(),
constraint.getProtocol(),
constraint.getLocator(),
constraint.getKind() == ConstraintKind::SelfObjectOfProtocol);
case ConstraintKind::CheckedCast:
return simplifyCheckedCastConstraint(constraint.getFirstType(),
constraint.getSecondType(),
constraint.getLocator());
case ConstraintKind::ValueMember:
case ConstraintKind::TypeMember:
return simplifyMemberConstraint(constraint);
case ConstraintKind::Archetype:
return simplifyArchetypeConstraint(constraint);
case ConstraintKind::Class:
return simplifyClassConstraint(constraint);
case ConstraintKind::DynamicLookupValue:
return simplifyDynamicLookupConstraint(constraint);
case ConstraintKind::Conjunction:
// Process all of the constraints in the conjunction.
for (auto con : constraint.getNestedConstraints()) {
addConstraint(con);
if (failedConstraint)
return SolutionKind::Error;
}
return SolutionKind::Solved;
case ConstraintKind::Disjunction:
// Disjunction constraints are never solved here.
return SolutionKind::Unsolved;
}
}