Skip to content

Commit 9eed013

Browse files
committed
[CSSolver] Don't generate implicit argument for keypath dynamic lookup
Implicit argument expression was necessary to generate keypath constraint which is used to validate a choice picked for the member. But since read-only check has been factored out it's now possible to validate choice directly in combination with new 'keypath dynamic lookup' locator associated with member type variable which represents result of the dynamic lookup.
1 parent 3e7a7a2 commit 9eed013

File tree

4 files changed

+77
-109
lines changed

4 files changed

+77
-109
lines changed

lib/Sema/CSApply.cpp

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,18 +1515,44 @@ namespace {
15151515
return ctorRef;
15161516
}
15171517

1518-
Expr *buildKeyPathDynamicMemberIndexExpr(ConstraintLocator *memberLoc) {
1519-
auto arg = solution.DynamicMemberArguments.find(memberLoc);
1520-
assert(arg != solution.DynamicMemberArguments.end() &&
1521-
"cannot find argument for keypath dynamic member lookup");
1522-
1523-
auto *keyPath = arg->getSecond();
1524-
keyPath->forEachChildExpr([&](Expr *childExpr) -> Expr * {
1525-
simplifyExprType(childExpr);
1526-
return childExpr;
1527-
});
1518+
/// Build an implicit argument for keypath based dynamic lookup,
1519+
/// which consists of KeyPath expression and a single component.
1520+
///
1521+
/// \param keyPathTy The type of the keypath argument.
1522+
/// \param dotLoc The location of the '.' preceding member name.
1523+
/// \param memberLoc The locator to be associated with new argument.
1524+
Expr *buildKeyPathDynamicMemberIndexExpr(BoundGenericType *keyPathTy,
1525+
SourceLoc dotLoc,
1526+
ConstraintLocator *memberLoc) {
1527+
auto &ctx = cs.getASTContext();
1528+
// Only properties are supported at the moment.
1529+
auto *UDE = dyn_cast<UnresolvedDotExpr>(memberLoc->getAnchor());
1530+
if (!UDE)
1531+
return nullptr;
1532+
1533+
simplifyExprType(UDE);
1534+
UDE->setType(cs.getType(UDE));
15281535

1529-
return visitKeyPathExpr(keyPath);
1536+
// Let's re-use existinng expression but switch its base
1537+
// to keypath special dot expression.
1538+
UDE->setBase(new (ctx) KeyPathDotExpr(dotLoc));
1539+
1540+
// Now, let's create a KeyPath expression itself.
1541+
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
1542+
/*parsedRoot=*/nullptr,
1543+
/*parsedPath=*/UDE,
1544+
/*isImplicit=*/true);
1545+
1546+
auto *propertyLoc = cs.getConstraintLocator(
1547+
memberLoc,
1548+
LocatorPathElt::getKeyPathDynamicMember(keyPathTy->getAnyNominal()));
1549+
auto overload = solution.getOverloadChoice(propertyLoc);
1550+
keyPath->resolveComponents(
1551+
ctx, {buildKeyPathPropertyComponent(overload, UDE->getLoc(),
1552+
propertyLoc)});
1553+
keyPath->setType(keyPathTy);
1554+
cs.cacheType(keyPath);
1555+
return keyPath;
15301556
}
15311557

15321558
/// Bridge the given value (which is an error type) to NSError.
@@ -2697,7 +2723,8 @@ namespace {
26972723
auto fieldName = selected.choice.getName().getBaseIdentifier().str();
26982724
argExpr = buildDynamicMemberLookupIndexExpr(fieldName, loc, dc, cs);
26992725
} else {
2700-
argExpr = buildKeyPathDynamicMemberIndexExpr(memberLocator);
2726+
argExpr = buildKeyPathDynamicMemberIndexExpr(
2727+
paramTy->castTo<BoundGenericType>(), dotLoc, memberLocator);
27012728
}
27022729

