Skip to content

Commit afa1198

Browse files
committed
[ConstraintSystem] Determine whether bindings are potentially incomplete on demand
1 parent 7eb623d commit afa1198

File tree

2 files changed

+70
-39
lines changed

2 files changed

+70
-39
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4730,12 +4730,6 @@ class ConstraintSystem {
47304730
/// Whether the bindings of this type involve other type variables.
47314731
bool InvolvesTypeVariables = false;
47324732

4733-
/// Whether the bindings represent (potentially) incomplete set,
4734-
/// there is no way to say with absolute certainty if that's the
4735-
/// case, but that could happen when certain constraints like
4736-
/// `bind param` are present in the system.
4737-
bool PotentiallyIncomplete = false;
4738-
47394733
ASTNode AssociatedCodeCompletionToken = ASTNode();
47404734

47414735
/// Whether this type variable has literal bindings.
@@ -4752,12 +4746,17 @@ class ConstraintSystem {
47524746
llvm::SmallMapVector<TypeVariableType *, Constraint *, 4> SupertypeOf;
47534747
llvm::SmallMapVector<TypeVariableType *, Constraint *, 4> EquivalentTo;
47544748

4755-
PotentialBindings(TypeVariableType *typeVar)
4756-
: TypeVar(typeVar), PotentiallyIncomplete(isGenericParameter()) {}
4749+
PotentialBindings(TypeVariableType *typeVar) : TypeVar(typeVar) {}
47574750

47584751
/// Determine whether the set of bindings is non-empty.
47594752
explicit operator bool() const { return !Bindings.empty(); }
47604753

4754+
/// Whether the bindings represent (potentially) incomplete set,
4755+
/// there is no way to say with absolute certainty if that's the
4756+
/// case, but that could happen when certain constraints like
4757+
/// `bind param` are present in the system.
4758+
bool isPotentiallyIncomplete() const;
4759+
47614760
/// If there is only one binding and it's to a hole type, consider
47624761
/// this type variable to be a hole in a constraint system regardless
47634762
/// of where hole type originated.
@@ -4838,7 +4837,7 @@ class ConstraintSystem {
48384837

48394838
// As a last resort, let's check if the bindings are
48404839
// potentially incomplete, and if so, let's de-prioritize them.
4841-
return x.PotentiallyIncomplete < y.PotentiallyIncomplete;
4840+
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
48424841
}
48434842

48444843
void foundLiteralBinding(ProtocolDecl *proto) {
@@ -4939,7 +4938,7 @@ class ConstraintSystem {
49394938
void dump(llvm::raw_ostream &out,
49404939
unsigned indent = 0) const LLVM_ATTRIBUTE_USED {
49414940
out.indent(indent);
4942-
if (PotentiallyIncomplete)
4941+
if (isPotentiallyIncomplete())
49434942
out << "potentially_incomplete ";
49444943
if (FullyBound)
49454944
out << "fully_bound ";

lib/Sema/CSBindings.cpp

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,64 @@
2222
using namespace swift;
2323
using namespace constraints;
2424

25+
bool ConstraintSystem::PotentialBindings::isPotentiallyIncomplete() const {
26+
// Generic parameters are always potentially incomplete.
27+
if (isGenericParameter())
28+
return true;
29+
30+
// If current type variable is associated with a code completion token
31+
// it's possible that it doesn't have enough contextual information
32+
// to be resolved to anything so let's delay considering it until everything
33+
// else is resolved.
34+
if (AssociatedCodeCompletionToken)
35+
return true;
36+
37+
auto *locator = TypeVar->getImpl().getLocator();
38+
if (!locator)
39+
return false;
40+
41+
if (locator->isLastElement<LocatorPathElt::UnresolvedMemberChainResult>()) {
42+
// If subtyping is allowed and this is a result of an implicit member chain,
43+
// let's delay binding it to an optional until its object type resolved too or
44+
// it has been determined that there is no possibility to resolve it. Otherwise
45+
// we might end up missing solutions since it's allowed to implicitly unwrap
46+
// base type of the chain but it can't be done early - type variable
47+
// representing chain's result type has a different l-valueness comparing
48+
// to generic parameter of the optional.
49+
if (llvm::any_of(Bindings, [&](const PotentialBinding &binding) {
50+
if (binding.Kind != AllowedBindingKind::Subtypes)
51+
return false;
52+
53+
auto objectType = binding.BindingType->getOptionalObjectType();
54+
return objectType && objectType->isTypeVariableOrMember();
55+
}))
56+
return true;
57+
}
58+
59+
if (isHole()) {
60+
// If the base of the unresolved member reference like `.foo`
61+
// couldn't be resolved we'd want to bind it to a hole at the
62+
// very last moment possible, just like generic parameters.
63+
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
64+
return true;
65+
66+
// Delay resolution of the code completion expression until
67+
// the very end to give it a chance to be bound to some
68+
// contextual type even if it's a hole.
69+
if (locator->directlyAt<CodeCompletionExpr>())
70+
return true;
71+
72+
// Delay resolution of the `nil` literal to a hole until
73+
// the very end to give it a change to be bound to some
74+
// other type, just like code completion expression which
75+
// relies solely on contextual information.
76+
if (locator->directlyAt<NilLiteralExpr>())
77+
return true;
78+
}
79+
80+
return false;
81+
}
82+
2583
void ConstraintSystem::PotentialBindings::inferTransitiveProtocolRequirements(
2684
const ConstraintSystem &cs,
2785
llvm::SmallDenseMap<TypeVariableType *, ConstraintSystem::PotentialBindings>
@@ -466,25 +524,19 @@ void ConstraintSystem::PotentialBindings::finalize(
466524
// couldn't be resolved we'd want to bind it to a hole at the
467525
// very last moment possible, just like generic parameters.
468526
auto *locator = TypeVar->getImpl().getLocator();
469-
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
470-
PotentiallyIncomplete = true;
471527

472528
// Delay resolution of the code completion expression until
473529
// the very end to give it a chance to be bound to some
474530
// contextual type even if it's a hole.
475-
if (locator->directlyAt<CodeCompletionExpr>()) {
531+
if (locator->directlyAt<CodeCompletionExpr>())
476532
FullyBound = true;
477-
PotentiallyIncomplete = true;
478-
}
479533

480534
// Delay resolution of the `nil` literal to a hole until
481535
// the very end to give it a change to be bound to some
482536
// other type, just like code completion expression which
483537
// relies solely on contextual information.
484-
if (locator->directlyAt<NilLiteralExpr>()) {
538+
if (locator->directlyAt<NilLiteralExpr>())
485539
FullyBound = true;
486-
PotentiallyIncomplete = true;
487-
}
488540

489541
// If this type variable is associated with a code completion token
490542
// and it failed to infer any bindings let's adjust hole's locator
@@ -874,10 +926,8 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
874926
// bindings and use it when forming a hole if there are no other bindings
875927
// available.
876928
if (auto *locator = bindingTypeVar->getImpl().getLocator()) {
877-
if (locator->directlyAt<CodeCompletionExpr>()) {
929+
if (locator->directlyAt<CodeCompletionExpr>())
878930
result.AssociatedCodeCompletionToken = locator->getAnchor();
879-
result.PotentiallyIncomplete = true;
880-
}
881931
}
882932

883933
switch (constraint->getKind()) {
@@ -916,24 +966,6 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
916966
return None;
917967
}
918968

919-
// If subtyping is allowed and this is a result of an implicit member chain,
920-
// let's delay binding it to an optional until its object type resolved too or
921-
// it has been determined that there is no possibility to resolve it. Otherwise
922-
// we might end up missing solutions since it's allowed to implicitly unwrap
923-
// base type of the chain but it can't be done early - type variable
924-
// representing chain's result type has a different l-valueness comparing
925-
// to generic parameter of the optional.
926-
if (kind == AllowedBindingKind::Subtypes) {
927-
auto *locator = typeVar->getImpl().getLocator();
928-
if (locator &&
929-
locator->isLastElement<LocatorPathElt::UnresolvedMemberChainResult>()) {
930-
auto objectType = type->getOptionalObjectType();
931-
if (objectType && objectType->isTypeVariableOrMember()) {
932-
result.PotentiallyIncomplete = true;
933-
}
934-
}
935-
}
936-
937969
if (type->is<InOutType>() && !typeVar->getImpl().canBindToInOut())
938970
type = LValueType::get(type->getInOutObjectType());
939971
if (type->is<LValueType>() && !typeVar->getImpl().canBindToLValue())

0 commit comments

Comments
 (0)