Skip to content

Commit fccb3e0

Browse files
[CSBindings] Prevent solver from infering default binding to auto closures arguments
1 parent b16f340 commit fccb3e0

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,12 @@ void PotentialBindings::inferTransitiveBindings(
336336
addLiteral(literal.second.getSource());
337337

338338
// Infer transitive defaults.
339-
for (const auto &def : bindings.Defaults)
339+
for (const auto &def : bindings.Defaults) {
340+
if (def.getSecond()->getKind() == ConstraintKind::DefaultClosureType)
341+
continue;
342+
340343
addDefault(def.second);
344+
}
341345

342346
// TODO: We shouldn't need this in the future.
343347
if (entry.second->getKind() != ConstraintKind::Subtype)
@@ -366,11 +370,45 @@ void PotentialBindings::inferTransitiveBindings(
366370
}
367371
}
368372

373+
// If potential binding type variable is a closure that has a subtype relation
374+
// associated with argument conversion constraint located directly on an
375+
// autoclosure parameter.
376+
static bool
377+
isClosureInAutoClosureArgumentConversion(PotentialBindings &bindings) {
378+
379+
if (!bindings.TypeVar->getImpl().isClosureType())
380+
return false;
381+
382+
return llvm::any_of(
383+
bindings.SubtypeOf,
384+
[](std::pair<TypeVariableType *, Constraint *> subType) {
385+
if (subType.second->getKind() != ConstraintKind::ArgumentConversion)
386+
return false;
387+
return subType.second->getLocator()
388+
->isLastElement<LocatorPathElt::AutoclosureResult>();
389+
});
390+
}
391+
369392
void PotentialBindings::finalize(
370393
llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
371394
&inferredBindings) {
372395
inferTransitiveProtocolRequirements(inferredBindings);
373396
inferTransitiveBindings(inferredBindings);
397+
398+
// For autoclosure parameters if we have a closure argument which could
399+
// default to `() -> $T`, we avoid infering defaultable binding because
400+
// an autoclosure cannot accept a closure paramenter unless the result `$T`
401+
// is bound to a function type via another contextual binding. Also consider
402+
// adjacent vars because they can also default transitively.
403+
if (isClosureInAutoClosureArgumentConversion(*this)) {
404+
auto closureDefault = llvm::find_if(
405+
Defaults, [](const std::pair<CanType, Constraint *> &entry) {
406+
return entry.second->getKind() == ConstraintKind::DefaultClosureType;
407+
});
408+
if (closureDefault != Defaults.end()) {
409+
Defaults.erase(closureDefault);
410+
}
411+
}
374412
}
375413

376414
PotentialBindings::BindingScore

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2520,7 +2520,7 @@ namespace {
25202520
closure->walk(collectVarRefs);
25212521

25222522
// If walker discovered error expressions, let's fail constraint
2523-
// genreation only if closure is going to participate
2523+
// generation only if closure is going to participate
25242524
// in the type-check. This allows us to delay validation of
25252525
// multi-statement closures until body is opened.
25262526
if (shouldTypeCheckInEnclosingExpression(closure) &&

0 commit comments

Comments
 (0)