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;
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user