mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user