Skip to content

Commit 9649b76

Browse files
committed
[CSBindings] Don't generate bindings for defaults
Let's keep defaults separate from direct and transitive bindings, that would make it easier to handle them in incremental model. Instead of generating bindings for defaults and adding to the main set, let's allow producer to choose what to do with them once type variable has been picked for attempting.
1 parent f3da35a commit 9649b76

File tree

3 files changed

+129
-58
lines changed

3 files changed

+129
-58
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,7 +4741,7 @@ class ConstraintSystem {
47414741
Optional<llvm::SmallPtrSet<Constraint *, 4>> TransitiveProtocols;
47424742

47434743
/// The set of constraints which would be used to infer default types.
4744-
llvm::TinyPtrVector<Constraint *> Defaults;
4744+
llvm::SmallDenseMap<CanType, Constraint *, 2> Defaults;
47454745

47464746
/// The set of constraints which delay attempting this type variable.
47474747
llvm::TinyPtrVector<Constraint *> DelayedBy;
@@ -4772,7 +4772,7 @@ class ConstraintSystem {
47724772

47734773
/// Determine whether the set of bindings is non-empty.
47744774
explicit operator bool() const {
4775-
return !Bindings.empty() || isDirectHole();
4775+
return !Bindings.empty() || !Defaults.empty() || isDirectHole();
47764776
}
47774777

47784778
/// Determine whether attempting this type variable should be
@@ -4822,7 +4822,8 @@ class ConstraintSystem {
48224822
if (!CS.shouldAttemptFixes())
48234823
return false;
48244824

4825-
return Bindings.empty() && TypeVar->getImpl().canBindToHole();
4825+
return Bindings.empty() && Defaults.empty() &&
4826+
TypeVar->getImpl().canBindToHole();
48264827
}
48274828

48284829
/// Determine if the bindings only constrain the type variable from above
@@ -4838,19 +4839,38 @@ class ConstraintSystem {
48384839
});
48394840
}
48404841

