Files
swift-mirror/lib/Sema/CSBindings.cpp
Pavel Yaskevich 5d5872bb83 [CSBindings] Avoid binding type variables to collection types directly
Instead of binding collection types directly let's try to
bind using temporary type variables substituted for element
types, that's going to ensure that subtype relationship is
always preserved.

Resolves: rdar://problem/35541153
2017-12-01 23:04:19 -08:00

631 lines
23 KiB
C++

//===--- CSBindings.cpp - Constraint Solver -------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements selection of bindings for type variables.
//
//===----------------------------------------------------------------------===//
#include "ConstraintGraph.h"
#include "ConstraintSystem.h"
#include <tuple>
using namespace swift;
using namespace constraints;
Optional<ConstraintSystem::PotentialBindings>
ConstraintSystem::determineBestBindings() {
// Look for potential type variable bindings.
Optional<PotentialBindings> bestBindings;
for (auto typeVar : getTypeVariables()) {
// Skip any type variables that are bound.
if (typeVar->getImpl().hasRepresentativeOrFixed())
continue;
// Get potential bindings.
auto bindings = getPotentialBindings(typeVar);
if (!bindings)
continue;
if (TC.getLangOpts().DebugConstraintSolver) {
auto &log = getASTContext().TypeCheckerDebug->getStream();
bindings.dump(typeVar, log, solverState->depth * 2);
}
// If these are the first bindings, or they are better than what
// we saw before, use them instead.
if (!bestBindings || bindings < *bestBindings)
bestBindings = std::move(bindings);
}
return bestBindings;
}
/// Find the set of type variables that are inferable from the given type.
///
/// \param type The type to search.
/// \param typeVars Collects the type variables that are inferable from the
/// given type. This set is not cleared, so that multiple types can be explored
/// and introduce their results into the same set.
static void
findInferableTypeVars(Type type,
SmallPtrSetImpl<TypeVariableType *> &typeVars) {
type = type->getCanonicalType();
if (!type->hasTypeVariable())
return;
class Walker : public TypeWalker {
SmallPtrSetImpl<TypeVariableType *> &typeVars;
public:
explicit Walker(SmallPtrSetImpl<TypeVariableType *> &typeVars)
: typeVars(typeVars) {}
Action walkToTypePre(Type ty) override {
if (ty->is<DependentMemberType>())
return Action::SkipChildren;
if (auto typeVar = ty->getAs<TypeVariableType>())
typeVars.insert(typeVar);
return Action::Continue;
}
};
type.walk(Walker(typeVars));
}
/// \brief Return whether a relational constraint between a type variable and a
/// trivial wrapper type (autoclosure, unary tuple) should result in the type
/// variable being potentially bound to the value type, as opposed to the
/// wrapper type.
static bool shouldBindToValueType(Constraint *constraint) {
switch (constraint->getKind()) {
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OperatorArgumentTupleConversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::ArgumentTupleConversion:
case ConstraintKind::Conversion:
case ConstraintKind::BridgingConversion:
case ConstraintKind::Subtype:
return true;
case ConstraintKind::Bind:
case ConstraintKind::Equal:
case ConstraintKind::BindParam:
case ConstraintKind::BindToPointerType:
case ConstraintKind::ConformsTo:
case ConstraintKind::LiteralConformsTo:
case ConstraintKind::CheckedCast:
case ConstraintKind::SelfObjectOfProtocol:
case ConstraintKind::ApplicableFunction:
case ConstraintKind::BindOverload:
case ConstraintKind::OptionalObject:
return false;
case ConstraintKind::DynamicTypeOf:
case ConstraintKind::EscapableFunctionOf:
case ConstraintKind::OpenedExistentialOf:
case ConstraintKind::KeyPath:
case ConstraintKind::KeyPathApplication:
case ConstraintKind::ValueMember:
case ConstraintKind::UnresolvedValueMember:
case ConstraintKind::Defaultable:
case ConstraintKind::Disjunction:
llvm_unreachable("shouldBindToValueType() may only be called on "
"relational constraints");
}
llvm_unreachable("Unhandled ConstraintKind in switch.");
}
void ConstraintSystem::PotentialBindings::addPotentialBinding(
PotentialBinding binding, bool allowJoinMeet) {
assert(!binding.BindingType->is<ErrorType>());
// If this is a non-defaulted supertype binding,
// check whether we can combine it with another
// supertype binding by computing the 'join' of the types.
if (binding.Kind == AllowedBindingKind::Supertypes &&
!binding.BindingType->hasTypeVariable() && !binding.DefaultedProtocol &&
!binding.isDefaultableBinding() && allowJoinMeet) {
if (lastSupertypeIndex) {
// Can we compute a join?
auto &lastBinding = Bindings[*lastSupertypeIndex];
auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
auto bindingType = binding.BindingType->getWithoutSpecifierType();
auto join = Type::join(lastType, bindingType);
if (join) {
auto anyType = join->getASTContext().TheAnyType;
if (!join->isEqual(anyType) || lastType->isEqual(anyType) ||
bindingType->isEqual(anyType)) {
// Replace the last supertype binding with the join. We're done.
lastBinding.BindingType = join;
return;
}
}
}
// Record this as the most recent supertype index.
lastSupertypeIndex = Bindings.size();
}
Bindings.push_back(std::move(binding));
}
/// \brief Retrieve the set of potential type bindings for the given
/// representative type variable, along with flags indicating whether
/// those types should be opened.
ConstraintSystem::PotentialBindings
ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar &&
"not a representative");
assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type");
// Gather the constraints associated with this type variable.
SmallVector<Constraint *, 8> constraints;
llvm::SmallPtrSet<Constraint *, 4> visitedConstraints;
getConstraintGraph().gatherConstraints(
typeVar, constraints, ConstraintGraph::GatheringKind::EquivalenceClass);
PotentialBindings result(typeVar);
// Consider each of the constraints related to this type variable.
llvm::SmallPtrSet<CanType, 4> exactTypes;
llvm::SmallPtrSet<ProtocolDecl *, 4> literalProtocols;
SmallVector<Constraint *, 2> defaultableConstraints;
bool addOptionalSupertypeBindings = false;
auto &tc = getTypeChecker();
bool hasNonDependentMemberRelationalConstraints = false;
bool hasDependentMemberRelationalConstraints = false;
for (auto constraint : constraints) {
// Only visit each constraint once.
if (!visitedConstraints.insert(constraint).second)
continue;
switch (constraint->getKind()) {
case ConstraintKind::Bind:
case ConstraintKind::Equal:
case ConstraintKind::BindParam:
case ConstraintKind::BindToPointerType:
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::ArgumentTupleConversion:
case ConstraintKind::OperatorArgumentTupleConversion:
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OptionalObject:
// Relational constraints: break out to look for types above/below.
break;
case ConstraintKind::BridgingConversion:
case ConstraintKind::CheckedCast:
case ConstraintKind::EscapableFunctionOf:
case ConstraintKind::OpenedExistentialOf:
case ConstraintKind::KeyPath:
case ConstraintKind::KeyPathApplication:
// Constraints from which we can't do anything.
continue;
case ConstraintKind::DynamicTypeOf: {
// Direct binding of the left-hand side could result
// in `DynamicTypeOf` failure if right-hand side is
// bound (because 'Bind' requires equal types to
// succeed), or left is bound to Any which is not an
// [existential] metatype.
auto dynamicType = constraint->getFirstType();
if (auto *tv = dynamicType->getAs<TypeVariableType>()) {
if (tv->getImpl().getRepresentative(nullptr) == typeVar)
return {typeVar};
}
// This is right-hand side, let's continue.
continue;
}
case ConstraintKind::Defaultable:
// Do these in a separate pass.
if (getFixedTypeRecursive(constraint->getFirstType(), true)
->getAs<TypeVariableType>() == typeVar) {
defaultableConstraints.push_back(constraint);
hasNonDependentMemberRelationalConstraints = true;
}
continue;
case ConstraintKind::Disjunction:
// FIXME: Recurse into these constraints to see whether this
// type variable is fully bound by any of them.
result.InvolvesTypeVariables = true;
continue;
case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
// Swift 3 allowed the use of default types for normal conformances
// to expressible-by-literal protocols.
if (tc.Context.LangOpts.EffectiveLanguageVersion[0] >= 4)
continue;
if (!constraint->getSecondType()->is<ProtocolType>())
continue;
LLVM_FALLTHROUGH;
case ConstraintKind::LiteralConformsTo: {
// If there is a 'nil' literal constraint, we might need optional
// supertype bindings.
if (constraint->getProtocol()->isSpecificProtocol(
KnownProtocolKind::ExpressibleByNilLiteral))
addOptionalSupertypeBindings = true;
// If there is a default literal type for this protocol, it's a
// potential binding.
auto defaultType = tc.getDefaultType(constraint->getProtocol(), DC);
if (!defaultType)
continue;
// Note that we have a literal constraint with this protocol.
literalProtocols.insert(constraint->getProtocol());
hasNonDependentMemberRelationalConstraints = true;
// Handle unspecialized types directly.
if (!defaultType->hasUnboundGenericType()) {
if (!exactTypes.insert(defaultType->getCanonicalType()).second)
continue;
result.foundLiteralBinding(constraint->getProtocol());
result.addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
constraint->getKind(),
constraint->getProtocol()});
continue;
}
// For generic literal types, check whether we already have a
// specialization of this generic within our list.
// FIXME: This assumes that, e.g., the default literal
// int/float/char/string types are never generic.
auto nominal = defaultType->getAnyNominal();
if (!nominal)
continue;
bool matched = false;
for (auto exactType : exactTypes) {
if (auto exactNominal = exactType->getAnyNominal()) {
// FIXME: Check parents?
if (nominal == exactNominal) {
matched = true;
break;
}
}
}
if (!matched) {
result.foundLiteralBinding(constraint->getProtocol());
exactTypes.insert(defaultType->getCanonicalType());
result.addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
constraint->getKind(),
constraint->getProtocol()});
}
continue;
}
case ConstraintKind::ApplicableFunction:
case ConstraintKind::BindOverload: {
if (result.FullyBound && result.InvolvesTypeVariables)
continue;
// If this variable is in the left-hand side, it is fully bound.
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferableTypeVars(simplifyType(constraint->getFirstType()), typeVars);
if (typeVars.count(typeVar))
result.FullyBound = true;
if (result.InvolvesTypeVariables)
continue;
// If this and another type variable occur, this result involves
// type variables.
findInferableTypeVars(simplifyType(constraint->getSecondType()),
typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;
}
case ConstraintKind::ValueMember:
case ConstraintKind::UnresolvedValueMember:
// If our type variable shows up in the base type, there's
// nothing to do.
// FIXME: Can we avoid simplification here?
if (ConstraintSystem::typeVarOccursInType(
typeVar, simplifyType(constraint->getFirstType()),
&result.InvolvesTypeVariables)) {
continue;
}
// If the type variable is in the list of member type
// variables, it is fully bound.
// FIXME: Can we avoid simplification here?
if (ConstraintSystem::typeVarOccursInType(
typeVar, simplifyType(constraint->getSecondType()),
&result.InvolvesTypeVariables)) {
result.FullyBound = true;
}
continue;
}
// Handle relational constraints.
assert(constraint->getClassification() ==
ConstraintClassification::Relational &&
"only relational constraints handled here");
// Record constraint which contributes to the
// finding of pontential bindings.
result.Sources.insert(constraint);
auto first = simplifyType(constraint->getFirstType());
auto second = simplifyType(constraint->getSecondType());
if (first->is<TypeVariableType>() && first->isEqual(second))
continue;
Type type;
AllowedBindingKind kind;
if (first->getAs<TypeVariableType>() == typeVar) {
// Upper bound for this type variable.
type = second;
kind = AllowedBindingKind::Subtypes;
} else if (second->getAs<TypeVariableType>() == typeVar) {
// Lower bound for this type variable.
type = first;
kind = AllowedBindingKind::Supertypes;
} else {
// Can't infer anything.
if (result.InvolvesTypeVariables)
continue;
// Check whether both this type and another type variable are
// inferable.
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferableTypeVars(first, typeVars);
findInferableTypeVars(second, typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;
}
// Do not attempt to bind to ErrorType.
if (type->hasError())
continue;
// If the type we'd be binding to is a dependent member, don't try to
// resolve this type variable yet.
if (type->is<DependentMemberType>()) {
if (!ConstraintSystem::typeVarOccursInType(
typeVar, type, &result.InvolvesTypeVariables)) {
hasDependentMemberRelationalConstraints = true;
}
continue;
}
hasNonDependentMemberRelationalConstraints = true;
// Check whether we can perform this binding.
// FIXME: this has a super-inefficient extraneous simplifyType() in it.
bool isNilLiteral = false;
bool *isNilLiteralPtr = nullptr;
if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
isNilLiteralPtr = &isNilLiteral;
if (auto boundType = checkTypeOfBinding(typeVar, type, isNilLiteralPtr)) {
type = *boundType;
if (type->hasTypeVariable())
result.InvolvesTypeVariables = true;
} else {
// If the bound is a 'nil' literal type, add optional supertype bindings.
if (isNilLiteral) {
addOptionalSupertypeBindings = true;
continue;
}
result.InvolvesTypeVariables = true;
continue;
}
// Don't deduce autoclosure types or single-element, non-variadic
// tuples.
if (shouldBindToValueType(constraint)) {
if (auto funcTy = type->getAs<FunctionType>()) {
if (funcTy->isAutoClosure())
type = funcTy->getResult();
}
type = type->getWithoutImmediateLabel();
}
// Don't deduce IUO types.
Type alternateType;
bool adjustedIUO = false;
if (kind == AllowedBindingKind::Supertypes &&
constraint->getKind() >= ConstraintKind::Conversion &&
constraint->getKind() <= ConstraintKind::OperatorArgumentConversion) {
auto innerType = type->getWithoutSpecifierType();
if (auto objectType =
lookThroughImplicitlyUnwrappedOptionalType(innerType)) {
type = OptionalType::get(objectType);
alternateType = objectType;
adjustedIUO = true;
}
}
// Make sure we aren't trying to equate type variables with different
// lvalue-binding rules.
if (auto otherTypeVar = type->getAs<TypeVariableType>()) {
if (typeVar->getImpl().canBindToLValue() !=
otherTypeVar->getImpl().canBindToLValue())
continue;
}
// BindParam constraints are not reflexive and must be treated specially.
if (constraint->getKind() == ConstraintKind::BindParam) {
if (kind == AllowedBindingKind::Subtypes) {
if (auto *lvt = type->getAs<LValueType>()) {
type = InOutType::get(lvt->getObjectType());
}
} else if (kind == AllowedBindingKind::Supertypes) {
if (auto *iot = type->getAs<InOutType>()) {
type = LValueType::get(iot->getObjectType());
}
}
kind = AllowedBindingKind::Exact;
}
if (exactTypes.insert(type->getCanonicalType()).second)
result.addPotentialBinding({type, kind, constraint->getKind()},
/*allowJoinMeet=*/!adjustedIUO);
if (alternateType &&
exactTypes.insert(alternateType->getCanonicalType()).second)
result.addPotentialBinding({alternateType, kind, constraint->getKind()},
/*allowJoinMeet=*/false);
}
// If we have any literal constraints, check whether there is already a
// binding that provides a type that conforms to that literal protocol. In
// such cases, remove the default binding suggestion because the existing
// suggestion is better.
if (!literalProtocols.empty()) {
SmallPtrSet<ProtocolDecl *, 5> coveredLiteralProtocols;
for (auto &binding : result.Bindings) {
// Skip defaulted-protocol constraints.
if (binding.DefaultedProtocol)
continue;
Type testType;
switch (binding.Kind) {
case AllowedBindingKind::Exact:
testType = binding.BindingType;
break;
case AllowedBindingKind::Subtypes:
case AllowedBindingKind::Supertypes:
testType = binding.BindingType->getRValueType();
break;
}
// Check each non-covered literal protocol to determine which ones
bool updatedBindingType = false;
for (auto proto : literalProtocols) {
do {
// If the type conforms to this protocol, we're covered.
if (tc.conformsToProtocol(
testType, proto, DC,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::SkipConditionalRequirements))) {
coveredLiteralProtocols.insert(proto);
break;
}
// If we're allowed to bind to subtypes, look through optionals.
// FIXME: This is really crappy special case of computing a reasonable
// result based on the given constraints.
if (binding.Kind == AllowedBindingKind::Subtypes) {
if (auto objTy = testType->getAnyOptionalObjectType()) {
updatedBindingType = true;
testType = objTy;
continue;
}
}
updatedBindingType = false;
break;
} while (true);
}
if (updatedBindingType)
binding.BindingType = testType;
}
// For any literal type that has been covered, remove the default literal
// type.
if (!coveredLiteralProtocols.empty()) {
result.Bindings.erase(
std::remove_if(result.Bindings.begin(), result.Bindings.end(),
[&](PotentialBinding &binding) {
return binding.DefaultedProtocol &&
coveredLiteralProtocols.count(
*binding.DefaultedProtocol) > 0;
}),
result.Bindings.end());
}
}
/// Add defaultable constraints last.
for (auto constraint : defaultableConstraints) {
Type type = constraint->getSecondType();
if (!exactTypes.insert(type->getCanonicalType()).second)
continue;
++result.NumDefaultableBindings;
result.addPotentialBinding({type, AllowedBindingKind::Exact,
constraint->getKind(), None,
constraint->getLocator()});
}
// Determine if the bindings only constrain the type variable from above with
// an existential type; such a binding is not very helpful because it's
// impossible to enumerate the existential type's subtypes.
result.SubtypeOfExistentialType =
std::all_of(result.Bindings.begin(), result.Bindings.end(),
[](const PotentialBinding &binding) {
return binding.BindingType->isExistentialType() &&
binding.Kind == AllowedBindingKind::Subtypes;
});
// If we're supposed to add optional supertype bindings, do so now.
if (addOptionalSupertypeBindings) {
for (unsigned i : indices(result.Bindings)) {
auto &binding = result.Bindings[i];
bool wrapInOptional = false;
if (binding.Kind == AllowedBindingKind::Supertypes) {
// If the type doesn't conform to ExpressibleByNilLiteral,
// produce an optional of that type as a potential binding. We
// overwrite the binding in place because the non-optional type
// will fail to type-check against the nil-literal conformance.
auto nominalBindingDecl =
binding.BindingType->getRValueType()->getAnyNominal();
bool conformsToExprByNilLiteral = false;
if (nominalBindingDecl) {
SmallVector<ProtocolConformance *, 2> conformances;
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
DC->getParentModule(),
getASTContext().getProtocol(
KnownProtocolKind::ExpressibleByNilLiteral),
conformances);
}
wrapInOptional = !conformsToExprByNilLiteral;
} else if (binding.isDefaultableBinding() &&
binding.BindingType->isAny()) {
wrapInOptional = true;
}
if (wrapInOptional) {
binding.BindingType = OptionalType::get(binding.BindingType);
}
}
}
// If there were both dependent-member and non-dependent-member relational
// constraints, consider this "fully bound"; we don't want to touch it.
if (hasDependentMemberRelationalConstraints) {
if (hasNonDependentMemberRelationalConstraints)
result.FullyBound = true;
else
result.Bindings.clear();
}
return result;
}