Skip to content

Commit e676e05

Browse files
committed
[CSBindings] Transform literal requirements into bindings when type variable is attempted
1 parent 731810e commit e676e05

File tree

4 files changed

+115
-85
lines changed

4 files changed

+115
-85
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4786,7 +4786,8 @@ class ConstraintSystem {
47864786

47874787
/// Determine whether the set of bindings is non-empty.
47884788
explicit operator bool() const {
4789-
return !Bindings.empty() || !Defaults.empty() || isDirectHole();
4789+
return !Bindings.empty() || getNumViableLiteralBindings() > 0 ||
4790+
!Defaults.empty() || isDirectHole();
47904791
}
47914792

47924793
/// Determines whether this type variable could be `nil`,
@@ -4840,8 +4841,8 @@ class ConstraintSystem {
48404841
if (!CS.shouldAttemptFixes())
48414842
return false;
48424843

4843-
return Bindings.empty() && Defaults.empty() &&
4844-
TypeVar->getImpl().canBindToHole();
4844+
return Bindings.empty() && getNumViableLiteralBindings() == 0 &&
4845+
Defaults.empty() && TypeVar->getImpl().canBindToHole();
48454846
}
48464847

48474848
/// Determine if the bindings only constrain the type variable from above
@@ -4857,6 +4858,8 @@ class ConstraintSystem {
48574858
});
48584859
}
48594860

