[ConstraintSystem] Use originating constraint as a source for a binding

Unify all of the fields of `PotentialBinding` which have to do with
location information into a single field with is either a constraint
(for regular bindings) or constraint locator (for "holes").

This helps to reduce the amount of space used by `PotentialBinding`
 as well as propagate more contextual information when binding gets
 attempted.
This commit is contained in:
Pavel Yaskevich
2019-12-11 16:30:35 -08:00
parent 9cbc761a89
commit bb51a8f97d
2 changed files with 91 additions and 52 deletions

View File

@@ -81,7 +81,7 @@ ConstraintSystem::determineBestBindings() {
continue;
bindings.addPotentialBinding(
{type, AllowedBindingKind::Supertypes, binding.BindingSource});
binding.withSameSource(type, AllowedBindingKind::Supertypes));
}
}
@@ -143,8 +143,8 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
!binding.BindingType->hasUnresolvedType() &&
!binding.BindingType->hasTypeVariable() &&
!binding.BindingType->hasUnboundGenericType() &&
!binding.DefaultedProtocol && !binding.isDefaultableBinding() &&
allowJoinMeet) {
!binding.hasDefaultedLiteralProtocol() &&
!binding.isDefaultableBinding() && allowJoinMeet) {
if (lastSupertypeIndex) {
auto &lastBinding = Bindings[*lastSupertypeIndex];
auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
@@ -164,7 +164,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
lastSupertypeIndex = Bindings.size();
}
if (auto *literalProtocol = binding.DefaultedProtocol)
if (auto *literalProtocol = binding.getDefaultedLiteralProtocol())
foundLiteralBinding(literalProtocol);
// If the type variable can't bind to an lvalue, make sure the
@@ -371,7 +371,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
kind = AllowedBindingKind::Exact;
}
return PotentialBinding{type, kind, constraint->getKind()};
return PotentialBinding{type, kind, constraint};
}
/// Retrieve the set of potential type bindings for the given
@@ -466,8 +466,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
path.back().getKind() == ConstraintLocator::ClosureResult &&
binding->Kind == AllowedBindingKind::Supertypes &&
exactTypes.insert(voidType).second) {
result.addPotentialBinding(
{voidType, binding->Kind, constraint->getKind()},
result.addPotentialBinding({voidType, binding->Kind, constraint},
/*allowJoinMeet=*/false);
}
}
@@ -551,9 +550,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (!exactTypes.insert(defaultType->getCanonicalType()).second)
continue;
literalBindings.push_back({defaultType, AllowedBindingKind::Subtypes,
constraint->getKind(),
constraint->getProtocol()});
literalBindings.push_back(
{defaultType, AllowedBindingKind::Subtypes, constraint});
continue;
}
@@ -578,9 +576,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (!matched) {
exactTypes.insert(defaultType->getCanonicalType());
literalBindings.push_back({defaultType, AllowedBindingKind::Subtypes,
constraint->getKind(),
constraint->getProtocol()});
literalBindings.push_back(
{defaultType, AllowedBindingKind::Subtypes, constraint});
}
break;
@@ -677,7 +674,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
// might be covered by non-defaulted bindings.
bool updatedBindingType = false;
for (auto &literalBinding : literalBindings) {
auto *protocol = literalBinding.DefaultedProtocol;
auto *protocol = literalBinding.getDefaultedLiteralProtocol();
assert(protocol);
@@ -716,7 +713,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
}
for (auto &literalBinding : literalBindings) {
auto *protocol = literalBinding.DefaultedProtocol;
auto *protocol = literalBinding.getDefaultedLiteralProtocol();
// For any literal type that has been covered, skip them.
if (coveredLiteralProtocols.count(protocol) == 0)
result.addPotentialBinding(std::move(literalBinding));
@@ -729,9 +726,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (!exactTypes.insert(type->getCanonicalType()).second)
continue;
result.addPotentialBinding({type, AllowedBindingKind::Exact,
constraint->getKind(), nullptr,
constraint->getLocator()});
result.addPotentialBinding({type, AllowedBindingKind::Exact, constraint});
}
// If there are no bindings, typeVar may be a hole.
@@ -745,9 +740,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
result.PotentiallyIncomplete = true;
result.addPotentialBinding({getASTContext().TheUnresolvedType,
AllowedBindingKind::Exact, ConstraintKind::Defaultable, nullptr,
typeVar->getImpl().getLocator()});
result.addPotentialBinding(
PotentialBinding::forHole(getASTContext(), locator));
}
// Determine if the bindings only constrain the type variable from above with
@@ -918,11 +912,11 @@ bool TypeVarBindingProducer::computeNext() {
// If we have a protocol with a default type, look for alternative
// types to the default.
if (NumTries == 0 && binding.DefaultedProtocol) {
auto knownKind = *(binding.DefaultedProtocol->getKnownProtocolKind());
if (NumTries == 0 && binding.hasDefaultedLiteralProtocol()) {
auto knownKind =
*(binding.getDefaultedLiteralProtocol()->getKnownProtocolKind());
for (auto altType : CS.getAlternativeLiteralTypes(knownKind)) {
addNewBinding({altType, BindingKind::Subtypes, binding.BindingSource,
binding.DefaultedProtocol});
addNewBinding(binding.withSameSource(altType, BindingKind::Subtypes));
}
}
@@ -939,10 +933,10 @@ bool TypeVarBindingProducer::computeNext() {
if (auto otherTypeVar = objTy->getAs<TypeVariableType>()) {
if (TypeVar->getImpl().canBindToLValue() ==
otherTypeVar->getImpl().canBindToLValue()) {
addNewBinding({objTy, binding.Kind, binding.BindingSource});
addNewBinding(binding.withSameSource(objTy, binding.Kind));
}
} else {
addNewBinding({objTy, binding.Kind, binding.BindingSource});
addNewBinding(binding.withSameSource(objTy, binding.Kind));
}
}
}
@@ -953,7 +947,7 @@ bool TypeVarBindingProducer::computeNext() {
for (auto supertype : enumerateDirectSupertypes(type)) {
// If we're not allowed to try this binding, skip it.
if (auto simplifiedSuper = CS.checkTypeOfBinding(TypeVar, supertype))
addNewBinding({*simplifiedSuper, binding.Kind, binding.BindingSource});
addNewBinding(binding.withType(*simplifiedSuper));
}
}
@@ -970,10 +964,10 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
auto type = Binding.BindingType;
auto *locator = TypeVar->getImpl().getLocator();
if (Binding.DefaultedProtocol) {
if (Binding.hasDefaultedLiteralProtocol()) {
type = cs.openUnboundGenericType(type, locator);
type = type->reconstituteSugar(/*recursive=*/false);
} else if (Binding.BindingSource == ConstraintKind::ArgumentConversion &&
} else if (Binding.getSourceKind() == ConstraintKind::ArgumentConversion &&
!type->hasTypeVariable() && cs.isCollectionType(type)) {
// If the type binding comes from the argument conversion, let's
// instead of binding collection types directly, try to bind
@@ -994,7 +988,7 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
// If this was from a defaultable binding note that.
if (Binding.isDefaultableBinding()) {
cs.DefaultedConstraints.push_back(Binding.DefaultableBinding);
cs.DefaultedConstraints.push_back(Binding.getLocator());
if (locator->isForGenericParameter() && type->isHole()) {
// Drop `generic parameter` locator element so that all missing

View File

@@ -3288,28 +3288,72 @@ private:
/// The kind of bindings permitted.
AllowedBindingKind Kind;
/// The kind of the constraint this binding came from.
ConstraintKind BindingSource;
/// The defaulted protocol associated with this binding.
ProtocolDecl *DefaultedProtocol;
/// If this is a binding that comes from a \c Defaultable constraint,
/// the locator of that constraint.
ConstraintLocator *DefaultableBinding = nullptr;
protected:
/// The source of the type information.
///
/// Determines whether this binding represents a "hole" in
/// constraint system. Such bindings have no originating constraint
/// because they are synthetic, they have a locator instead.
PointerUnion<Constraint *, ConstraintLocator *> BindingSource;
PotentialBinding(Type type, AllowedBindingKind kind,
ConstraintKind bindingSource,
ProtocolDecl *defaultedProtocol = nullptr,
ConstraintLocator *defaultableBinding = nullptr)
PointerUnion<Constraint *, ConstraintLocator *> source)
: BindingType(type->getWithoutParens()), Kind(kind),
BindingSource(bindingSource), DefaultedProtocol(defaultedProtocol),
DefaultableBinding(defaultableBinding) {}
BindingSource(source) {}
bool isDefaultableBinding() const { return DefaultableBinding != nullptr; }
public:
PotentialBinding(Type type, AllowedBindingKind kind, Constraint *source)
: BindingType(type->getWithoutParens()), Kind(kind),
BindingSource(source) {}
bool isDefaultableBinding() const {
if (auto *constraint = BindingSource.dyn_cast<Constraint *>())
return constraint->getKind() == ConstraintKind::Defaultable;
// If binding source is not constraint - it's a hole, which is
// a last resort default binding for a type variable.
return true;
}
bool hasDefaultedLiteralProtocol() const {
return bool(getDefaultedLiteralProtocol());
}
ProtocolDecl *getDefaultedLiteralProtocol() const {
auto *constraint = BindingSource.dyn_cast<Constraint *>();
if (!constraint)
return nullptr;
return constraint->getKind() == ConstraintKind::LiteralConformsTo
? constraint->getProtocol()
: nullptr;
}
ConstraintKind getSourceKind() const {
if (auto *constraint = BindingSource.dyn_cast<Constraint *>())
return constraint->getKind();
// If binding source is not constraint - it's a hole which is
// always a `Bind` constraint.
return ConstraintKind::Bind;
}
ConstraintLocator *getLocator() const {
if (auto *constraint = BindingSource.dyn_cast<Constraint *>())
return constraint->getLocator();
return BindingSource.get<ConstraintLocator *>();
}
PotentialBinding withType(Type type) const {
return {type, Kind, BindingSource, DefaultedProtocol, DefaultableBinding};
return {type, Kind, BindingSource};
}
PotentialBinding withSameSource(Type type, AllowedBindingKind kind) {
return {type, Kind, BindingSource};
}
static PotentialBinding forHole(ASTContext &ctx,
ConstraintLocator *locator) {
return {ctx.TheUnresolvedType, AllowedBindingKind::Exact,
/*source=*/locator};
}
};
@@ -3464,9 +3508,8 @@ private:
out << "(supertypes of) ";
break;
}
if (binding.DefaultedProtocol)
out << "(default from "
<< binding.DefaultedProtocol->getName() << ") ";
if (auto *literal = binding.getDefaultedLiteralProtocol())
out << "(default from " << literal->getName() << ") ";
out << type.getString(PO);
},
[&]() { out << "; "; });
@@ -4196,7 +4239,9 @@ public:
bool isDefaultable() const { return Binding.isDefaultableBinding(); }
bool hasDefaultedProtocol() const { return Binding.DefaultedProtocol; }
bool hasDefaultedProtocol() const {
return Binding.hasDefaultedLiteralProtocol();
}
bool attempt(ConstraintSystem &cs) const;