27032730
assert(argExpr);
@@ -4128,10 +4155,6 @@ namespace {
41284155
KeyPathSubscriptComponents;
41294156
public:
41304157
Expr *visitKeyPathExpr(KeyPathExpr *E) {
4131-
return visitKeyPathExpr(E, cs.getConstraintLocator(E));
4132-
}
4133-
4134-
Expr *visitKeyPathExpr(KeyPathExpr *E, ConstraintLocator *baseLocator) {
41354158
if (E->isObjC()) {
41364159
cs.setType(E, cs.getType(E->getObjCStringLiteralExpr()));
41374160
return E;
@@ -4205,8 +4228,7 @@ namespace {
42054228
Optional<SelectedOverload> foundDecl;
42064229

42074230
auto locator = cs.getConstraintLocator(
4208-
baseLocator,
4209-
ConstraintLocator::PathElement::getKeyPathComponent(i));
4231+
E, ConstraintLocator::PathElement::getKeyPathComponent(i));
42104232
if (kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
42114233
locator =
42124234
cs.getConstraintLocator(locator,

lib/Sema/CSSolver.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,6 @@ Solution ConstraintSystem::finalize() {
172172
for (auto &e : CheckedConformances)
173173
solution.Conformances.push_back({e.first, e.second});
174174

175-
for (auto &arg : DynamicMemberArguments)
176-
solution.DynamicMemberArguments.insert(arg);
177-
178175
return solution;
179176
}
180177

@@ -245,11 +242,6 @@ void ConstraintSystem::applySolution(const Solution &solution) {
245242
// Register any missing members encountered along this path.
246243
MissingMembers.insert(solution.MissingMembers.begin(),
247244
solution.MissingMembers.end());
248-
249-
// Register any implicitly generated argument used by keypath
250-
// based dynamic member lookup.
251-
DynamicMemberArguments.append(solution.DynamicMemberArguments.begin(),
252-
solution.DynamicMemberArguments.end());
253245
}
254246

255247
/// Restore the type variable bindings to what they were before
@@ -433,7 +425,6 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
433425
numMissingMembers = cs.MissingMembers.size();
434426
numDisabledConstraints = cs.solverState->getNumDisabledConstraints();
435427
numFavoredConstraints = cs.solverState->getNumFavoredConstraints();
436-
numDynamicMemberArguments = cs.DynamicMemberArguments.size();
437428

438429
PreviousScore = cs.CurrentScore;
439430

@@ -488,10 +479,6 @@ ConstraintSystem::SolverScope::~SolverScope() {
488479
// Remove any missing members found along the current path.
489480
truncate(cs.MissingMembers, numMissingMembers);
490481

491-
// Remove any implicitly generated arguments used by keypath
492-
// based dynamic lookup generated along the current path.
493-
truncate(cs.DynamicMemberArguments, numDynamicMemberArguments);
494-
495482
// Reset the previous score.
496483
cs.CurrentScore = PreviousScore;
497484

lib/Sema/ConstraintSystem.cpp

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,42 +1893,32 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
18931893

18941894
refType = fnType->getResult();
18951895

1896-
auto *keyPathExpr = buildImplicitDynamicKeyPathArgument(
1897-
locator->getAnchor(), keyPathTy, locator);
1898-
1899-
// If argument couldn't be built, let's fail this choice.
1900-
if (!keyPathExpr) {
1901-
failedConstraint = Constraint::create(*this, ConstraintKind::Bind,
1902-
boundType, refType, locator);
1903-
return;
1904-
}
1896+
auto *keyPathDecl = keyPathTy->getAnyNominal();
1897+
assert(keyPathDecl &&
1898+
(keyPathDecl == getASTContext().getKeyPathDecl() ||
1899+
keyPathDecl == getASTContext().getWritableKeyPathDecl()) &&
1900+
"parameter is supposed to be a keypath");
19051901

1906-
auto *keyPathLocator = getConstraintLocator(keyPathExpr);
1907-
auto *componentLoc = getConstraintLocator(
1908-
keyPathExpr, LocatorPathElt::getKeyPathComponent(0));
1902+
auto *keyPathLoc = getConstraintLocator(
1903+
locator, LocatorPathElt::getKeyPathDynamicMember(keyPathDecl));
19091904

19101905
auto rootTy = keyPathTy->getGenericArgs()[0];
1906+
auto leafTy = keyPathTy->getGenericArgs()[1];
1907+
19111908
// Member would either point to mutable or immutable property, we
19121909
// don't which at the moment, so let's allow its type to be l-value.
1913-
auto memberTy = createTypeVariable(componentLoc, TVO_CanBindToLValue);
1910+
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue);
19141911
// Attempt to lookup a member with a give name in the root type and
19151912
// assign result to the leaf type of the keypath.
19161913
addValueMemberConstraint(LValueType::get(rootTy), choice.getName(),
19171914
memberTy, useDC, FunctionRefKind::Unapplied,
1918-
/*outerAlternatives=*/{}, componentLoc);
1915+
/*outerAlternatives=*/{}, keyPathLoc);
19191916

1920-
auto rvalueMemberTy = createTypeVariable(keyPathLocator);
19211917
// Since member type is going to be bound to "leaf" generic parameter
19221918
// of the keypath, it has to be an r-value always, so let's add a new
1923-
// constraint to preserve that.
1924-
addConstraint(ConstraintKind::Equal, memberTy, rvalueMemberTy,
1925-
keyPathLocator);
1926-
1927-
// For a new keypath constraint which is going to check whether given
1928-
// overload is correct.
1929-
addUnsolvedConstraint(Constraint::create(*this, ConstraintKind::KeyPath,
1930-
keyPathTy, rootTy,
1931-
rvalueMemberTy, keyPathLocator));
1919+
// constraint to represent that conversion instead of loading member
1920+
// type into "leaf" directly.
1921+
addConstraint(ConstraintKind::Equal, memberTy, leafTy, keyPathLoc);
19321922
}
19331923
break;
19341924
}
@@ -1998,6 +1988,29 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
19981988
}
19991989
}
20001990

