Skip to content

Commit d6ac93e

Browse files
committedNov 15, 2021
[CS] Don't set parsed paths for dynamic member key paths
The logic here could form AST loops due to passing in `anchor` for the key path's parsed path. However setting a parsed path here seems to be a holdover from the CSDiag days, so set the path to `nullptr` and rip out and the rest of the synthesis and SanitizeExpr logic for it. rdar://85236369
1 parent 15098e2 commit d6ac93e

File tree

3 files changed

+64
-109
lines changed

3 files changed

+64
-109
lines changed
 

Diff for: ‎lib/Sema/CSApply.cpp

+36-79
Original file line numberDiff line numberDiff line change
@@ -2218,23 +2218,31 @@ namespace {
22182218
Expr *buildKeyPathDynamicMemberArgExpr(BoundGenericType *keyPathTy,
22192219
SourceLoc dotLoc,
22202220
ConstraintLocator *memberLoc) {
2221+
using Component = KeyPathExpr::Component;
22212222
auto &ctx = cs.getASTContext();
22222223
auto *anchor = getAsExpr(memberLoc->getAnchor());
22232224

2224-
SmallVector<KeyPathExpr::Component, 2> components;
2225-
2226-
// Let's create a KeyPath expression and fill in "parsed path"
2227-
// after component is built.
2228-
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
2229-
/*parsedRoot=*/nullptr,
2230-
/*parsedPath=*/anchor,
2231-
/*hasLeadingDot=*/false,
2232-
/*isImplicit=*/true);
2233-
// Type of the keypath expression we are forming is known
2234-
// in advance, so let's set it right away.
2235-
keyPath->setType(keyPathTy);
2236-
cs.cacheType(keyPath);
2225+
auto makeKeyPath = [&](ArrayRef<Component> components) -> Expr * {
2226+
// Create a new implicit key path. We pass in anchor as the parsed path
2227+
// to set the end loc, but don't want to keep it as the parsed path,
2228+
// so clear it out after.
2229+
auto *kp = new (ctx) KeyPathExpr(/*backslashLoc*/ dotLoc,
2230+
/*parsedRoot*/ nullptr,
2231+
/*parsedPath*/ anchor,
2232+
/*hasLeadingDot*/ false,
2233+
/*isImplicit*/ true);
2234+
kp->setParsedPath(nullptr);
2235+
kp->setComponents(ctx, components);
2236+
kp->setType(keyPathTy);
2237+
cs.cacheExprTypes(kp);
2238+
2239+
// See whether there's an equivalent ObjC key path string we can produce
2240+
// for interop purposes.
2241+
checkAndSetObjCKeyPathString(kp);
2242+
return kp;
2243+
};
22372244

2245+
SmallVector<Component, 2> components;
22382246
auto *componentLoc = cs.getConstraintLocator(
22392247
memberLoc,
22402248
LocatorPathElt::KeyPathDynamicMember(keyPathTy->getAnyNominal()));
@@ -2247,95 +2255,44 @@ namespace {
22472255
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
22482256
buildKeyPathSubscriptComponent(overload, dotLoc, /*args=*/nullptr,
22492257
componentLoc, components);
2250-
keyPath->setComponents(ctx, components);
2251-
cs.cacheExprTypes(keyPath);
2252-
return keyPath;
2258+
return makeKeyPath(components);
22532259
}
22542260

22552261
default:
22562262
break;
22572263
}
22582264

2259-
// We can't reuse existing expression because type-check
2260-
// based diagnostics could hold the reference to original AST.
2261-
Expr *componentExpr = nullptr;
2262-
auto *dotExpr = new (ctx) KeyPathDotExpr(dotLoc);
2263-
2264-
// Determines whether this index is built to be used for
2265-
// one of the existing keypath components e.g. `\Lens<[Int]>.count`
2266-
// instead of a regular expression e.g. `lens[0]`.
2267-
bool forKeyPathComponent = false;
2268-
// Looks like keypath dynamic member lookup was used inside
2269-
// of a keypath expression e.g. `\Lens<[Int]>.count` where
2270-
// `count` is referenced using dynamic lookup.
22712265
if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
2266+
// Looks like keypath dynamic member lookup was used inside
2267+
// of a keypath expression e.g. `\Lens<[Int]>.count` where
2268+
// `count` is referenced using dynamic lookup.
22722269
auto kpElt = memberLoc->findFirst<LocatorPathElt::KeyPathComponent>();
22732270
assert(kpElt && "no keypath component node");
2274-
auto &origComponent = KPE->getComponents()[kpElt->getIndex()];
2275-
2276-
using ComponentKind = KeyPathExpr::Component::Kind;
2277-
if (origComponent.getKind() == ComponentKind::UnresolvedProperty) {
2278-
anchor = new (ctx) UnresolvedDotExpr(
2279-
dotExpr, dotLoc, origComponent.getUnresolvedDeclName(),
2280-
DeclNameLoc(origComponent.getLoc()),
2281-
/*Implicit=*/true);
2282-
} else if (origComponent.getKind() ==
2283-
ComponentKind::UnresolvedSubscript) {
2284-
anchor = SubscriptExpr::create(
2285-
ctx, dotExpr, origComponent.getSubscriptArgs(), ConcreteDeclRef(),
2286-
/*implicit=*/true, AccessSemantics::Ordinary);
2271+
auto &comp = KPE->getComponents()[kpElt->getIndex()];
2272+
2273+
if (comp.getKind() == Component::Kind::UnresolvedProperty) {
2274+
buildKeyPathPropertyComponent(overload, comp.getLoc(), componentLoc,
2275+
components);
2276+
} else if (comp.getKind() == Component::Kind::UnresolvedSubscript) {
2277+
buildKeyPathSubscriptComponent(overload, comp.getLoc(),
2278+
comp.getSubscriptArgs(), componentLoc,
2279+
components);
22872280
} else {
22882281
return nullptr;
22892282
}
2290-
2291-
anchor->setType(simplifyType(overload.openedType));
2292-
cs.cacheType(anchor);
2293-
forKeyPathComponent = true;
2283+
return makeKeyPath(components);
22942284
}
22952285

