Skip to content

Commit 3accb65

Browse files
committed
[AST] Track whether key path expression has a leading dot
This is going to be useful to detect whether contextual root is really expected during key path resolution in Sema.
1 parent 5d8d8da commit 3accb65

File tree

4 files changed

+20
-13
lines changed

4 files changed

+20
-13
lines changed

include/swift/AST/Expr.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5035,6 +5035,10 @@ class KeyPathExpr : public Expr {
50355035
// The processed/resolved type, like Foo.Bar in \Foo.Bar.?.baz.
50365036
TypeRepr *RootType = nullptr;
50375037

5038+
/// Determines whether a key path starts with '.' which denotes necessity for
5039+
/// a contextual root type.
5040+
bool HasLeadingDot = false;
5041+
50385042
public:
50395043
/// A single stored component, which will be one of:
50405044
/// - an unresolved DeclNameRef, which has to be type-checked
@@ -5396,10 +5400,11 @@ class KeyPathExpr : public Expr {
53965400
bool isImplicit = false);
53975401

53985402
KeyPathExpr(SourceLoc backslashLoc, Expr *parsedRoot, Expr *parsedPath,
5399-
bool isImplicit = false)
5403+
bool hasLeadingDot, bool isImplicit = false)
54005404
: Expr(ExprKind::KeyPath, isImplicit), StartLoc(backslashLoc),
54015405
EndLoc(parsedPath ? parsedPath->getEndLoc() : parsedRoot->getEndLoc()),
5402-
ParsedRoot(parsedRoot), ParsedPath(parsedPath) {
5406+
ParsedRoot(parsedRoot), ParsedPath(parsedPath),
5407+
HasLeadingDot(hasLeadingDot) {
54035408
assert((parsedRoot || parsedPath) &&
54045409
"keypath must have either root or path");
54055410
Bits.KeyPathExpr.IsObjC = false;
@@ -5463,6 +5468,9 @@ class KeyPathExpr : public Expr {
54635468
/// True if this is an ObjC key path expression.
54645469
bool isObjC() const { return Bits.KeyPathExpr.IsObjC; }
54655470

5471+
/// True if this key path expression has a leading dot.
5472+
bool expectsContextualRoot() const { return HasLeadingDot; }
5473+
54665474
static bool classof(const Expr *E) {
54675475
return E->getKind() == ExprKind::KeyPath;
54685476
}

lib/Parse/ParseExpr.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,8 @@ ParserResult<Expr> Parser::parseExprKeyPath() {
570570
return rootResult;
571571
}
572572

573-
if (startsWithSymbol(Tok, '.')) {
573+
bool hasLeadingDot = startsWithSymbol(Tok, '.');
574+
if (hasLeadingDot) {
574575
SyntaxParsingContext ExprContext(SyntaxContext, SyntaxContextKind::Expr);
575576

576577
auto dotLoc = Tok.getLoc();
@@ -600,8 +601,9 @@ ParserResult<Expr> Parser::parseExprKeyPath() {
600601
if (rootResult.isNull() && pathResult.isNull())
601602
return nullptr;
602603

603-
auto keypath = new (Context) KeyPathExpr(
604-
backslashLoc, rootResult.getPtrOrNull(), pathResult.getPtrOrNull());
604+
auto keypath =
605+
new (Context) KeyPathExpr(backslashLoc, rootResult.getPtrOrNull(),
606+
pathResult.getPtrOrNull(), hasLeadingDot);
605607

606608
// Handle code completion.
607609
if ((Tok.is(tok::code_complete) && !Tok.isAtStartOfLine()) ||

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,7 @@ namespace {
19641964
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
19651965
/*parsedRoot=*/nullptr,
19661966
/*parsedPath=*/anchor,
1967+
/*hasLeadingDot=*/false,
19671968
/*isImplicit=*/true);
19681969
// Type of the keypath expression we are forming is known
19691970
// in advance, so let's set it right away.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -817,19 +817,15 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
817817
propertyKeyPath = UnresolvedDotExpr::createImplicit(ctx, propertyKeyPath,
818818
enclosingSelfAccess->accessedProperty->getFullName());
819819
propertyKeyPath = new (ctx) KeyPathExpr(
820-
SourceLoc(), nullptr, propertyKeyPath);
820+
SourceLoc(), nullptr, propertyKeyPath, /*hasLeadingDot=*/true);
821821

822822
// Key path referring to the backing storage property.
823823
Expr *storageKeyPath = new (ctx) KeyPathDotExpr(SourceLoc());
824824
storageKeyPath = UnresolvedDotExpr::createImplicit(ctx, storageKeyPath,
825825
storage->getFullName());
826-
storageKeyPath = new (ctx) KeyPathExpr(
827-
SourceLoc(), nullptr, storageKeyPath);
828-
Expr *args[3] = {
829-
selfDRE,
830-
propertyKeyPath,
831-
storageKeyPath
832-
};
826+
storageKeyPath = new (ctx) KeyPathExpr(SourceLoc(), nullptr, storageKeyPath,
827+
/*hasLeadingDot=*/true);
828+
Expr *args[3] = {selfDRE, propertyKeyPath, storageKeyPath};
833829

834830
SubscriptDecl *subscriptDecl = enclosingSelfAccess->subscript;
835831
lookupExpr = SubscriptExpr::create(

0 commit comments

Comments
 (0)