1991+
// Check whether this is overload choice found via keypath
1992+
// based dynamic member lookup. Since it's unknown upfront
1993+
// what kind of declaration lookup is going to find, let's
1994+
// double check here that given keypath is appropriate for it.
1995+
auto path = locator->getPath();
1996+
if (!path.empty() && path.back().isKeyPathDynamicMember()) {
1997+
auto *keyPath = path.back().getKeyPath();
1998+
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
1999+
// If this is an attempt to access read-only member via
2000+
// writable key path, let's fail this choice early.
2001+
//
2002+
// TODO(diagnostics): Add a new fix that is suggests to
2003+
// add `subscript(dynamicMember: WritableKeyPath<T, U>)`
2004+
// overload here, instead of failing.
2005+
if (isReadOnlyKeyPathComponent(storage) &&
2006+
keyPath == getASTContext().getWritableKeyPathDecl()) {
2007+
failedConstraint = Constraint::create(*this, ConstraintKind::Bind,
2008+
boundType, refType, locator);
2009+
return;
2010+
}
2011+
}
2012+
}
2013+
20012014
// Check whether applying this overload would result in invalid
20022015
// partial function application e.g. partial application of
20032016
// mutating method or initializer.
@@ -2601,35 +2614,3 @@ void ConstraintSystem::generateConstraints(
26012614
recordChoice(constraints, index, choices[index]);
26022615
}
26032616
}
2604-
2605-
KeyPathExpr *ConstraintSystem::buildImplicitDynamicKeyPathArgument(
2606-
Expr *member, BoundGenericType *keyPathTy, ConstraintLocator *locator) {
2607-
// Only properties are support at the moment.
2608-
auto *UDE = dyn_cast<UnresolvedDotExpr>(member);
2609-
if (!UDE)
2610-
return nullptr;
2611-
2612-
auto &ctx = getASTContext();
2613-
auto dotLoc = UDE->getDotLoc();
2614-
2615-
auto *property = new (ctx)
2616-
UnresolvedDotExpr(new (ctx) KeyPathDotExpr(dotLoc), dotLoc,
2617-
UDE->getName(), UDE->getNameLoc(), /*isImplicit=*/true);
2618-
2619-
// Now, let's create a KeyPath expression itself.
2620-
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
2621-
/*parsedRoot=*/nullptr,
2622-
/*parsedPath=*/property,
2623-
/*isImplicit=*/true);
2624-
2625-
// Let's form a single unrsolved property component this keypath is
2626-
// going to refer to.
2627-
keyPath->resolveComponents(
2628-
ctx, {KeyPathExpr::Component::forUnresolvedProperty(
2629-
property->getName(), property->getStartLoc())});
2630-
setType(keyPath, keyPathTy);
2631-
2632-
// Register newly generated argument in the constraint system.
2633-
DynamicMemberArguments.push_back({locator, keyPath});
2634-
return keyPath;
2635-
}

lib/Sema/ConstraintSystem.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,6 @@ class Solution {
613613
llvm::SmallVector<std::pair<ConstraintLocator *, ProtocolConformanceRef>, 8>
614614
Conformances;
615615

616-
/// The set of implicitly generated arguments used by keypath based
617-
/// dynamic lookup.
618-
llvm::SmallDenseMap<ConstraintLocator *, KeyPathExpr *>
619-
DynamicMemberArguments;
620-
621616
/// Simplify the given type by substituting all occurrences of
622617
/// type variables for their fixed types.
623618
Type simplifyType(Type type) const;
@@ -1081,11 +1076,6 @@ class ConstraintSystem {
10811076
SmallVector<std::pair<ConstraintLocator *, ProtocolConformanceRef>, 8>
10821077
CheckedConformances;
10831078

1084-
/// A cache that stores implicitly generated arguments for keypath based
1085-
/// dynamic lookup.
1086-
SmallVector<std::pair<ConstraintLocator *, KeyPathExpr *>, 4>
1087-
DynamicMemberArguments;
1088-
10891079
public:
10901080
/// The locators of \c Defaultable constraints whose defaults were used.
10911081
SmallVector<ConstraintLocator *, 8> DefaultedConstraints;
@@ -1553,8 +1543,6 @@ class ConstraintSystem {
15531543

15541544
unsigned numFavoredConstraints;
15551545

1556-
unsigned numDynamicMemberArguments;
1557-
15581546
/// The previous score.
15591547
Score PreviousScore;
15601548

@@ -2761,16 +2749,6 @@ class ConstraintSystem {
27612749
bool includeInaccessibleMembers);
27622750

27632751
private:
2764-
/// Build an implicit argument for keypath based dynamic lookup,
2765-
/// which consists of KeyPath expression and a single component.
2766-
///
2767-
/// \param member The member being dynamically lookuped up.
2768-
/// \param keyPathTy The type of the keypath argument.
2769-
/// \param locator The locator to be associated with new argument.
2770-
KeyPathExpr *buildImplicitDynamicKeyPathArgument(Expr *member,
2771-
BoundGenericType *keyPathTy,
2772-
ConstraintLocator *locator);
2773-
27742752
/// Attempt to simplify the given construction constraint.
27752753
///
27762754
/// \param valueType The type being constructed.

0 commit comments

Comments
 (0)