Skip to content

Commit 99c27d2

Browse files
committed
[CSApply] Avoid reusing expressions for keypath dynamic member lookup components
In presence of type-check based diagnostics we can't mutate existing expressions, because diagnostics could be holding references to them directly or to expressions which point to modified ones.
1 parent 589283b commit 99c27d2

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

lib/Sema/CSApply.cpp

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,32 +1535,52 @@ namespace {
15351535
SourceLoc dotLoc,
15361536
ConstraintLocator *memberLoc) {
15371537
auto &ctx = cs.getASTContext();
1538+
auto *anchor = memberLoc->getAnchor();
15381539

15391540
KeyPathExpr::Component component;
1540-
auto *componentExpr = memberLoc->getAnchor();
15411541

1542-
simplifyExprType(componentExpr);
1543-
componentExpr->setType(cs.getType(componentExpr));
1544-
1545-
// Now, let's create a KeyPath expression itself.
1542+
// Let's create a KeyPath expression and fill in "parsed path"
1543+
// after component is built.
15461544
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
15471545
/*parsedRoot=*/nullptr,
1548-
/*parsedPath=*/componentExpr,
1546+
/*parsedPath=*/anchor,
15491547
/*isImplicit=*/true);
15501548

15511549
auto *componentLoc = cs.getConstraintLocator(
15521550
memberLoc,
15531551
LocatorPathElt::getKeyPathDynamicMember(keyPathTy->getAnyNominal()));
15541552
auto overload = solution.getOverloadChoice(componentLoc);
15551553

1556-
// Let's re-use existing expression, but switch its base
1557-
// to keypath special "dot" expression.
1558-
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(componentExpr)) {
1559-
UDE->setBase(new (ctx) KeyPathDotExpr(dotLoc));
1554+
// We can't reuse existing expression because type-check
1555+
// based diagnostics could hold the reference to original AST.
1556+
Expr *componentExpr = nullptr;
1557+
auto *dotExpr = new (ctx) KeyPathDotExpr(dotLoc);
1558+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
1559+
componentExpr = new (ctx) UnresolvedDotExpr(
1560+
dotExpr, dotLoc, UDE->getName(), UDE->getNameLoc(),
1561+
/*Implicit=*/true);
1562+
15601563
component = buildKeyPathPropertyComponent(overload, UDE->getLoc(),
15611564
componentLoc);
1562-
} else if (auto *SE = dyn_cast<SubscriptExpr>(componentExpr)) {
1563-
SE->setBase(new (ctx) KeyPathDotExpr(dotLoc));
1565+
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
1566+
SmallVector<Expr *, 4> arguments;
1567+
if (auto *TE = dyn_cast<TupleExpr>(SE->getIndex())) {
1568+
auto args = TE->getElements();
1569+
arguments.append(args.begin(), args.end());
1570+
} else {
1571+
arguments.push_back(SE->getIndex()->getSemanticsProvidingExpr());
1572+
}
1573+
1574+
Expr *trailingClosure = nullptr;
1575+
if (SE->hasTrailingClosure())
1576+
trailingClosure = arguments.pop_back_val();
1577+
1578+
componentExpr = SubscriptExpr::create(
1579+
ctx, dotExpr, SE->getStartLoc(), arguments, SE->getArgumentLabels(),
1580+
SE->getArgumentLabelLocs(), SE->getEndLoc(), trailingClosure,
1581+
SE->hasDecl() ? SE->getDecl() : ConcreteDeclRef(),
1582+
/*implicit=*/true, SE->getAccessSemantics());
1583+
15641584
component = buildKeyPathSubscriptComponent(
15651585
overload, SE->getLoc(), SE->getIndex(), SE->getArgumentLabels(),
15661586
componentLoc);
@@ -1571,6 +1591,11 @@ namespace {
15711591
return nullptr;
15721592
}
15731593

1594+
assert(componentExpr);
1595+
componentExpr->setType(simplifyType(cs.getType(anchor)));
1596+
cs.cacheType(componentExpr);
1597+
1598+
keyPath->setParsedPath(componentExpr);
15741599
keyPath->resolveComponents(ctx, {component});
15751600
keyPath->setType(keyPathTy);
15761601
cs.cacheType(keyPath);
@@ -2760,7 +2785,8 @@ namespace {
27602785
paramTy->castTo<BoundGenericType>(), dotLoc, memberLocator);
27612786
}
27622787

2763-
assert(argExpr);
2788+
if (!argExpr)
2789+
return nullptr;
27642790

27652791
// Build a tuple so that the argument has a label.
27662792
auto tupleTy =

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,3 +579,11 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>,
579579
}
580580
dict["ultimate question"] = 42
581581
}
582+
583+
func keypath_with_incorrect_return_type(_ arr: Lens<Array<Int>>) {
584+
for idx in 0..<arr.count {
585+
// expected-error@-1 {{binary operator '..<' cannot be applied to operands of type 'Int' and 'Lens<Int>'}}
586+
// expected-note@-2 {{expected an argument list of type '(Self, Self)'}}
587+
let _ = arr[idx]
588+
}
589+
}

0 commit comments

Comments
 (0)