[ConstraintSystem] Store declaration context in which application occurs in ApplicableFunction constraint

This is required because `ApplicableFunction` constraint can
inject member reference constraints that require a declaration
context.

For example, `_ = { Double(...) }` would now produce a disjunction
for `Double.init` where overload choice declaration contexts point
to the closure instead of the enclosing context.

This addresses a long-standing FIXME in `simplifyApplicableFnConstraint`
and helps with disjunction optimizer because its correctness depends on
correct identification of declaration contexts where applications happen.
This commit is contained in:
Pavel Yaskevich
2025-02-09 15:41:34 -08:00
parent d24f22ec54
commit 23ace7d770
5 changed files with 191 additions and 41 deletions

View File

@@ -13107,16 +13107,12 @@ createImplicitRootForCallAsFunction(ConstraintSystem &cs, Type refType,
}
ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
Type type1, Type type2,
FunctionType *func1, Type type2,
std::optional<TrailingClosureMatching> trailingClosureMatching,
DeclContext *useDC,
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {
auto &ctx = getASTContext();
// By construction, the left hand side is a type that looks like the
// following: $T1 -> $T2.
auto func1 = type1->castTo<FunctionType>();
// Before stripping lvalue-ness and optional types, save the original second
// type for handling `func callAsFunction` and `@dynamicCallable`
// applications. This supports the following cases:
@@ -13173,7 +13169,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
auto formUnsolved = [&](bool activate = false) {
if (flags.contains(TMF_GenerateConstraints)) {
auto *application = Constraint::createApplicableFunction(
*this, type1, type2, trailingClosureMatching, useDC,
*this, func1, type2, trailingClosureMatching, useDC,
getConstraintLocator(locator));
addUnsolvedConstraint(application);
@@ -13203,7 +13199,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
// If the types are obviously equivalent, we're done. This optimization
// is not valid for operators though, where an inout parameter does not
// have an explicit inout argument.
if (type1.getPointer() == desugar2) {
if (func1 == desugar2) {
// Note that this could throw.
recordPotentialThrowSite(
PotentialThrowSite::Application, Type(desugar2), outerLocator);
@@ -13370,10 +13366,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
auto applyLocator = getConstraintLocator(locator);
auto forwardConstraint = Constraint::createApplicableFunction(
*this, type1, type2, TrailingClosureMatching::Forward, useDC,
*this, func1, type2, TrailingClosureMatching::Forward, useDC,
applyLocator);
auto backwardConstraint = Constraint::createApplicableFunction(
*this, type1, type2, TrailingClosureMatching::Backward, useDC,
*this, func1, type2, TrailingClosureMatching::Backward, useDC,
applyLocator);
addDisjunctionConstraint({forwardConstraint, backwardConstraint},
applyLocator);
@@ -13472,7 +13468,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
// Handle applications of @dynamicCallable types.
auto result = simplifyDynamicCallableApplicableFnConstraint(
type1, origType2, subflags, locator);
func1, origType2, subflags, locator);
if (shouldAttemptFixes() && result == SolutionKind::Error) {
// Skip this fix if the type is not yet resolved or
@@ -16204,9 +16200,9 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
case ConstraintKind::ApplicableFunction:
return simplifyApplicableFnConstraint(
constraint.getFirstType(), constraint.getSecondType(),
constraint.getAppliedFunctionType(), constraint.getCalleeType(),
constraint.getTrailingClosureMatching(),
/*FIXME*/DC, /*flags=*/std::nullopt,
constraint.getApplicationDC(), /*flags=*/std::nullopt,
constraint.getLocator());
case ConstraintKind::DynamicCallableApplicableFunction: