Skip to content

Commit a6168a9

Browse files
authored
[CS] Don't adjust opened types of @dynamicMemberLookup overloa… (#28694)
[CS] Don't adjust opened types of @dynamicMemberLookup overloads
2 parents 392baef + bea99b1 commit a6168a9

File tree

3 files changed

+80
-64
lines changed

3 files changed

+80
-64
lines changed

lib/Sema/CSApply.cpp

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,28 +1376,17 @@ namespace {
13761376
auto subscriptRef = resolveConcreteDeclRef(subscript, memberLoc);
13771377

13781378
// Figure out the index and result types.
1379-
Type resultTy;
1380-
if (choice.getKind() != OverloadChoiceKind::DynamicMemberLookup &&
1381-
choice.getKind() != OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1382-
auto subscriptTy = simplifyType(selected.openedType);
1383-
auto *subscriptFnTy = subscriptTy->castTo<FunctionType>();
1384-
resultTy = subscriptFnTy->getResult();
1385-
1386-
// Coerce the index argument.
1387-
index = coerceCallArguments(index, subscriptFnTy, subscriptRef, nullptr,
1388-
argLabels, hasTrailingClosure,
1389-
locator.withPathElement(
1390-
ConstraintLocator::ApplyArgument));
1391-
if (!index)
1392-
return nullptr;
1379+
auto subscriptTy = simplifyType(selected.openedType);
1380+
auto *subscriptFnTy = subscriptTy->castTo<FunctionType>();
1381+
auto resultTy = subscriptFnTy->getResult();
13931382

1394-
} else {
1395-
// If this is a @dynamicMemberLookup, then the type of the selection is
1396-
// actually the property/result type. That's fine though, and we
1397-
// already have the index type adjusted to the correct type expected by
1398-
// the subscript.
1399-
resultTy = simplifyType(selected.openedType);
1400-
}
1383+
// Coerce the index argument.
1384+
index = coerceCallArguments(index, subscriptFnTy, subscriptRef, nullptr,
1385+
argLabels, hasTrailingClosure,
1386+
locator.withPathElement(
1387+
ConstraintLocator::ApplyArgument));
1388+
if (!index)
1389+
return nullptr;
14011390

14021391
auto getType = [&](const Expr *E) -> Type {
14031392
return cs.getType(E);
@@ -4490,9 +4479,6 @@ namespace {
44904479
OverloadChoiceKind::KeyPathDynamicMemberLookup;
44914480

44924481
if (forDynamicLookup) {
4493-
overload.openedType =
4494-
overload.openedFullType->castTo<AnyFunctionType>()->getResult();
4495-
44964482
labels = cs.getASTContext().Id_dynamicMember;
44974483

44984484
auto indexType = getTypeOfDynamicMemberIndex(overload);

lib/Sema/ConstraintSystem.cpp

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,9 +1875,7 @@ isInvalidPartialApplication(ConstraintSystem &cs, const ValueDecl *member,
18751875

18761876
std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
18771877
const OverloadChoice &choice, ConstraintLocator *locator,
1878-
Type boundType, Type refType, DeclContext *useDC,
1879-
llvm::function_ref<void(unsigned int, Type, ConstraintLocator *)>
1880-
verifyThatArgumentIsHashable) {
1878+
Type boundType, Type refType) {
18811879
// If the declaration is unavailable, note that in the score.
18821880
if (choice.getDecl()->getAttrs().isUnavailable(getASTContext())) {
18831881
increaseScore(SK_Unavailable);
@@ -1899,6 +1897,7 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
18991897

19001898
// Deal with values declared as implicitly unwrapped, or
19011899
// functions with return types that are implicitly unwrapped.
1900+
// TODO: Move this logic to bindOverloadType.
19021901
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
19031902
// Build the disjunction to attempt binding both T? and T (or
19041903
// function returning T? and function returning T).
@@ -1910,6 +1909,7 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
19101909
bindConstraintCreated = true;
19111910
}
19121911

1912+
// TODO: Move this to getTypeOfMemberReference.
19131913
refType = OptionalType::get(refType->getRValueType());
19141914
}
19151915

@@ -1922,6 +1922,7 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
19221922
case OverloadChoiceKind::KeyPathApplication:
19231923
return {refType, bindConstraintCreated};
19241924
case OverloadChoiceKind::DeclViaDynamic: {
1925+
// TODO: Move the IUO handling logic here to bindOverloadType.
19251926
if (isa<SubscriptDecl>(choice.getDecl())) {
19261927
// We always expect function type for subscripts.
19271928
auto fnTy = refType->castTo<AnyFunctionType>();
@@ -1982,20 +1983,52 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
19821983

19831984
// We store an Optional of the originally resolved type in the
19841985
// overload set.
1986+
// TODO: Move this to getTypeOfMemberReference.
19851987
refType = OptionalType::get(refType->getRValueType());
19861988
}
19871989

19881990
return {refType, /*bindConstraintCreated*/ true};
19891991
}
1992+
case OverloadChoiceKind::DynamicMemberLookup:
1993+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
1994+
return {refType, bindConstraintCreated};
1995+
}
1996+
1997+
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
1998+
}
1999+
2000+
void ConstraintSystem::bindOverloadType(
2001+
const SelectedOverload &overload, Type boundType,
2002+
ConstraintLocator *locator, DeclContext *useDC,
2003+
llvm::function_ref<void(unsigned int, Type, ConstraintLocator *)>
2004+
verifyThatArgumentIsHashable) {
2005+
auto choice = overload.choice;
2006+
auto openedType = overload.openedType;
2007+
2008+
auto bindTypeOrIUO = [&](Type ty) {
2009+
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
2010+
// Build the disjunction to attempt binding both T? and T (or
2011+
// function returning T? and function returning T).
2012+
buildDisjunctionForImplicitlyUnwrappedOptional(boundType, ty, locator);
2013+
} else {
2014+
// Add the type binding constraint.
2015+
addConstraint(ConstraintKind::Bind, boundType, ty, locator);
2016+
}
2017+
};
2018+
switch (choice.getKind()) {
2019+
case OverloadChoiceKind::Decl:
2020+
case OverloadChoiceKind::DeclViaBridge:
2021+
case OverloadChoiceKind::DeclViaUnwrappedOptional:
2022+
case OverloadChoiceKind::TupleIndex:
2023+
case OverloadChoiceKind::BaseType:
2024+
case OverloadChoiceKind::KeyPathApplication:
2025+
case OverloadChoiceKind::DeclViaDynamic:
2026+
bindTypeOrIUO(openedType);
2027+
return;
19902028
case OverloadChoiceKind::DynamicMemberLookup: {
19912029
// DynamicMemberLookup results are always a (dynamicMember:T1)->T2
19922030
// subscript.
1993-
auto refFnType = refType->castTo<FunctionType>();
1994-
1995-
// If this is a dynamic member lookup, then the decl we have is for the
1996-
// subscript(dynamicMember:) member, but the type we need to return is the
1997-
// result of the subscript. Dig through it.
1998-
refType = refFnType->getResult();
2031+
auto refFnType = openedType->castTo<FunctionType>();
19992032

20002033
// Before we drop the argument type on the floor, we need to constrain it
20012034
// to having a literal conformance to ExpressibleByStringLiteral. This
@@ -2008,7 +2041,7 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
20082041
TypeChecker::getProtocol(getASTContext(), choice.getDecl()->getLoc(),
20092042
KnownProtocolKind::ExpressibleByStringLiteral);
20102043
if (!stringLiteral)
2011-
return {refType, bindConstraintCreated};
2044+
return;
20122045

20132046
addConstraint(ConstraintKind::LiteralConformsTo, argType,
20142047
stringLiteral->getDeclaredType(), locator);
@@ -2018,19 +2051,21 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
20182051
if (isa<KeyPathExpr>(locator->getAnchor()))
20192052
verifyThatArgumentIsHashable(0, argType, locator);
20202053

2021-
return {refType, bindConstraintCreated};
2054+
// The resolved decl is for subscript(dynamicMember:), however the original
2055+
// member constraint was for a property. Therefore we need to bind to the
2056+
// result type.
2057+
bindTypeOrIUO(refFnType->getResult());
2058+
return;
20222059
}
20232060
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2024-
auto *fnType = refType->castTo<FunctionType>();
2061+
auto *fnType = openedType->castTo<FunctionType>();
20252062
assert(fnType->getParams().size() == 1 &&
20262063
"subscript always has one argument");
20272064
// Parameter type is KeyPath<T, U> where `T` is a root type
20282065
// and U is a leaf type (aka member type).
20292066
auto keyPathTy =
20302067
fnType->getParams()[0].getPlainType()->castTo<BoundGenericType>();
20312068

2032-
refType = fnType->getResult();
2033-
20342069
auto *keyPathDecl = keyPathTy->getAnyNominal();
20352070
assert(isKnownKeyPathDecl(getASTContext(), keyPathDecl) &&
20362071
"parameter is supposed to be a keypath");
@@ -2051,18 +2086,11 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
20512086
DeclName memberName =
20522087
isSubscriptRef ? DeclBaseName::createSubscript() : choice.getName();
20532088

2054-
auto *memberRef = Constraint::createMember(
2055-
*this, ConstraintKind::ValueMember, LValueType::get(rootTy), memberTy,
2056-
memberName, useDC,
2057-
isSubscriptRef ? FunctionRefKind::DoubleApply
2058-
: FunctionRefKind::Unapplied,
2059-
keyPathLoc);
2060-
2061-
// Delay simplication of this constraint until after the overload choice
2062-
// has been bound for this key path dynamic member. This helps to identify
2063-
// recursive calls with the same base.
2064-
addUnsolvedConstraint(memberRef);
2065-
activateConstraint(memberRef);
2089+
addValueMemberConstraint(LValueType::get(rootTy), memberName, memberTy,
2090+
useDC,
2091+
isSubscriptRef ? FunctionRefKind::DoubleApply
2092+
: FunctionRefKind::Unapplied,
2093+
/*outerAlternatives=*/{}, keyPathLoc);
20662094

20672095
// In case of subscript things are more compicated comparing to "dot"
20682096
// syntax, because we have to get "applicable function" constraint
@@ -2140,10 +2168,15 @@ std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
21402168

21412169
if (isa<KeyPathExpr>(locator->getAnchor()))
21422170
verifyThatArgumentIsHashable(0, keyPathTy, locator);
2171+
2172+
// The resolved decl is for subscript(dynamicMember:), however the
2173+
// original member constraint was either for a property, or we've
2174+
// re-purposed the overload type variable to represent the result type of
2175+
// the subscript. In both cases, we need to bind to the result type.
2176+
bindTypeOrIUO(fnType->getResult());
2177+
return;
21432178
}
2144-
return {refType, bindConstraintCreated};
21452179
}
2146-
21472180
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
21482181
}
21492182

