Skip to content

Commit 6b31126

Browse files
authored
Merge branch 'master' into separate-note-switch
2 parents fb0985b + ab9f280 commit 6b31126

30 files changed

+912
-666
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,8 @@ ERROR(expr_keypath_expected_property_or_type,PointsToFirstBadToken,
11761176
"expected property or type name within '#keyPath(...)'", ())
11771177
ERROR(expr_keypath_expected_rparen,PointsToFirstBadToken,
11781178
"expected ')' to complete '#keyPath' expression", ())
1179+
ERROR(expr_keypath_expected_expr,none,
1180+
"expected expression path in Swift key path",())
11791181

11801182
// Selector expressions.
11811183
ERROR(expr_selector_expected_lparen,PointsToFirstBadToken,

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,10 @@ ERROR(expr_unsupported_objc_key_path_compound_name,none,
441441
"compound name", ())
442442
ERROR(expr_keypath_no_keypath_type,none,
443443
"broken standard library: no 'KeyPath' type found", ())
444+
ERROR(expr_swift_keypath_invalid_component,none,
445+
"invalid component of Swift key path", ())
446+
ERROR(expr_swift_keypath_not_starting_with_type,none,
447+
"a Swift key path must begin with a type", ())
444448

445449
// Selector expressions.
446450
ERROR(expr_selector_no_objc_runtime,none,

include/swift/AST/Expr.h

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4558,12 +4558,21 @@ class ObjCSelectorExpr : public Expr {
45584558
/// #keyPath(Person.friends.firstName)
45594559
/// \endcode
45604560
class KeyPathExpr : public Expr {
4561-
SourceLoc KeywordLoc;
4561+
SourceLoc StartLoc;
45624562
SourceLoc LParenLoc;
4563-
SourceLoc RParenLoc;
4564-
TypeRepr *RootType;
4563+
SourceLoc EndLoc;
45654564
Expr *ObjCStringLiteralExpr = nullptr;
45664565

4566+
// The parsed root of a Swift keypath (the section before an unusual dot, like
4567+
// Foo.Bar in \Foo.Bar.?.baz).
4568+
Expr *ParsedRoot = nullptr;
4569+
// The parsed path of a Swift keypath (the section after an unusual dot, like
4570+
// ?.baz in \Foo.Bar.?.baz).
4571+
Expr *ParsedPath = nullptr;
4572+
4573+
// The processed/resolved type, like Foo.Bar in \Foo.Bar.?.baz.
4574+
TypeRepr *RootType = nullptr;
4575+
45674576
public:
45684577
/// A single stored component, which will be one of:
45694578
/// - an unresolved DeclName, which has to be type-checked
@@ -4772,17 +4781,23 @@ class KeyPathExpr : public Expr {
47724781
/// Create a new #keyPath expression.
47734782
KeyPathExpr(ASTContext &C,
47744783
SourceLoc keywordLoc, SourceLoc lParenLoc,
4775-
TypeRepr *root,
47764784
ArrayRef<Component> components,
47774785
SourceLoc rParenLoc,
4778-
bool isObjC,
47794786
bool isImplicit = false);
47804787

4781-
SourceLoc getLoc() const { return KeywordLoc; }
4782-
SourceRange getSourceRange() const {
4783-
return SourceRange(KeywordLoc, RParenLoc);
4788+
KeyPathExpr(SourceLoc backslashLoc, Expr *parsedRoot, Expr *parsedPath,
4789+
bool isImplicit = false)
4790+
: Expr(ExprKind::KeyPath, isImplicit), StartLoc(backslashLoc),
4791+
EndLoc(parsedPath ? parsedPath->getEndLoc() : parsedRoot->getEndLoc()),
4792+
ParsedRoot(parsedRoot), ParsedPath(parsedPath) {
4793+
assert((parsedRoot || parsedPath) &&
4794+
"keypath must have either root or path");
4795+
KeyPathExprBits.IsObjC = false;
47844796
}
47854797

4798+
SourceLoc getLoc() const { return StartLoc; }
4799+
SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); }
4800+
47864801
/// Get the components array.
47874802
ArrayRef<Component> getComponents() const {
47884803
return Components;
@@ -4807,11 +4822,34 @@ class KeyPathExpr : public Expr {
48074822
void setObjCStringLiteralExpr(Expr *expr) {
48084823
ObjCStringLiteralExpr = expr;
48094824
}
4810-
4825+
4826+
Expr *getParsedRoot() const {
4827+
assert(!isObjC() && "cannot get parsed root of ObjC keypath");
4828+
return ParsedRoot;
4829+
}
4830+
void setParsedRoot(Expr *root) {
4831+
assert(!isObjC() && "cannot get parsed root of ObjC keypath");
4832+
ParsedRoot = root;
4833+
}
4834+
4835+
Expr *getParsedPath() const {
4836+
assert(!isObjC() && "cannot get parsed path of ObjC keypath");
4837+
return ParsedPath;
4838+
}
4839+
void setParsedPath(Expr *path) {
4840+
assert(!isObjC() && "cannot set parsed path of ObjC keypath");
4841+
ParsedPath = path;
4842+
}
4843+
48114844
TypeRepr *getRootType() const {
4845+
assert(!isObjC() && "cannot get root type of ObjC keypath");
48124846
return RootType;
48134847
}
4814-
4848+
void setRootType(TypeRepr *rootType) {
4849+
assert(!isObjC() && "cannot set root type of ObjC keypath");
4850+
RootType = rootType;
4851+
}
4852+
48154853
/// True if this is an ObjC key path expression.
48164854
bool isObjC() const { return KeyPathExprBits.IsObjC; }
48174855

@@ -4820,6 +4858,22 @@ class KeyPathExpr : public Expr {
48204858
}
48214859
};
48224860

4861+
/// Represents the unusual behaviour of a . in a \ keypath expression, such as
4862+
/// \.[0] and \Foo.?.
4863+
class KeyPathDotExpr : public Expr {
4864+
SourceLoc DotLoc;
4865+
4866+
public:
4867+
KeyPathDotExpr(SourceLoc dotLoc)
4868+
: Expr(ExprKind::KeyPathDot, /*isImplicit=*/true), DotLoc(dotLoc) {}
4869+
4870+
SourceLoc getLoc() const { return DotLoc; }
4871+
SourceRange getSourceRange() const { return SourceRange(DotLoc, DotLoc); }
4872+
4873+
static bool classof(const Expr *E) {
4874+
return E->getKind() == ExprKind::KeyPathDot;
4875+
}
4876+
};
48234877

48244878
inline bool Expr::isInfixOperator() const {
48254879
return isa<BinaryExpr>(this) || isa<IfExpr>(this) ||

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ UNCHECKED_EXPR(UnresolvedPattern, Expr)
168168
EXPR(EditorPlaceholder, Expr)
169169
EXPR(ObjCSelector, Expr)
170170
EXPR(KeyPath, Expr)
171+
UNCHECKED_EXPR(KeyPathDot, Expr)
171172

172173
#undef EXPR_RANGE
173174
#undef LITERAL_EXPR

include/swift/Parse/Parser.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class Parser {
130130

131131
bool InPoundLineEnvironment = false;
132132
bool InPoundIfEnvironment = false;
133+
bool InSwiftKeyPath = false;
133134

134135
LocalContext *CurLocalContext = nullptr;
135136

@@ -517,16 +518,16 @@ class Parser {
517518
/// Add a camel-cased option if it is different than the first option.
518519
void diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc,
519520
StringRef DeclKindName);
520-
521-
/// \brief Check whether the current token starts with '<'.
522-
bool startsWithLess(Token Tok) {
523-
return Tok.isAnyOperator() && Tok.getText()[0] == '<';
521+
522+
bool startsWithSymbol(Token Tok, char symbol) {
523+
return (Tok.isAnyOperator() || Tok.isPunctuation()) &&
524+
Tok.getText()[0] == symbol;
524525
}
526+
/// \brief Check whether the current token starts with '<'.
527+
bool startsWithLess(Token Tok) { return startsWithSymbol(Tok, '<'); }
525528

526529
/// \brief Check whether the current token starts with '>'.
527-
bool startsWithGreater(Token Tok) {
528-
return Tok.isAnyOperator() && Tok.getText()[0] == '>';
529-
}
530+
bool startsWithGreater(Token Tok) { return startsWithSymbol(Tok, '>'); }
530531

531532
/// \brief Consume the starting '<' of the current token, which may either
532533
/// be a complete '<' token or some kind of operator token starting with '<',
@@ -1141,6 +1142,10 @@ class Parser {
11411142
bool isForConditionalDirective = false);
11421143
ParserResult<Expr> parseExprSequenceElement(Diag<> ID,
11431144
bool isExprBasic);
1145+
ParserResult<Expr> parseExprPostfixSuffix(ParserResult<Expr> inner,
1146+
bool isExprBasic,
1147+
bool periodHasKeyPathBehaviour,
1148+
bool &hasBindOptional);
11441149
ParserResult<Expr> parseExprPostfix(Diag<> ID, bool isExprBasic);
11451150
ParserResult<Expr> parseExprUnary(Diag<> ID, bool isExprBasic);
11461151
ParserResult<Expr> parseExprKeyPathObjC();

include/swift/Syntax/TokenKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ PUNCTUATOR(arrow, "->")
174174

175175
PUNCTUATOR(backtick, "`")
176176

177+
PUNCTUATOR(backslash, "\\")
178+
177179
PUNCTUATOR(exclaim_postfix, "!") // if left-bound
178180

179181
PUNCTUATOR(question_postfix, "?") // if left-bound
@@ -193,7 +195,6 @@ POUND_KEYWORD(else)
193195
POUND_KEYWORD(elseif)
194196
POUND_KEYWORD(endif)
195197
POUND_KEYWORD(keyPath)
196-
POUND_KEYWORD(keyPath2) // TODO
197198
POUND_KEYWORD(line)
198199
POUND_KEYWORD(sourceLocation)
199200
POUND_KEYWORD(selector)

lib/AST/ASTDumper.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,25 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
24672467
OS << '\n';
24682468
printRec(stringLiteral);
24692469
}
2470+
if (!E->isObjC()) {
2471+
OS << "\n";
2472+
if (auto root = E->getParsedRoot()) {
2473+
printRec(root);
2474+
} else {
2475+
OS.indent(Indent + 2) << "<<null>>";
2476+
}
2477+
OS << "\n";
2478+
if (auto path = E->getParsedPath()) {
2479+
printRec(path);
2480+
} else {
2481+
OS.indent(Indent + 2) << "<<null>>";
2482+
}
2483+
}
2484+
OS << ")";
2485+
}
2486+
2487+
void visitKeyPathDotExpr(KeyPathDotExpr *E) {
2488+
printCommon(E, "key_path_dot_expr");
24702489
OS << ")";
24712490
}
24722491
};

lib/AST/ASTWalker.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -915,10 +915,35 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
915915
E->setObjCStringLiteralExpr(sub);
916916
return E;
917917
}
918-
918+
919+
auto components = E->getComponents();
920+
if (components.empty()) {
921+
// No components means a parsed-only/pre-resolution Swift key path.
922+
assert(!E->isObjC());
923+
if (auto parsedRoot = E->getParsedRoot()) {
924+
Expr *newRoot = doIt(parsedRoot);
925+
if (!newRoot)
926+
return nullptr;
927+
E->setParsedRoot(newRoot);
928+
}
929+
if (auto parsedPath = E->getParsedPath()) {
930+
Expr *newPath = doIt(parsedPath);
931+
if (!newPath)
932+
return nullptr;
933+
E->setParsedPath(newPath);
934+
}
935+
return E;
936+
}
937+
938+
if (!E->isObjC()) {
939+
auto rootType = E->getRootType();
940+
if (rootType && doIt(rootType))
941+
return nullptr;
942+
}
943+
919944
SmallVector<KeyPathExpr::Component, 4> updatedComponents;
920945
bool didChangeComponents = false;
921-
for (auto &origComponent : E->getComponents()) {
946+
for (auto &origComponent : components) {
922947
auto component = origComponent;
923948
switch (auto kind = component.getKind()) {
924949
case KeyPathExpr::Component::Kind::Subscript:
@@ -955,10 +980,12 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
955980
E->resolveComponents(E->getType()->getASTContext(),
956981
updatedComponents);
957982
}
958-
983+
959984
return E;
960985
}
961986

987+
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }
988+
962989
//===--------------------------------------------------------------------===//
963990
// Everything Else
964991
//===--------------------------------------------------------------------===//

lib/AST/Expr.cpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ ConcreteDeclRef Expr::getReferencedDecl() const {
510510
NO_REFERENCE(EditorPlaceholder);
511511
NO_REFERENCE(ObjCSelector);
512512
NO_REFERENCE(KeyPath);
513+
NO_REFERENCE(KeyPathDot);
513514

514515
#undef SIMPLE_REFERENCE
515516
#undef NO_REFERENCE
@@ -796,6 +797,7 @@ bool Expr::canAppendCallParentheses() const {
796797
case ExprKind::Assign:
797798
case ExprKind::UnresolvedPattern:
798799
case ExprKind::EditorPlaceholder:
800+
case ExprKind::KeyPathDot:
799801
return false;
800802
}
801803

@@ -2003,23 +2005,17 @@ ArchetypeType *OpenExistentialExpr::getOpenedArchetype() const {
20032005
return type->castTo<ArchetypeType>();
20042006
}
20052007

2006-
KeyPathExpr::KeyPathExpr(ASTContext &C,
2007-
SourceLoc keywordLoc, SourceLoc lParenLoc,
2008-
TypeRepr *root,
2009-
ArrayRef<Component> components,
2010-
SourceLoc rParenLoc,
2011-
bool isObjC,
2012-
bool isImplicit)
2013-
: Expr(ExprKind::KeyPath, isImplicit),
2014-
KeywordLoc(keywordLoc), LParenLoc(lParenLoc), RParenLoc(rParenLoc),
2015-
RootType(root),
2016-
Components(C.AllocateUninitialized<Component>(components.size()))
2017-
{
2008+
KeyPathExpr::KeyPathExpr(ASTContext &C, SourceLoc keywordLoc,
2009+
SourceLoc lParenLoc, ArrayRef<Component> components,
2010+
SourceLoc rParenLoc, bool isImplicit)
2011+
: Expr(ExprKind::KeyPath, isImplicit), StartLoc(keywordLoc),
2012+
LParenLoc(lParenLoc), EndLoc(rParenLoc),
2013+
Components(C.AllocateUninitialized<Component>(components.size())) {
20182014
// Copy components into the AST context.
20192015
std::uninitialized_copy(components.begin(), components.end(),
20202016
Components.begin());
2021-
2022-
KeyPathExprBits.IsObjC = isObjC;
2017+
2018+
KeyPathExprBits.IsObjC = true;
20232019
}
20242020

20252021
void

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4922,7 +4922,6 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
49224922
// implementation in the standard library.
49234923
transferKnown(KnownProtocolKind::Equatable);
49244924
transferKnown(KnownProtocolKind::Hashable);
4925-
transferKnown(KnownProtocolKind::Comparable);
49264925
bool transferredObjCBridgeable =
49274926
transferKnown(KnownProtocolKind::ObjectiveCBridgeable);
49284927

0 commit comments

Comments
 (0)