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

View File

@@ -3288,28 +3288,72 @@ private:
/// The kind of bindings permitted. /// The kind of bindings permitted.
AllowedBindingKind Kind; AllowedBindingKind Kind;
/// The kind of the constraint this binding came from. protected:
ConstraintKind BindingSource; /// The source of the type information.
///
/// The defaulted protocol associated with this binding. /// Determines whether this binding represents a "hole" in
ProtocolDecl *DefaultedProtocol; /// constraint system. Such bindings have no originating constraint
/// because they are synthetic, they have a locator instead.
/// If this is a binding that comes from a \c Defaultable constraint, PointerUnion<Constraint *, ConstraintLocator *> BindingSource;
/// the locator of that constraint.
ConstraintLocator *DefaultableBinding = nullptr;
PotentialBinding(Type type, AllowedBindingKind kind, PotentialBinding(Type type, AllowedBindingKind kind,
ConstraintKind bindingSource, PointerUnion<Constraint *, ConstraintLocator *> source)
ProtocolDecl *defaultedProtocol = nullptr,
ConstraintLocator *defaultableBinding = nullptr)
: BindingType(type->getWithoutParens()), Kind(kind), : BindingType(type->getWithoutParens()), Kind(kind),
BindingSource(bindingSource), DefaultedProtocol(defaultedProtocol), BindingSource(source) {}
DefaultableBinding(defaultableBinding) {}
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 { 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) "; out << "(supertypes of) ";
break; break;
} }
if (binding.DefaultedProtocol) if (auto *literal = binding.getDefaultedLiteralProtocol())
out << "(default from " out << "(default from " << literal->getName() << ") ";
<< binding.DefaultedProtocol->getName() << ") ";
out << type.getString(PO); out << type.getString(PO);
}, },
[&]() { out << "; "; }); [&]() { out << "; "; });
@@ -4196,7 +4239,9 @@ public:
bool isDefaultable() const { return Binding.isDefaultableBinding(); } bool isDefaultable() const { return Binding.isDefaultableBinding(); }
bool hasDefaultedProtocol() const { return Binding.DefaultedProtocol; } bool hasDefaultedProtocol() const {
return Binding.hasDefaultedLiteralProtocol();
}
bool attempt(ConstraintSystem &cs) const; bool attempt(ConstraintSystem &cs) const;