4861+
unsigned getNumViableLiteralBindings() const;
4862+
48604863
unsigned getNumViableDefaultableBindings() const {
48614864
if (isDirectHole())
48624865
return 1;
@@ -4893,9 +4896,12 @@ class ConstraintSystem {
48934896
// It's considered to be non-default for purposes of
48944897
// ranking because we'd like to prioritize resolving
48954898
// closures to gain more information from their bodies.
4896-
auto numNonDefaultableBindings =
4897-
!b.Bindings.empty() ? b.Bindings.size()
4898-
: b.TypeVar->getImpl().isClosureType() ? 1 : 0;
4899+
unsigned numBindings =
4900+
b.Bindings.size() + b.getNumViableLiteralBindings();
4901+
auto numNonDefaultableBindings = numBindings > 0 ? numBindings
4902+
: b.TypeVar->getImpl().isClosureType()
4903+
? 1
4904+
: 0;
48994905

49004906
return std::make_tuple(b.isHole(),
49014907
numNonDefaultableBindings == 0,
@@ -4946,34 +4952,7 @@ class ConstraintSystem {
49464952
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
49474953
}
49484954

4949-
LiteralBindingKind getLiteralKind() const {
4950-
LiteralBindingKind kind = LiteralBindingKind::None;
4951-
4952-
for (const auto &binding : Bindings) {
4953-
auto *proto = binding.getDefaultedLiteralProtocol();
4954-
if (!proto)
4955-
continue;
4956-
4957-
switch (*proto->getKnownProtocolKind()) {
4958-
case KnownProtocolKind::ExpressibleByDictionaryLiteral:
4959-
case KnownProtocolKind::ExpressibleByArrayLiteral:
4960-
case KnownProtocolKind::ExpressibleByStringInterpolation:
4961-
kind = LiteralBindingKind::Collection;
4962-
break;
4963-
4964-
case KnownProtocolKind::ExpressibleByFloatLiteral:
4965-
kind = LiteralBindingKind::Float;
4966-
break;
4967-
4968-
default:
4969-
if (kind != LiteralBindingKind::Collection)
4970-
kind = LiteralBindingKind::Atom;
4971-
break;
4972-
}
4973-
}
4974-
4975-
return kind;
4976-
}
4955+
LiteralBindingKind getLiteralKind() const;
49774956

49784957
void addDefault(Constraint *constraint);
49794958

@@ -5060,11 +5039,6 @@ class ConstraintSystem {
50605039
ConstraintSystem::PotentialBindings>
50615040
&inferredBindings);
50625041

5063-
/// Infer bindings based on any protocol conformances that have default
5064-
/// types.
5065-
void inferDefaultTypes(ConstraintSystem &cs,
5066-
llvm::SmallPtrSetImpl<CanType> &existingTypes);
5067-
50685042
public:
50695043
bool infer(ConstraintSystem &cs,
50705044
llvm::SmallPtrSetImpl<CanType> &exactTypes,

lib/Sema/CSBindings.cpp

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -355,35 +355,6 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
355355
}
356356
}
357357

358-
void ConstraintSystem::PotentialBindings::inferDefaultTypes(
359-
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
360-
for (const auto &literal : Literals) {
361-
Constraint *constraint = nullptr;
362-
bool isDirectRequirement = false;
363-
Constraint *coveredBy = nullptr;
364-
365-
std::tie(constraint, isDirectRequirement, coveredBy) = literal.second;
366-
367-
// Can't be defaulted because it's already covered by an
368-
// existing direct or transitive binding which is always
369-
// better.
370-
if (coveredBy)
371-
continue;
372-
373-
auto defaultType = TypeChecker::getDefaultType(literal.first, cs.DC);
374-
if (!defaultType)
375-
continue;
376-
377-
// We need to figure out whether this is a direct conformance
378-
// requirement or inferred transitive one to identify binding
379-
// kind correctly.
380-
addPotentialBinding({defaultType,
381-
isDirectRequirement ? AllowedBindingKind::Subtypes
382-
: AllowedBindingKind::Supertypes,
383-
constraint});
384-
}
385-
}
386-
387358
void ConstraintSystem::PotentialBindings::finalize(
388359
ConstraintSystem &cs,
389360
llvm::SmallDenseMap<TypeVariableType *, ConstraintSystem::PotentialBindings>
@@ -396,7 +367,6 @@ void ConstraintSystem::PotentialBindings::finalize(
396367

397368
inferTransitiveProtocolRequirements(cs, inferredBindings);
398369
inferTransitiveBindings(cs, existingTypes, inferredBindings);
399-
inferDefaultTypes(cs, existingTypes);
400370
}
401371

402372
Optional<ConstraintSystem::PotentialBindings>
@@ -426,13 +396,7 @@ ConstraintSystem::determineBestBindings() {
426396
if (shouldAttemptFixes() && typeVar->getImpl().canBindToHole())
427397
return true;
428398

429-
return bindings ||
430-
llvm::any_of(
431-
bindings.Literals,
432-
[&](const std::pair<ProtocolDecl *,
433-
PotentialBindings::LiteralInfo> &literal) {
434-
return bool(TypeChecker::getDefaultType(literal.first, DC));
435-
});
399+
return bool(bindings);
436400
};
437401

438402
// Now let's see if we could infer something for related type
@@ -1210,6 +1174,47 @@ bool ConstraintSystem::PotentialBindings::infer(
12101174
return false;
12111175
}
12121176

1177+
ConstraintSystem::LiteralBindingKind
1178+
ConstraintSystem::PotentialBindings::getLiteralKind() const {
1179+
LiteralBindingKind kind = LiteralBindingKind::None;
1180+
1181+
for (const auto &literal : Literals) {
1182+
auto *protocol = literal.first;
1183+
auto *coveredBy = std::get<2>(literal.second);
1184+
1185+
// Only uncovered defaultable literal protocols participate.
1186+
if (coveredBy || !TypeChecker::getDefaultType(protocol, CS.DC))
1187+
continue;
1188+
1189+
switch (*protocol->getKnownProtocolKind()) {
1190+
case KnownProtocolKind::ExpressibleByDictionaryLiteral:
1191+
case KnownProtocolKind::ExpressibleByArrayLiteral:
1192+
case KnownProtocolKind::ExpressibleByStringInterpolation:
1193+
kind = LiteralBindingKind::Collection;
1194+
break;
1195+
1196+
case KnownProtocolKind::ExpressibleByFloatLiteral:
1197+
kind = LiteralBindingKind::Float;
1198+
break;
1199+
1200+
default:
1201+
if (kind != LiteralBindingKind::Collection)
1202+
kind = LiteralBindingKind::Atom;
1203+
break;
1204+
}
1205+
}
1206+
1207+
return kind;
1208+
}
1209+
1210+
unsigned
1211+
ConstraintSystem::PotentialBindings::getNumViableLiteralBindings() const {
1212+
return llvm::count_if(Literals, [&](const auto &literal) {
1213+
auto *coveredBy = std::get<2>(literal.second);
1214+
return !(coveredBy || !TypeChecker::getDefaultType(literal.first, CS.DC));
1215+
});
1216+
}
1217+
12131218
/// Check whether the given type can be used as a binding for the given
12141219
/// type variable.
12151220
///

lib/Sema/CSSolver.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,11 +2287,31 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
22872287
return;
22882288

22892289
auto bindings = cs.inferBindingsFor(typeVar);
2290-
if (bindings.isHole() || bindings.involvesTypeVariables() ||
2291-
bindings.Bindings.size() != 1)
2290+
2291+
auto numBindings =
2292+
bindings.Bindings.size() + bindings.getNumViableLiteralBindings();
2293+
if (bindings.isHole() || bindings.involvesTypeVariables() || numBindings != 1)
22922294
return;
22932295

2294-
auto conversionType = bindings.Bindings[0].BindingType;
2296+
Type conversionType;
2297+
2298+
// There is either a single direct/transitive binding, or
2299+
// a single literal default.
2300+
if (!bindings.Bindings.empty()) {
2301+
conversionType = bindings.Bindings[0].BindingType;
2302+
} else {
2303+
for (const auto &literal : bindings.Literals) {
2304+
auto *coveredBy = std::get<2>(literal.second);
2305+
if (coveredBy)
2306+
continue;
2307+
2308+
if (auto defaultTy = TypeChecker::getDefaultType(literal.first, cs.DC)) {
2309+
conversionType = defaultTy;
2310+
break;
2311+
}
2312+
}
2313+
}
2314+
22952315
auto constraints = cs.CG.gatherConstraints(
22962316
typeVar,
22972317
ConstraintGraph::GatheringKind::EquivalenceClass,

lib/Sema/ConstraintSystem.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
195195
if (auto defaultType = TypeChecker::getDefaultType(literalProtocol, DC)) {
196196
// Check whether the nominal types match. This makes sure that we
197197
// properly handle Array vs. Array<T>.
198-
if (defaultType->getAnyNominal() != type->getAnyNominal())
198+
if (defaultType->getAnyNominal() != type->getAnyNominal()) {
199199
increaseScore(SK_NonDefaultLiteral);
200+
}
200201
}
201202
}
202203
}
@@ -5349,18 +5350,48 @@ TypeVarBindingProducer::TypeVarBindingProducer(
53495350
// A binding to `Any` which should always be considered as a last resort.
53505351
Optional<Binding> Any;
53515352

5352-
for (const auto &binding : bindings.Bindings) {
5353-
auto type = binding.BindingType;
5354-
5353+
auto addBinding = [&](const Binding &binding) {
53555354
// Adjust optionality of existing bindings based on presence of
53565355
// `ExpressibleByNilLiteral` requirement.
53575356
if (requiresOptionalAdjustment(binding)) {
5358-
Bindings.push_back(binding.withType(OptionalType::get(type)));
5359-
} else if (type->isAny()) {
5357+
Bindings.push_back(
5358+
binding.withType(OptionalType::get(binding.BindingType)));
5359+
} else if (binding.BindingType->isAny()) {
53605360
Any.emplace(binding);
53615361
} else {
53625362
Bindings.push_back(binding);
53635363
}
5364+
};
5365+
5366+
for (const auto &binding : bindings.Bindings) {
5367+
addBinding(binding);
5368+
}
5369+
5370+
// Infer defaults based on "uncovered" literal protocol requirements.
5371+
for (const auto &literal : bindings.Literals) {
5372+
Constraint *constraint = nullptr;
5373+
bool isDirectRequirement = false;
5374+
Constraint *coveredBy = nullptr;
5375+
5376+
std::tie(constraint, isDirectRequirement, coveredBy) = literal.second;
5377+
5378+
// Can't be defaulted because it's already covered by an
5379+
// existing direct or transitive binding which is always
5380+
// better.
5381+
if (coveredBy)
5382+
continue;
5383+
5384+
auto defaultType = TypeChecker::getDefaultType(literal.first, CS.DC);
5385+
if (!defaultType)
5386+
continue;
5387+
5388+
// We need to figure out whether this is a direct conformance
5389+
// requirement or inferred transitive one to identify binding
5390+
// kind correctly.
5391+
addBinding(
5392+
{defaultType,
5393+
isDirectRequirement ? BindingKind::Subtypes : BindingKind::Supertypes,
5394+
constraint});
53645395
}
53655396

53665397
// Let's always consider `Any` to be a last resort binding because

0 commit comments

Comments
 (0)