@@ -2231,8 +2264,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
22312264
// getTypeOfMemberReference(); their result types are unchecked
22322265
// optional.
22332266
std::tie(refType, bindConstraintCreated) =
2234-
adjustTypeOfOverloadReference(choice, locator, boundType, refType,
2235-
useDC, verifyThatArgumentIsHashable);
2267+
adjustTypeOfOverloadReference(choice, locator, boundType, refType);
22362268
break;
22372269
}
22382270

@@ -2361,15 +2393,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
23612393

23622394
// In some cases we already created the appropriate bind constraints.
23632395
if (!bindConstraintCreated) {
2364-
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
2365-
// Build the disjunction to attempt binding both T? and T (or
2366-
// function returning T? and function returning T).
2367-
buildDisjunctionForImplicitlyUnwrappedOptional(boundType, refType,
2368-
locator);
2369-
} else {
2370-
// Add the type binding constraint.
2371-
addConstraint(ConstraintKind::Bind, boundType, refType, locator);
2372-
}
2396+
bindOverloadType(overload, boundType, locator, useDC,
2397+
verifyThatArgumentIsHashable);
23732398
}
23742399

23752400
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2817,7 +2817,12 @@ class ConstraintSystem {
28172817
/// this member and a bit indicating whether or not a bind constraint was added.
28182818
std::pair<Type, bool> adjustTypeOfOverloadReference(
28192819
const OverloadChoice &choice, ConstraintLocator *locator, Type boundType,
2820-
Type refType, DeclContext *useDC,
2820+
Type refType);
2821+
2822+
/// Add the constraints needed to bind an overload's type variable.
2823+
void bindOverloadType(
2824+
const SelectedOverload &overload, Type boundType,
2825+
ConstraintLocator *locator, DeclContext *useDC,
28212826
llvm::function_ref<void(unsigned int, Type, ConstraintLocator *)>
28222827
verifyThatArgumentIsHashable);
28232828

0 commit comments

Comments
 (0)