[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
This commit is contained in:
Hamish Knight
2021-11-15 12:25:17 +00:00
parent 15098e22bd
commit d6ac93efb1
3 changed files with 62 additions and 107 deletions

View File

@@ -2218,23 +2218,31 @@ namespace {
Expr *buildKeyPathDynamicMemberArgExpr(BoundGenericType *keyPathTy,
SourceLoc dotLoc,
ConstraintLocator *memberLoc) {
using Component = KeyPathExpr::Component;
auto &ctx = cs.getASTContext();
auto *anchor = getAsExpr(memberLoc->getAnchor());
SmallVector<KeyPathExpr::Component, 2> components;
auto makeKeyPath = [&](ArrayRef<Component> components) -> Expr * {
// Create a new implicit key path. We pass in anchor as the parsed path
// to set the end loc, but don't want to keep it as the parsed path,
// so clear it out after.
auto *kp = new (ctx) KeyPathExpr(/*backslashLoc*/ dotLoc,
/*parsedRoot*/ nullptr,
/*parsedPath*/ anchor,
/*hasLeadingDot*/ false,
/*isImplicit*/ true);
kp->setParsedPath(nullptr);
kp->setComponents(ctx, components);
kp->setType(keyPathTy);
cs.cacheExprTypes(kp);
// Let's create a KeyPath expression and fill in "parsed path"
// after component is built.
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
/*parsedRoot=*/nullptr,
/*parsedPath=*/anchor,
/*hasLeadingDot=*/false,
/*isImplicit=*/true);
// Type of the keypath expression we are forming is known
// in advance, so let's set it right away.
keyPath->setType(keyPathTy);
cs.cacheType(keyPath);
// See whether there's an equivalent ObjC key path string we can produce
// for interop purposes.
checkAndSetObjCKeyPathString(kp);
return kp;
};
SmallVector<Component, 2> components;
auto *componentLoc = cs.getConstraintLocator(
memberLoc,
LocatorPathElt::KeyPathDynamicMember(keyPathTy->getAnyNominal()));
@@ -2247,95 +2255,44 @@ namespace {
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
buildKeyPathSubscriptComponent(overload, dotLoc, /*args=*/nullptr,
componentLoc, components);
keyPath->setComponents(ctx, components);
cs.cacheExprTypes(keyPath);
return keyPath;
return makeKeyPath(components);
}
default:
break;
}
// We can't reuse existing expression because type-check
// based diagnostics could hold the reference to original AST.
Expr *componentExpr = nullptr;
auto *dotExpr = new (ctx) KeyPathDotExpr(dotLoc);
// Determines whether this index is built to be used for
// one of the existing keypath components e.g. `\Lens<[Int]>.count`
// instead of a regular expression e.g. `lens[0]`.
bool forKeyPathComponent = false;
// Looks like keypath dynamic member lookup was used inside
// of a keypath expression e.g. `\Lens<[Int]>.count` where
// `count` is referenced using dynamic lookup.
if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
// Looks like keypath dynamic member lookup was used inside
// of a keypath expression e.g. `\Lens<[Int]>.count` where
// `count` is referenced using dynamic lookup.
auto kpElt = memberLoc->findFirst<LocatorPathElt::KeyPathComponent>();
assert(kpElt && "no keypath component node");
auto &origComponent = KPE->getComponents()[kpElt->getIndex()];
auto &comp = KPE->getComponents()[kpElt->getIndex()];
using ComponentKind = KeyPathExpr::Component::Kind;
if (origComponent.getKind() == ComponentKind::UnresolvedProperty) {
anchor = new (ctx) UnresolvedDotExpr(
dotExpr, dotLoc, origComponent.getUnresolvedDeclName(),
DeclNameLoc(origComponent.getLoc()),
/*Implicit=*/true);
} else if (origComponent.getKind() ==
ComponentKind::UnresolvedSubscript) {
anchor = SubscriptExpr::create(
ctx, dotExpr, origComponent.getSubscriptArgs(), ConcreteDeclRef(),
/*implicit=*/true, AccessSemantics::Ordinary);
if (comp.getKind() == Component::Kind::UnresolvedProperty) {
buildKeyPathPropertyComponent(overload, comp.getLoc(), componentLoc,
components);
} else if (comp.getKind() == Component::Kind::UnresolvedSubscript) {
buildKeyPathSubscriptComponent(overload, comp.getLoc(),
comp.getSubscriptArgs(), componentLoc,
components);
} else {
return nullptr;
}
anchor->setType(simplifyType(overload.openedType));
cs.cacheType(anchor);
forKeyPathComponent = true;
return makeKeyPath(components);
}
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
componentExpr =
forKeyPathComponent
? UDE
: new (ctx) UnresolvedDotExpr(dotExpr, dotLoc, UDE->getName(),
UDE->getNameLoc(),
/*Implicit=*/true);
buildKeyPathPropertyComponent(overload, UDE->getLoc(), componentLoc,
components);
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
componentExpr = SE;
// If this is not for a keypath component, we have to copy
// original subscript expression because expression based
// diagnostics might have a reference to it, so it couldn't
// be modified.
if (!forKeyPathComponent) {
componentExpr = SubscriptExpr::create(
ctx, dotExpr, SE->getArgs(),
SE->hasDecl() ? SE->getDecl() : ConcreteDeclRef(),
/*implicit=*/true, SE->getAccessSemantics());
}
buildKeyPathSubscriptComponent(overload, SE->getLoc(), SE->getArgs(),
componentLoc, components);
} else {
return nullptr;
}
assert(componentExpr);
Type ty = simplifyType(cs.getType(anchor));
componentExpr->setType(ty);
cs.cacheType(componentExpr);
keyPath->setParsedPath(componentExpr);
keyPath->setComponents(ctx, components);
cs.cacheExprTypes(keyPath);
// See whether there's an equivalent ObjC key path string we can produce
// for interop purposes.
checkAndSetObjCKeyPathString(keyPath);
return keyPath;
return makeKeyPath(components);
}
/// Bridge the given value (which is an error type) to NSError.