4841-
unsigned getNumDefaultableBindings() const {
4842-
return isDirectHole()
4843-
? 1
4844-
: llvm::count_if(Bindings,
4845-
[](const PotentialBinding &binding) {
4846-
return binding.isDefaultableBinding();
4847-
});
4842+
unsigned getNumViableDefaultableBindings() const {
4843+
if (isDirectHole())
4844+
return 1;
4845+
4846+
// We might want to consider adding this as a field to `PotentialBindings`
4847+
// and collect this information as new bindings become available but,
4848+
// since we are moving towards incremental model, which implies that
4849+
// `PotentialBindings` would stay alive for a long time, it's not
4850+
// immediately clear whether storage overhead of keeping this set just
4851+
// for ranking is worth it.
4852+
llvm::SmallPtrSet<CanType, 4> discoveredTypes;
4853+
for (const auto &binding : Bindings)
4854+
discoveredTypes.insert(binding.BindingType->getCanonicalType());
4855+
4856+
return llvm::count_if(
4857+
Defaults, [&](const std::pair<CanType, Constraint *> &def) {
4858+
return def.second->getKind() == ConstraintKind::Defaultable &&
4859+
discoveredTypes.count(def.first) == 0;
4860+
});
48484861
}
48494862

48504863
static BindingScore formBindingScore(const PotentialBindings &b) {
4851-
auto numDefaults = b.getNumDefaultableBindings();
4864+
// If there are no bindings available but this type
4865+
// variable represents a closure - let's consider it
4866+
// as having a single non-default binding - that would
4867+
// be a type inferred based on context.
4868+
// It's considered to be non-default for purposes of
4869+
// ranking because we'd like to prioritize resolving
4870+
// closures to gain more information from their bodies.
48524871
auto numNonDefaultableBindings =
4853-
b.isDirectHole() ? 0 : b.Bindings.size() - numDefaults;
4872+
!b.Bindings.empty() ? b.Bindings.size()
4873+
: b.TypeVar->getImpl().isClosureType() ? 1 : 0;
48544874

48554875
return std::make_tuple(b.isHole(),
48564876
numNonDefaultableBindings == 0,
@@ -4874,10 +4894,8 @@ class ConstraintSystem {
48744894
if (yScore < xScore)
48754895
return false;
48764896

4877-
auto xDefaults =
4878-
x.isDirectHole() ? 1 : x.Bindings.size() + std::get<6>(xScore);
4879-
auto yDefaults =
4880-
y.isDirectHole() ? 1 : y.Bindings.size() + std::get<6>(yScore);
4897+
auto xDefaults = x.getNumViableDefaultableBindings();
4898+
auto yDefaults = y.getNumViableDefaultableBindings();
48814899

48824900
// If there is a difference in number of default types,
48834901
// prioritize bindings with fewer of them.
@@ -4922,6 +4940,8 @@ class ConstraintSystem {
49224940
}
49234941
}
49244942

4943+
void addDefault(Constraint *constraint);
4944+
49254945
/// Add a potential binding to the list of bindings,
49264946
/// coalescing supertype bounds when we are able to compute the meet.
49274947
void addPotentialBinding(PotentialBinding binding,
@@ -5014,34 +5034,46 @@ class ConstraintSystem {
50145034
if (involvesTypeVariables())
50155035
out << "involves_type_vars ";
50165036

5017-
auto numDefaultable = getNumDefaultableBindings();
5037+
auto numDefaultable = getNumViableDefaultableBindings();
50185038
if (numDefaultable > 0)
50195039
out << "#defaultable_bindings=" << numDefaultable << " ";
50205040

50215041
PrintOptions PO;
50225042
PO.PrintTypesForDebugging = true;
5043+
5044+
auto printBinding = [&](const PotentialBinding &binding) {
5045+
auto type = binding.BindingType;
5046+
switch (binding.Kind) {
5047+
case AllowedBindingKind::Exact:
5048+
break;
5049+
5050+
case AllowedBindingKind::Subtypes:
5051+
out << "(subtypes of) ";
5052+
break;
5053+
5054+
case AllowedBindingKind::Supertypes:
5055+
out << "(supertypes of) ";
5056+
break;
5057+
}
5058+
if (auto *literal = binding.getDefaultedLiteralProtocol())
5059+
out << "(default from " << literal->getName() << ") ";
5060+
out << type.getString(PO);
5061+
};
5062+
50235063
out << "bindings={";
5024-
interleave(Bindings,
5025-
[&](const PotentialBinding &binding) {
5026-
auto type = binding.BindingType;
5027-
switch (binding.Kind) {
5028-
case AllowedBindingKind::Exact:
5029-
break;
5030-
5031-
case AllowedBindingKind::Subtypes:
5032-
out << "(subtypes of) ";
5033-
break;
5034-
5035-
case AllowedBindingKind::Supertypes:
5036-
out << "(supertypes of) ";
5037-
break;
5038-
}
5039-
if (auto *literal = binding.getDefaultedLiteralProtocol())
5040-
out << "(default from " << literal->getName() << ") ";
5041-
out << type.getString(PO);
5042-
},
5043-
[&]() { out << "; "; });
5064+
interleave(Bindings, printBinding, [&]() { out << "; "; });
50445065
out << "}";
5066+
5067+
if (!Defaults.empty()) {
5068+
out << " defaults={";
5069+
for (const auto &entry : Defaults) {
5070+
auto *constraint = entry.second;
5071+
PotentialBinding binding{constraint->getSecondType(),
5072+
AllowedBindingKind::Exact, constraint};
5073+
printBinding(binding);
5074+
}
5075+
out << "}";
5076+
}
50455077
}
50465078

50475079
void dump(ConstraintSystem *cs,
@@ -5839,6 +5871,9 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
58395871

58405872
TypeVariableType *TypeVar;
58415873
llvm::SmallVector<Binding, 8> Bindings;
5874+
/// The set of defaults to attempt once producer
5875+
/// runs out of direct & transitive bindings.
5876+
llvm::SmallVector<Constraint *, 4> DelayedDefaults;
58425877

58435878
// The index pointing to the offset in the bindings
58445879
// generator is currently at, `numTries` represents
@@ -5886,6 +5921,8 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
58865921
/// Check whether binding type is required to either conform to
58875922
/// `ExpressibleByNilLiteral` protocol or be wrapped into an optional type.
58885923
bool requiresOptionalAdjustment(const Binding &binding) const;
5924+
5925+
Binding getDefaultBinding(Constraint *constraint) const;
58895926
};
58905927

58915928
/// Iterator over disjunction choices, makes it

lib/Sema/CSBindings.cpp

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
319319
});
320320

321321
// Infer transitive defaults.
322-
llvm::copy(bindings.Defaults, std::back_inserter(Defaults));
322+
for (const auto &def : bindings.Defaults)
323+
addDefault(def.second);
323324

324325
// TODO: We shouldn't need this in the future.
325326
if (entry.second->getKind() != ConstraintKind::Subtype)
@@ -513,24 +514,6 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
513514
: AllowedBindingKind::Supertypes,
514515
constraint});
515516
}
516-
517-
/// Add defaultable constraints.
518-
for (auto *constraint : Defaults) {
519-
Type type = constraint->getSecondType();
520-
if (!existingTypes.insert(type->getCanonicalType()).second)
521-
continue;
522-
523-
if (constraint->getKind() == ConstraintKind::DefaultClosureType) {
524-
// If there are no other possible bindings for this closure
525-
// let's default it to the type inferred from its parameters/body,
526-
// otherwise we should only attempt contextual types as a
527-
// top-level closure type.
528-
if (!Bindings.empty())
529-
continue;
530-
}
531-
532-
addPotentialBinding({type, AllowedBindingKind::Exact, constraint});
533-
}
534517
}
535518

