Skip to content

Commit 88efaac

Browse files
authored
Merge pull request #34988 from xedin/on-demand-fully-bound
[CSBindings] Instead of using a flag track constraints which delay type variable
2 parents 7dc50a1 + c1d178a commit 88efaac

File tree

2 files changed

+80
-68
lines changed

2 files changed

+80
-68
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4740,9 +4740,8 @@ class ConstraintSystem {
47404740
/// The set of constraints which would be used to infer default types.
47414741
llvm::TinyPtrVector<Constraint *> Defaults;
47424742

4743-
/// Whether these bindings should be delayed until the rest of the
4744-
/// constraint system is considered "fully bound".
4745-
bool FullyBound = false;
4743+
/// The set of constraints which delay attempting this type variable.
4744+
llvm::TinyPtrVector<Constraint *> DelayedBy;
47464745

47474746
/// Whether the bindings of this type involve other type variables.
47484747
bool InvolvesTypeVariables = false;
@@ -4765,6 +4764,17 @@ class ConstraintSystem {
47654764
/// Determine whether the set of bindings is non-empty.
47664765
explicit operator bool() const { return !Bindings.empty(); }
47674766

4767+
/// Determine whether attempting this type variable should be
4768+
/// delayed until the rest of the constraint system is considered
4769+
/// "fully bound" meaning constraints, which affect completeness
4770+
/// of the binding set, for this type variable such as - member
4771+
/// constraint, disjunction, function application etc. - are simplified.
4772+
///
4773+
/// Note that in some situations i.e. when there are no more
4774+
/// disjunctions or type variables left to attempt, it's still
4775+
/// okay to attempt "delayed" type variable to make forward progress.
4776+
bool isDelayed() const;
4777+
47684778
/// Whether the bindings represent (potentially) incomplete set,
47694779
/// there is no way to say with absolute certainty if that's the
47704780
/// case, but that could happen when certain constraints like
@@ -4807,7 +4817,7 @@ class ConstraintSystem {
48074817

48084818
return std::make_tuple(b.isHole(),
48094819
!hasNoDefaultableBindings,
4810-
b.FullyBound,
4820+
b.isDelayed(),
48114821
b.isSubtypeOfExistentialType(),
48124822
b.InvolvesTypeVariables,
48134823
static_cast<unsigned char>(b.LiteralBinding),
@@ -4954,8 +4964,8 @@ class ConstraintSystem {
49544964
out.indent(indent);
49554965
if (isPotentiallyIncomplete())
49564966
out << "potentially_incomplete ";
4957-
if (FullyBound)
4958-
out << "fully_bound ";
4967+
if (isDelayed())
4968+
out << "delayed ";
49594969
if (isSubtypeOfExistentialType())
49604970
out << "subtype_of_existential ";
49614971
if (LiteralBinding != LiteralBindingKind::None)

lib/Sema/CSBindings.cpp

Lines changed: 64 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,31 @@ bool ConstraintSystem::PotentialBinding::isViableForJoin() const {
3333
!isDefaultableBinding();
3434
}
3535

36+
bool ConstraintSystem::PotentialBindings::isDelayed() const {
37+
if (!DelayedBy.empty())
38+
return true;
39+
40+
if (isHole()) {
41+
auto *locator = TypeVar->getImpl().getLocator();
42+
assert(locator && "a hole without locator?");
43+
44+
// Delay resolution of the code completion expression until
45+
// the very end to give it a chance to be bound to some
46+
// contextual type even if it's a hole.
47+
if (locator->directlyAt<CodeCompletionExpr>())
48+
return true;
49+
50+
// Delay resolution of the `nil` literal to a hole until
51+
// the very end to give it a change to be bound to some
52+
// other type, just like code completion expression which
53+
// relies solely on contextual information.
54+
if (locator->directlyAt<NilLiteralExpr>())
55+
return true;
56+
}
57+
58+
return false;
59+
}
60+
3661
bool ConstraintSystem::PotentialBindings::isPotentiallyIncomplete() const {
3762
// Generic parameters are always potentially incomplete.
3863
if (isGenericParameter())
@@ -555,19 +580,6 @@ void ConstraintSystem::PotentialBindings::finalize(
555580
// very last moment possible, just like generic parameters.
556581
auto *locator = TypeVar->getImpl().getLocator();
557582

558-
// Delay resolution of the code completion expression until
559-
// the very end to give it a chance to be bound to some
560-
// contextual type even if it's a hole.
561-
if (locator->directlyAt<CodeCompletionExpr>())
562-
FullyBound = true;
563-
564-
// Delay resolution of the `nil` literal to a hole until
565-
// the very end to give it a change to be bound to some
566-
// other type, just like code completion expression which
567-
// relies solely on contextual information.
568-
if (locator->directlyAt<NilLiteralExpr>())
569-
FullyBound = true;
570-
571583
// If this type variable is associated with a code completion token
572584
// and it failed to infer any bindings let's adjust hole's locator
573585
// to point to a code completion token to avoid attempting to "fix"
@@ -776,7 +788,7 @@ bool ConstraintSystem::PotentialBindings::isViable(
776788

777789
bool ConstraintSystem::PotentialBindings::favoredOverDisjunction(
778790
Constraint *disjunction) const {
779-
if (isHole() || FullyBound)
791+
if (isHole() || isDelayed())
780792
return false;
781793

782794
// If this bindings are for a closure and there are no holes,
@@ -871,8 +883,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
871883
// of bindings for them until closure's body is opened.
872884
if (auto *typeVar = first->getAs<TypeVariableType>()) {
873885
if (typeVar->getImpl().isClosureType()) {
874-
result.InvolvesTypeVariables = true;
875-
result.FullyBound = true;
886+
result.DelayedBy.push_back(constraint);
876887
return None;
877888
}
878889
}
@@ -918,7 +929,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
918929
if (type->is<DependentMemberType>()) {
919930
if (!ConstraintSystem::typeVarOccursInType(typeVar, type,
920931
&result.InvolvesTypeVariables)) {
921-
result.FullyBound = true;
932+
result.DelayedBy.push_back(constraint);
922933
}
923934

924935
return None;
@@ -1056,7 +1067,7 @@ bool ConstraintSystem::PotentialBindings::infer(
10561067
// delaying bindings for as long as possible.
10571068
if (isExpr<ForceValueExpr>(anchor) && !type->is<LValueType>()) {
10581069
addPotentialBinding(binding->withType(LValueType::get(type)));
1059-
FullyBound = true;
1070+
DelayedBy.push_back(constraint);
10601071
}
10611072

10621073
// If this is a type variable representing closure result,
@@ -1076,9 +1087,6 @@ bool ConstraintSystem::PotentialBindings::infer(
10761087
break;
10771088
}
10781089
case ConstraintKind::KeyPathApplication: {
1079-
if (FullyBound)
1080-
return false;
1081-
10821090
// If this variable is in the application projected result type, mark the
10831091
// result as `FullyBound` to ensure we delay binding until we've bound
10841092
// other type variables in the KeyPathApplication constraint. This ensures
@@ -1087,8 +1095,9 @@ bool ConstraintSystem::PotentialBindings::infer(
10871095
SmallPtrSet<TypeVariableType *, 4> typeVars;
10881096
findInferableTypeVars(cs.simplifyType(constraint->getThirdType()),
10891097
typeVars);
1090-
if (typeVars.count(TypeVar))
1091-
FullyBound = true;
1098+
if (typeVars.count(TypeVar)) {
1099+
DelayedBy.push_back(constraint);
1100+
}
10921101

10931102
break;
10941103
}
@@ -1130,17 +1139,14 @@ bool ConstraintSystem::PotentialBindings::infer(
11301139
break;
11311140

11321141
case ConstraintKind::Disjunction:
1133-
// FIXME: Recurse into these constraints to see whether this
1134-
// type variable is fully bound by any of them.
1135-
InvolvesTypeVariables = true;
1136-
11371142
// If there is additional context available via disjunction
11381143
// associated with closure literal (e.g. coercion to some other
11391144
// type) let's delay resolving the closure until the disjunction
11401145
// is attempted.
11411146
if (TypeVar->getImpl().isClosureType())
11421147
return true;
11431148

1149+
DelayedBy.push_back(constraint);
11441150
break;
11451151

11461152
case ConstraintKind::ConformsTo:
@@ -1162,50 +1168,46 @@ bool ConstraintSystem::PotentialBindings::infer(
11621168
case ConstraintKind::ApplicableFunction:
11631169
case ConstraintKind::DynamicCallableApplicableFunction:
11641170
case ConstraintKind::BindOverload: {
1165-
if (FullyBound && InvolvesTypeVariables)
1166-
return false;
1167-
1168-
// If this variable is in the left-hand side, it is fully bound.
1169-
SmallPtrSet<TypeVariableType *, 4> typeVars;
1170-
findInferableTypeVars(cs.simplifyType(constraint->getFirstType()),
1171-
typeVars);
1172-
if (typeVars.count(TypeVar))
1173-
FullyBound = true;
1174-
1175-
if (InvolvesTypeVariables)
1176-
return false;
1177-
1178-
// If this and another type variable occur, this result involves
1179-
// type variables.
1180-
findInferableTypeVars(cs.simplifyType(constraint->getSecondType()),
1181-
typeVars);
1182-
if (typeVars.size() > 1 && typeVars.count(TypeVar))
1183-
InvolvesTypeVariables = true;
1171+
// It's possible that type of member couldn't be determined,
1172+
// and if so it would be beneficial to bind member to a hole
1173+
// early to propagate that information down to arguments,
1174+
// result type of a call that references such a member.
1175+
if (cs.shouldAttemptFixes() && TypeVar->getImpl().canBindToHole()) {
1176+
if (ConstraintSystem::typeVarOccursInType(
1177+
TypeVar, cs.simplifyType(constraint->getSecondType())))
1178+
break;
1179+
}
11841180

1181+
DelayedBy.push_back(constraint);
11851182
break;
11861183
}
11871184

11881185
case ConstraintKind::ValueMember:
11891186
case ConstraintKind::UnresolvedValueMember:
1190-
case ConstraintKind::ValueWitness:
1191-
// If our type variable shows up in the base type, there's
1192-
// nothing to do.
1193-
// FIXME: Can we avoid simplification here?
1194-
if (ConstraintSystem::typeVarOccursInType(
1195-
TypeVar, cs.simplifyType(constraint->getFirstType()),
1196-
&InvolvesTypeVariables)) {
1197-
return false;
1187+
case ConstraintKind::ValueWitness: {
1188+
// If current type variable represents a member type of some reference,
1189+
// it would be bound once member is resolved either to a actual member
1190+
// type or to a hole if member couldn't be found.
1191+
auto memberTy = constraint->getSecondType()->castTo<TypeVariableType>();
1192+
1193+
if (memberTy->getImpl().hasRepresentativeOrFixed()) {
1194+
if (auto type = memberTy->getImpl().getFixedType(/*record=*/nullptr)) {
1195+
// It's possible that member has been bound to some other type variable
1196+
// instead of merged with it because it's wrapped in an l-value type.
1197+
if (type->getWithoutSpecifierType()->isEqual(TypeVar)) {
1198+
DelayedBy.push_back(constraint);
1199+
break;
1200+
}
1201+
} else {
1202+
memberTy = memberTy->getImpl().getRepresentative(/*record=*/nullptr);
1203+
}
11981204
}
11991205

1200-
// If the type variable is in the list of member type
1201-
// variables, it is fully bound.
1202-
// FIXME: Can we avoid simplification here?
1203-
if (ConstraintSystem::typeVarOccursInType(
1204-
TypeVar, cs.simplifyType(constraint->getSecondType()),
1205-
&InvolvesTypeVariables)) {
1206-
FullyBound = true;
1207-
}
1206+
if (memberTy == TypeVar)
1207+
DelayedBy.push_back(constraint);
1208+
12081209
break;
1210+
}
12091211

12101212
case ConstraintKind::OneWayEqual:
12111213
case ConstraintKind::OneWayBindParam: {

0 commit comments

Comments
 (0)