22962286
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
2297-
componentExpr =
2298-
forKeyPathComponent
2299-
? UDE
2300-
: new (ctx) UnresolvedDotExpr(dotExpr, dotLoc, UDE->getName(),
2301-
UDE->getNameLoc(),
2302-
/*Implicit=*/true);
2303-
23042287
buildKeyPathPropertyComponent(overload, UDE->getLoc(), componentLoc,
23052288
components);
23062289
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
2307-
componentExpr = SE;
2308-
// If this is not for a keypath component, we have to copy
2309-
// original subscript expression because expression based
2310-
// diagnostics might have a reference to it, so it couldn't
2311-
// be modified.
2312-
if (!forKeyPathComponent) {
2313-
componentExpr = SubscriptExpr::create(
2314-
ctx, dotExpr, SE->getArgs(),
2315-
SE->hasDecl() ? SE->getDecl() : ConcreteDeclRef(),
2316-
/*implicit=*/true, SE->getAccessSemantics());
2317-
}
2318-
23192290
buildKeyPathSubscriptComponent(overload, SE->getLoc(), SE->getArgs(),
23202291
componentLoc, components);
23212292
} else {
23222293
return nullptr;
23232294
}
2324-
2325-
assert(componentExpr);
2326-
Type ty = simplifyType(cs.getType(anchor));
2327-
componentExpr->setType(ty);
2328-
cs.cacheType(componentExpr);
2329-
2330-
keyPath->setParsedPath(componentExpr);
2331-
keyPath->setComponents(ctx, components);
2332-
cs.cacheExprTypes(keyPath);
2333-
2334-
// See whether there's an equivalent ObjC key path string we can produce
2335-
// for interop purposes.
2336-
checkAndSetObjCKeyPathString(keyPath);
2337-
2338-
return keyPath;
2295+
return makeKeyPath(components);
23392296
}
23402297

23412298
/// Bridge the given value (which is an error type) to NSError.

Diff for: ‎lib/Sema/TypeCheckCodeCompletion.cpp

-30
Original file line numberDiff line numberDiff line change
@@ -203,36 +203,6 @@ class SanitizeExpr : public ASTWalker {
203203
EPE->setSemanticExpr(nullptr);
204204
}
205205

206-
// If this expression represents keypath based dynamic member
207-
// lookup, let's convert it back to the original form of
208-
// member or subscript reference.
209-
if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
210-
auto *args = SE->getArgs();
211-
auto isImplicitKeyPathExpr = [](Expr *argExpr) -> bool {
212-
if (auto *KP = dyn_cast<KeyPathExpr>(argExpr))
213-
return KP->isImplicit();
214-
return false;
215-
};
216-
217-
if (SE->isImplicit() && args->isUnary() &&
218-
args->front().getLabel() == C.Id_dynamicMember &&
219-
isImplicitKeyPathExpr(args->front().getExpr())) {
220-
auto *keyPathExpr = cast<KeyPathExpr>(args->front().getExpr());
221-
auto *componentExpr = keyPathExpr->getParsedPath();
222-
223-
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(componentExpr)) {
224-
UDE->setBase(SE->getBase());
225-
return {true, UDE};
226-
}
227-
228-
if (auto *subscript = dyn_cast<SubscriptExpr>(componentExpr)) {
229-
subscript->setBase(SE->getBase());
230-
return {true, subscript};
231-
}
232-
llvm_unreachable("unknown keypath component type");
233-
}
234-
}
235-
236206
// If this is a closure, only walk into its children if they
237207
// are type-checked in the context of the enclosing expression.
238208
if (auto closure = dyn_cast<ClosureExpr>(expr)) {

Diff for: ‎test/expr/unary/keypath/rdar85236369.swift

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-swift-frontend -dump-ast %s | %FileCheck %s
2+
3+
struct Q {
4+
var x: Int
5+
}
6+
7+
@dynamicMemberLookup
8+
struct R {
9+
subscript(dynamicMember dynamicMember: KeyPath<Q, Int>) -> Int {
10+
fatalError()
11+
}
12+
}
13+
14+
@dynamicMemberLookup
15+
struct S {
16+
subscript(dynamicMember dynamicMember: KeyPath<R, Int>) -> Int {
17+
fatalError()
18+
}
19+
}
20+
21+
// rdar://85236369 - We shouldn't synthesize a parsed root or path, we should
22+
// just have the original parsed root.
23+
24+
// CHECK-NOT: (parsed_root
25+
// CHECK-NOT: (parsed_path
26+
// CHECK: (parsed_root
27+
// CHECK-NOT: (parsed_path
28+
_ = \S.x

0 commit comments

Comments
 (0)