536519
void ConstraintSystem::PotentialBindings::finalize(
@@ -575,7 +558,7 @@ ConstraintSystem::determineBestBindings() {
575558
if (shouldAttemptFixes() && typeVar->getImpl().canBindToHole())
576559
return true;
577560

578-
return bindings || !bindings.Defaults.empty() ||
561+
return bindings ||
579562
llvm::any_of(bindings.Protocols, [&](Constraint *constraint) {
580563
return bool(
581564
TypeChecker::getDefaultType(constraint->getProtocol(), DC));
@@ -654,6 +637,11 @@ findInferableTypeVars(Type type,
654637
type.walk(Walker(typeVars));
655638
}
656639

640+
void ConstraintSystem::PotentialBindings::addDefault(Constraint *constraint) {
641+
auto defaultTy = constraint->getSecondType();
642+
Defaults.insert({defaultTy->getCanonicalType(), constraint});
643+
}
644+
657645
void ConstraintSystem::PotentialBindings::addPotentialBinding(
658646
PotentialBinding binding, bool allowJoinMeet) {
659647
assert(!binding.BindingType->is<ErrorType>());
@@ -1094,7 +1082,7 @@ bool ConstraintSystem::PotentialBindings::infer(
10941082
// Do these in a separate pass.
10951083
if (cs.getFixedTypeRecursive(constraint->getFirstType(), true)
10961084
->getAs<TypeVariableType>() == TypeVar) {
1097-
Defaults.push_back(constraint);
1085+
addDefault(constraint);
10981086
}
10991087
break;
11001088

@@ -1358,6 +1346,22 @@ bool TypeVarBindingProducer::computeNext() {
13581346
}
13591347
}
13601348

1349+
if (NumTries == 0) {
1350+
// Add defaultable constraints (if any).
1351+
for (auto *constraint : DelayedDefaults) {
1352+
if (constraint->getKind() == ConstraintKind::DefaultClosureType) {
1353+
// If there are no other possible bindings for this closure
1354+
// let's default it to the type inferred from its parameters/body,
1355+
// otherwise we should only attempt contextual types as a
1356+
// top-level closure type.
1357+
if (!ExploredTypes.empty())
1358+
continue;
1359+
}
1360+
1361+
addNewBinding(getDefaultBinding(constraint));
1362+
}
1363+
}
1364+
13611365
if (newBindings.empty())
13621366
return false;
13631367

lib/Sema/ConstraintSystem.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5378,6 +5378,24 @@ TypeVarBindingProducer::TypeVarBindingProducer(
53785378
if (Any) {
53795379
Bindings.push_back(*Any);
53805380
}
5381+
5382+
{
5383+
bool noBindings = Bindings.empty();
5384+
5385+
for (const auto &entry : bindings.Defaults) {
5386+
auto *constraint = entry.second;
5387+
if (noBindings) {
5388+
// If there are no direct or transitive bindings to attempt
5389+
// let's add defaults to the list right away.
5390+
Bindings.push_back(getDefaultBinding(constraint));
5391+
} else {
5392+
// Otherwise let's delay attempting default bindings
5393+
// until all of the direct & transitive bindings and
5394+
// their derivatives have been attempted.
5395+
DelayedDefaults.push_back(constraint);
5396+
}
5397+
}
5398+
}
53815399
}
53825400

53835401
bool TypeVarBindingProducer::requiresOptionalAdjustment(
@@ -5409,3 +5427,15 @@ bool TypeVarBindingProducer::requiresOptionalAdjustment(
54095427

54105428
return false;
54115429
}
5430+
5431+
ConstraintSystem::PotentialBinding
5432+
TypeVarBindingProducer::getDefaultBinding(Constraint *constraint) const {
5433+
assert(constraint->getKind() == ConstraintKind::Defaultable ||
5434+
constraint->getKind() == ConstraintKind::DefaultClosureType);
5435+
5436+
auto type = constraint->getSecondType();
5437+
Binding binding{type, BindingKind::Exact, constraint};
5438+
return requiresOptionalAdjustment(binding)
5439+
? binding.withType(OptionalType::get(type))
5440+
: binding;
5441+
}

0 commit comments

Comments
 (0)