Skip to content

Commit b8bbed8

Browse files
committed
[WIP] Implement SE-0039 (Modernizing Playground Literals) (#2215)
* Implement the majority of parsing support for SE-0039. * Parse old object literals names using new syntax and provide FixIt. For example, parse "#Image(imageLiteral:...)" and provide a FixIt to change it to "#imageLiteral(resourceName:...)". Now we see something like: test.swift:4:9: error: '#Image' has been renamed to '#imageLiteral var y = #Image(imageLiteral: "image.jpg") ^~~~~~ ~~~~~~~~~~~~ #imageLiteral resourceName Handling the old syntax, and providing a FixIt for that, will be handled in a separate commit. Needs tests. Will be provided in later commit once full parsing support is done. * Add back pieces of syntax map for object literals. * Add parsing support for old object literal syntax. ... and provide fixits to new syntax. Full tests to come in later commit. * Improve parsing of invalid object literals with old syntax. * Do not include bracket in code completion results. * Remove defunct code in SyntaxModel. * Add tests for migration fixits. * Add literals to code completion overload tests. @akyrtzi told me this should be fine. * Clean up response tests not to include full paths. * Further adjust offsets. * Mark initializer for _ColorLiteralConvertible in UIKit as @nonobjc. * Put attribute in the correct place.
1 parent ca5d7bd commit b8bbed8

31 files changed

+439
-248
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ docs/_build
3939
#==============================================================================#
4040
CMakeCache.txt
4141
CMakeFiles
42+
.atom-build.json

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,12 +1046,14 @@ ERROR(expected_rsquare_array_expr,PointsToFirstBadToken,
10461046
"expected ']' in container literal expression", ())
10471047

10481048
// Object literal expressions
1049-
ERROR(expected_identifier_after_l_square_lit,none,
1050-
"expected identifier after '[#' in object literal expression", ())
1049+
ERROR(expected_object_literal_identifier,none,
1050+
"expected identifier after '#' in object literal expression", ())
10511051
ERROR(expected_arg_list_in_object_literal,none,
10521052
"expected argument list in object literal", ())
1053-
ERROR(expected_r_square_lit_after_object_literal,none,
1054-
"expected '#]' at end of object literal expression", ())
1053+
ERROR(object_literal_legacy_name,none,
1054+
"'%0' has been renamed to '%1", (StringRef, StringRef))
1055+
ERROR(legacy_object_literal_syntax,none,
1056+
"object literal syntax no longer uses '[# ... #]'", ())
10551057

10561058
// If expressions
10571059
ERROR(expected_expr_after_if_question,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,8 @@ ERROR(pattern_used_in_type,none,
514514
NOTE(note_module_as_type,none,
515515
"cannot use module %0 as a type", (Identifier))
516516

517-
ERROR(use_unknown_object_literal,none,
518-
"use of unknown object literal name %0", (Identifier))
517+
ERROR(use_unknown_object_literal_protocol,none,
518+
"cannot deduce protocol for %0 literal", (StringRef))
519519
ERROR(object_literal_default_type_missing,none,
520520
"could not infer type of %0 literal", (StringRef))
521521
NOTE(object_literal_resolve_import,none,

include/swift/AST/Expr.h

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -831,36 +831,47 @@ class MagicIdentifierLiteralExpr : public LiteralExpr {
831831
};
832832

833833
// ObjectLiteralExpr - An expression of the form
834-
// '[#Color(red: 1, blue: 0, green: 0, alpha: 1)#]' with a name and a list
834+
// '#colorLiteral(red: 1, blue: 0, green: 0, alpha: 1)' with a name and a list
835835
// argument. The components of the list argument are meant to be themselves
836836
// constant.
837837
class ObjectLiteralExpr : public LiteralExpr {
838-
Identifier Name;
838+
public:
839+
/// The kind of object literal.
840+
enum LiteralKind : unsigned {
841+
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) Name,
842+
#include "swift/Parse/Tokens.def"
843+
};
844+
845+
private:
846+
LiteralKind LitKind;
839847
Expr *Arg;
840848
Expr *SemanticExpr;
841-
842-
SourceLoc LLitLoc;
843-
SourceLoc NameLoc;
844-
SourceLoc RLitLoc;
849+
SourceLoc PoundLoc;
845850

846851
public:
847-
ObjectLiteralExpr(SourceLoc LLitLoc, Identifier Name, SourceLoc NameLoc,
848-
Expr *Arg, SourceLoc RLitLoc, bool implicit = false)
852+
ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind,
853+
Expr *Arg, bool implicit = false)
849854
: LiteralExpr(ExprKind::ObjectLiteral, implicit),
850-
Name(Name), Arg(Arg), SemanticExpr(nullptr),
851-
LLitLoc(LLitLoc), NameLoc(NameLoc), RLitLoc(RLitLoc) {}
855+
LitKind(LitKind), Arg(Arg), SemanticExpr(nullptr),
856+
PoundLoc(PoundLoc) {}
852857

853-
Identifier getName() const { return Name; }
854-
SourceLoc getNameLoc() const { return NameLoc; }
858+
LiteralKind getLiteralKind() const { return LitKind; }
855859

856860
Expr *getArg() const { return Arg; }
857861
void setArg(Expr *arg) { Arg = arg; }
858862

859863
Expr *getSemanticExpr() const { return SemanticExpr; }
860864
void setSemanticExpr(Expr *expr) { SemanticExpr = expr; }
861865

862-
SourceLoc getSourceLoc() const { return NameLoc; }
863-
SourceRange getSourceRange() const { return SourceRange(LLitLoc, RLitLoc); }
866+
SourceLoc getSourceLoc() const { return PoundLoc; }
867+
SourceRange getSourceRange() const {
868+
return SourceRange(PoundLoc, Arg->getEndLoc());
869+
}
870+
871+
/// Return the string form of the literal name.
872+
StringRef getLiteralKindRawName() const;
873+
874+
StringRef getLiteralKindPlainName() const;
864875

865876
static bool classof(const Expr *E) {
866877
return E->getKind() == ExprKind::ObjectLiteral;

include/swift/Parse/Parser.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1177,8 +1177,17 @@ class Parser {
11771177

11781178
Expr *parseExprAnonClosureArg();
11791179
ParserResult<Expr> parseExprList(tok LeftTok, tok RightTok);
1180+
1181+
// NOTE: used only for legacy support for old object literal syntax.
1182+
// Will be removed in the future.
11801183
bool isCollectionLiteralStartingWithLSquareLit();
1181-
ParserResult<Expr> parseExprObjectLiteral();
1184+
1185+
/// Parse an object literal.
1186+
///
1187+
/// \param LK The literal kind as determined by the first token.
1188+
/// \param NewName New name for a legacy literal.
1189+
ParserResult<Expr> parseExprObjectLiteral(ObjectLiteralExpr::LiteralKind LK,
1190+
StringRef NewName = StringRef());
11821191
ParserResult<Expr> parseExprCallSuffix(ParserResult<Expr> fn,
11831192
Identifier firstSelectorPiece
11841193
= Identifier(),

include/swift/Parse/Tokens.def

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,29 @@
3838
#define POUND_KEYWORD(kw)
3939
#endif
4040

41+
/// POUND_NORMAL_KEYWORD(kw)
42+
/// Keywords except object and config keywords in the #foo namespace.
43+
#ifndef POUND_NORMAL_KEYWORD
44+
#define POUND_NORMAL_KEYWORD(kw) POUND_KEYWORD(kw)
45+
#endif
46+
47+
/// POUND_OBJECT_LITERAL(kw, desc, proto)
48+
/// Every keyword in the #foo namespace representing an object literal.
49+
#ifndef POUND_OBJECT_LITERAL
50+
#define POUND_OBJECT_LITERAL(kw, desc, proto) POUND_KEYWORD(kw)
51+
#endif
52+
53+
/// POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg)
54+
/// Every keyword in the #foo namespace representing an object literal.
55+
#ifndef POUND_OLD_OBJECT_LITERAL
56+
#define POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg) POUND_KEYWORD(kw)
57+
#endif
58+
59+
/// POUND_CONFIG(kw)
60+
/// Every keyword in the #foo namespace representing a configuration.
61+
#ifndef POUND_CONFIG
62+
#define POUND_CONFIG(kw) POUND_KEYWORD(kw)
63+
#endif
4164

4265
/// SIL_KEYWORD(kw)
4366
/// Expands for every SIL keyword. These are only keywords when parsing SIL.
@@ -140,9 +163,6 @@ PUNCTUATOR(r_brace, "}")
140163
PUNCTUATOR(l_square, "[")
141164
PUNCTUATOR(r_square, "]")
142165

143-
PUNCTUATOR(l_square_lit, "[#")
144-
PUNCTUATOR(r_square_lit, "#]")
145-
146166
PUNCTUATOR(period, ".")
147167
PUNCTUATOR(period_prefix, ".")
148168
PUNCTUATOR(comma, ",")
@@ -165,6 +185,11 @@ PUNCTUATOR(question_infix,"?") // if not left-bound
165185
PUNCTUATOR(sil_dollar, "$") // Only in SIL mode.
166186
PUNCTUATOR(sil_exclamation, "!") // Only in SIL mode.
167187

188+
// Legacy punctuators used for migrating old object literal syntax.
189+
// NOTE: Remove in the future.
190+
PUNCTUATOR(l_square_lit, "[#")
191+
PUNCTUATOR(r_square_lit, "#]")
192+
168193
// Keywords in the # namespace. "if" becomes "tok::pound_if".
169194
POUND_KEYWORD(if)
170195
POUND_KEYWORD(else)
@@ -173,9 +198,22 @@ POUND_KEYWORD(endif)
173198
POUND_KEYWORD(line)
174199
POUND_KEYWORD(setline)
175200
POUND_KEYWORD(sourceLocation)
176-
POUND_KEYWORD(available)
177201
POUND_KEYWORD(selector)
178202

203+
// Keywords in the # namespace that are build configurations.
204+
POUND_CONFIG(available)
205+
206+
207+
// Declaratively define object literals, including their
208+
// corresponding protocols.
209+
POUND_OBJECT_LITERAL(fileLiteral, "file reference", FileReferenceLiteralConvertible)
210+
POUND_OBJECT_LITERAL(imageLiteral, "image", ImageLiteralConvertible)
211+
POUND_OBJECT_LITERAL(colorLiteral, "color", ColorLiteralConvertible)
212+
213+
POUND_OLD_OBJECT_LITERAL(FileReference, fileLiteral, fileReferenceLiteral, resourceName)
214+
POUND_OLD_OBJECT_LITERAL(Image, imageLiteral, imageLiteral, resourceName)
215+
POUND_OLD_OBJECT_LITERAL(Color, colorLiteral, colorLiteralRed, red)
216+
179217
POUND_KEYWORD(file)
180218
POUND_KEYWORD(column)
181219
POUND_KEYWORD(function)
@@ -188,3 +226,7 @@ POUND_KEYWORD(dsohandle)
188226
#undef SIL_KEYWORD
189227
#undef PUNCTUATOR
190228
#undef POUND_KEYWORD
229+
#undef POUND_NORMAL_KEYWORD
230+
#undef POUND_OBJECT_LITERAL
231+
#undef POUND_OLD_OBJECT_LITERAL
232+
#undef POUND_CONFIG

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,9 +1623,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
16231623
}
16241624

16251625
void visitObjectLiteralExpr(ObjectLiteralExpr *E) {
1626-
printCommon(E, "object_literal")
1627-
<< " name=" << E->getName();
1628-
OS << '\n';
1626+
printCommon(E, "object_literal")
1627+
<< " kind='" << E->getLiteralKindPlainName() << "'\n";
16291628
printRec(E->getArg());
16301629
}
16311630

lib/AST/Expr.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,8 @@ shallowCloneImpl(const MagicIdentifierLiteralExpr *E, ASTContext &Ctx) {
743743

744744
static LiteralExpr *
745745
shallowCloneImpl(const ObjectLiteralExpr *E, ASTContext &Ctx) {
746-
auto res = new (Ctx) ObjectLiteralExpr(E->getStartLoc(), E->getName(),
747-
E->getNameLoc(), E->getArg(),
748-
E->getEndLoc());
746+
auto res = new (Ctx) ObjectLiteralExpr(E->getStartLoc(), E->getLiteralKind(),
747+
E->getArg());
749748
res->setSemanticExpr(E->getSemanticExpr());
750749
return res;
751750
}
@@ -846,6 +845,22 @@ StringLiteralExpr::StringLiteralExpr(StringRef Val, SourceRange Range,
846845
unicode::isSingleExtendedGraphemeCluster(Val);
847846
}
848847

848+
StringRef ObjectLiteralExpr::getLiteralKindRawName() const {
849+
switch (LitKind) {
850+
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) case Name: return #Name;
851+
#include "swift/Parse/Tokens.def"
852+
}
853+
llvm_unreachable("unspecified literal");
854+
}
855+
856+
StringRef ObjectLiteralExpr::getLiteralKindPlainName() const {
857+
switch (LitKind) {
858+
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) case Name: return Desc;
859+
#include "swift/Parse/Tokens.def"
860+
}
861+
llvm_unreachable("unspecified literal");
862+
}
863+
849864
void DeclRefExpr::setSpecialized() {
850865
if (isSpecialized())
851866
return;

lib/IDE/CodeCompletion.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,10 +3228,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32283228

32293229
auto floatType = context.getFloatDecl()->getDeclaredType();
32303230
addFromProto(LK::ColorLiteral, "", [&](Builder &builder) {
3231-
builder.addLeftBracket();
3232-
builder.addTextChunk("#Color");
3231+
builder.addTextChunk("#colorLiteral");
32333232
builder.addLeftParen();
3234-
builder.addCallParameter(context.getIdentifier("colorLiteralRed"),
3233+
builder.addCallParameter(context.getIdentifier("red"),
32353234
floatType, false, true);
32363235
builder.addComma();
32373236
builder.addCallParameter(context.getIdentifier("green"), floatType,
@@ -3243,20 +3242,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32433242
builder.addCallParameter(context.getIdentifier("alpha"), floatType,
32443243
false, true);
32453244
builder.addRightParen();
3246-
builder.addTextChunk("#");
3247-
builder.addRightBracket();
32483245
});
32493246

32503247
auto stringType = context.getStringDecl()->getDeclaredType();
32513248
addFromProto(LK::ImageLiteral, "", [&](Builder &builder) {
3252-
builder.addLeftBracket();
3253-
builder.addTextChunk("#Image");
3249+
builder.addTextChunk("#imageLiteral");
32543250
builder.addLeftParen();
3255-
builder.addCallParameter(context.getIdentifier("imageLiteral"),
3251+
builder.addCallParameter(context.getIdentifier("resourceName"),
32563252
stringType, false, true);
32573253
builder.addRightParen();
3258-
builder.addTextChunk("#");
3259-
builder.addRightBracket();
32603254
});
32613255

32623256
// Add tuple completion (item, item).

lib/IDE/SyntaxModel.cpp

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
8484
Length = Tok.getLength();
8585

8686
if (LiteralStartLoc.hasValue() && Length.hasValue()) {
87-
// We are still inside an object literal until we hit a r_square_lit.
88-
if (Tok.getKind() != tok::r_square_lit) {
89-
continue;
90-
}
9187
Kind = SyntaxNodeKind::ObjectLiteral;
9288
Nodes.emplace_back(Kind, CharSourceRange(SM, LiteralStartLoc.getValue(),
9389
Tok.getRange().getEnd()));
@@ -99,20 +95,23 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
9995
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
10096
#include "swift/Parse/Tokens.def"
10197
#undef KEYWORD
102-
case tok::pound_selector:
103-
case tok::pound_file:
104-
case tok::pound_column:
105-
case tok::pound_function:
106-
case tok::pound_dsohandle:
98+
99+
#define POUND_NORMAL_KEYWORD(Name) case tok::pound_##Name:
100+
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) case tok::pound_##Name:
101+
#define POUND_OLD_OBJECT_LITERAL(Name, NewName, OldArg, NewArg) case tok::pound_##Name:
102+
#include "swift/Parse/Tokens.def"
107103
Kind = SyntaxNodeKind::Keyword;
108104
break;
105+
106+
#define POUND_CONFIG(Name) case tok::pound_##Name:
107+
#include "swift/Parse/Tokens.def"
108+
Kind = SyntaxNodeKind::BuildConfigKeyword;
109+
break;
110+
109111
case tok::pound_line:
110112
Kind = Tok.isAtStartOfLine() ? SyntaxNodeKind::BuildConfigKeyword :
111113
SyntaxNodeKind::Keyword;
112114
break;
113-
case tok::pound_available:
114-
Kind = SyntaxNodeKind::BuildConfigKeyword;
115-
break;
116115
case tok::identifier:
117116
if (Tok.getText().startswith("<#"))
118117
Kind = SyntaxNodeKind::EditorPlaceholder;
@@ -189,11 +188,6 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
189188
break;
190189
}
191190

192-
case tok::l_square_lit: {
193-
LiteralStartLoc = Loc;
194-
continue;
195-
}
196-
197191
default:
198192
continue;
199193
}
@@ -490,11 +484,13 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
490484
} else if (auto *ObjectE = dyn_cast<ObjectLiteralExpr>(E)) {
491485
SyntaxStructureNode SN;
492486
SN.Kind = SyntaxStructureKind::ObjectLiteralExpression;
493-
SN.Range = charSourceRangeFromSourceRange(SM, E->getSourceRange());
494-
SourceLoc NRStart = ObjectE->getNameLoc();
495-
SourceLoc NREnd = NRStart.getAdvancedLoc(ObjectE->getName().getLength());
487+
SN.Range = charSourceRangeFromSourceRange(SM, ObjectE->getSourceRange());
488+
SourceLoc NRStart = ObjectE->getSourceLoc().getAdvancedLoc(1);
489+
SourceLoc NREnd =
490+
NRStart.getAdvancedLoc(ObjectE->getLiteralKindRawName().size());
496491
SN.NameRange = CharSourceRange(SM, NRStart, NREnd);
497-
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, E->getSourceRange());
492+
SN.BodyRange =
493+
innerCharSourceRangeFromSourceRange(SM, ObjectE->getSourceRange());
498494
pushStructureNode(SN, E);
499495

500496
} else if (auto *ArrayE = dyn_cast<ArrayExpr>(E)) {

lib/Parse/Lexer.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -578,9 +578,11 @@ void Lexer::lexIdentifier() {
578578
/// lexHash - Handle #], #! for shebangs, and the family of #identifiers.
579579
void Lexer::lexHash() {
580580
const char *TokStart = CurPtr-1;
581+
582+
// NOTE: legacy punctuator. Remove in the future.
581583
if (*CurPtr == ']') { // #]
582-
CurPtr++;
583-
return formToken(tok::r_square_lit, TokStart);
584+
CurPtr++;
585+
return formToken(tok::r_square_lit, TokStart);
584586
}
585587

586588
// Allow a hashbang #! line at the beginning of the file.
@@ -1620,11 +1622,16 @@ void Lexer::lexImpl() {
16201622
case '@': return formToken(tok::at_sign, TokStart);
16211623
case '{': return formToken(tok::l_brace, TokStart);
16221624
case '[': {
1623-
if (*CurPtr == '#') { // [#
1624-
CurPtr++;
1625-
return formToken(tok::l_square_lit, TokStart);
1626-
}
1627-
return formToken(tok::l_square, TokStart);
1625+
// NOTE: Legacy punctuator for old object literal syntax.
1626+
// Remove in the future.
1627+
if (*CurPtr == '#') { // [#
1628+
// NOTE: Do NOT include the '#' in the token, unlike in earlier
1629+
// versions of Swift that supported the old object literal syntax
1630+
// directly. The '#' will be lexed as part of the object literal
1631+
// keyword token itself.
1632+
return formToken(tok::l_square_lit, TokStart);
1633+
}
1634+
return formToken(tok::l_square, TokStart);
16281635
}
16291636
case '(': return formToken(tok::l_paren, TokStart);
16301637
case '}': return formToken(tok::r_brace, TokStart);

0 commit comments

Comments
 (0)