Skip to content

Commit 579274b

Browse files
authored
Merge pull request #35007 from xedin/refactor-involves-type-vars
[ConstraintSystem] Track adjacent type variables while inferring bindings
2 parents c55b9cc + 2619e2d commit 579274b

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4743,8 +4743,13 @@ class ConstraintSystem {
47434743
/// The set of constraints which delay attempting this type variable.
47444744
llvm::TinyPtrVector<Constraint *> DelayedBy;
47454745

4746-
/// Whether the bindings of this type involve other type variables.
4747-
bool InvolvesTypeVariables = false;
4746+
/// The set of type variables adjacent to the current one.
4747+
///
4748+
/// Type variables contained here are either related through the
4749+
/// bindings (contained in the binding type e.g. `Foo<$T0>`), or
4750+
/// reachable through subtype/conversion relationship e.g.
4751+
/// `$T0 subtype of $T1` or `$T0 arg conversion $T1`.
4752+
llvm::SmallPtrSet<TypeVariableType *, 2> AdjacentVars;
47484753

47494754
ASTNode AssociatedCodeCompletionToken = ASTNode();
47504755

@@ -4775,6 +4780,11 @@ class ConstraintSystem {
47754780
/// okay to attempt "delayed" type variable to make forward progress.
47764781
bool isDelayed() const;
47774782

4783+
/// Whether the bindings of this type involve other type variables,
4784+
/// or the type variable itself is adjacent to other type variables
4785+
/// that could become valid bindings in the future.
4786+
bool involvesTypeVariables() const;
4787+
47784788
/// Whether the bindings represent (potentially) incomplete set,
47794789
/// there is no way to say with absolute certainty if that's the
47804790
/// case, but that could happen when certain constraints like
@@ -4819,7 +4829,7 @@ class ConstraintSystem {
48194829
!hasNoDefaultableBindings,
48204830
b.isDelayed(),
48214831
b.isSubtypeOfExistentialType(),
4822-
b.InvolvesTypeVariables,
4832+
b.involvesTypeVariables(),
48234833
static_cast<unsigned char>(b.LiteralBinding),
48244834
-(b.Bindings.size() - numDefaults));
48254835
}
@@ -4970,7 +4980,7 @@ class ConstraintSystem {
49704980
out << "subtype_of_existential ";
49714981
if (LiteralBinding != LiteralBindingKind::None)
49724982
out << "literal=" << static_cast<int>(LiteralBinding) << " ";
4973-
if (InvolvesTypeVariables)
4983+
if (involvesTypeVariables())
49744984
out << "involves_type_vars ";
49754985

49764986
auto numDefaultable = getNumDefaultableBindings();

lib/Sema/CSBindings.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ bool ConstraintSystem::PotentialBindings::isDelayed() const {
5858
return false;
5959
}
6060

61+
bool ConstraintSystem::PotentialBindings::involvesTypeVariables() const {
62+
// This is effectively O(1) right now since bindings are re-computed
63+
// on each step of the solver, but once bindings are computed
64+
// incrementally it becomes more important to double-check that
65+
// any adjacent type variables found previously are still unresolved.
66+
return llvm::any_of(AdjacentVars, [](TypeVariableType *typeVar) {
67+
return !typeVar->getImpl().getFixedType(/*record=*/nullptr);
68+
});
69+
}
70+
6171
bool ConstraintSystem::PotentialBindings::isPotentiallyIncomplete() const {
6272
// Generic parameters are always potentially incomplete.
6373
if (isGenericParameter())
@@ -814,7 +824,7 @@ bool ConstraintSystem::PotentialBindings::favoredOverDisjunction(
814824
return boundType->lookThroughAllOptionalTypes()->is<TypeVariableType>();
815825
}
816826

817-
return !InvolvesTypeVariables;
827+
return !involvesTypeVariables();
818828
}
819829

820830
ConstraintSystem::PotentialBindings
@@ -888,17 +898,16 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
888898
}
889899
}
890900

891-
// Can't infer anything.
892-
if (result.InvolvesTypeVariables)
893-
return None;
894-
895901
// Check whether both this type and another type variable are
896902
// inferable.
897903
SmallPtrSet<TypeVariableType *, 4> typeVars;
898904
findInferableTypeVars(first, typeVars);
899905
findInferableTypeVars(second, typeVars);
900-
if (typeVars.size() > 1 && typeVars.count(typeVar))
901-
result.InvolvesTypeVariables = true;
906+
907+
if (typeVars.erase(typeVar)) {
908+
result.AdjacentVars.insert(typeVars.begin(), typeVars.end());
909+
}
910+
902911
return None;
903912
}
904913

@@ -927,11 +936,27 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
927936
// If the type we'd be binding to is a dependent member, don't try to
928937
// resolve this type variable yet.
929938
if (type->is<DependentMemberType>()) {
930-
if (!ConstraintSystem::typeVarOccursInType(typeVar, type,
931-
&result.InvolvesTypeVariables)) {
932-
result.DelayedBy.push_back(constraint);
939+
SmallVector<TypeVariableType *, 4> referencedVars;
940+
type->getTypeVariables(referencedVars);
941+
942+
bool containsSelf = false;
943+
for (auto *var : referencedVars) {
944+
// Add all type variables encountered in the type except
945+
// to the current type variable.
946+
if (var != typeVar) {
947+
result.AdjacentVars.insert(var);
948+
continue;
949+
}
950+
951+
containsSelf = true;
933952
}
934953

954+
// If inferred type doesn't contain the current type variable,
955+
// let's mark bindings as delayed until dependent member type
956+
// is resolved.
957+
if (!containsSelf)
958+
result.DelayedBy.push_back(constraint);
959+
935960
return None;
936961
}
937962

@@ -951,15 +976,18 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
951976
// FIXME: this has a super-inefficient extraneous simplifyType() in it.
952977
if (auto boundType = checkTypeOfBinding(typeVar, type)) {
953978
type = *boundType;
954-
if (type->hasTypeVariable())
955-
result.InvolvesTypeVariables = true;
979+
if (type->hasTypeVariable()) {
980+
SmallVector<TypeVariableType *, 4> referencedVars;
981+
type->getTypeVariables(referencedVars);
982+
result.AdjacentVars.insert(referencedVars.begin(), referencedVars.end());
983+
}
956984
} else {
957985
auto *bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>();
958986

959987
if (!bindingTypeVar)
960988
return None;
961989

962-
result.InvolvesTypeVariables = true;
990+
result.AdjacentVars.insert(bindingTypeVar);
963991

964992
// If current type variable is associated with a code completion token
965993
// it's possible that it doesn't have enough contextual information

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,7 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
22872287
return;
22882288

22892289
auto bindings = cs.inferBindingsFor(typeVar);
2290-
if (bindings.InvolvesTypeVariables || bindings.Bindings.size() != 1)
2290+
if (bindings.involvesTypeVariables() || bindings.Bindings.size() != 1)
22912291
return;
22922292

22932293
auto conversionType = bindings.Bindings[0].BindingType;

0 commit comments

Comments
 (0)