Skip to content

Commit 5358c11

Browse files
rxweiCodaFi
authored andcommitted
[SE-0096] [Parse] Implement type(of:) expression
1 parent 773d521 commit 5358c11

File tree

4 files changed

+91
-2
lines changed

4 files changed

+91
-2
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,18 @@ ERROR(expr_selector_expected_property_expr,PointsToFirstBadToken,
11051105
ERROR(expr_selector_expected_rparen,PointsToFirstBadToken,
11061106
"expected ')' to complete '#selector' expression", ())
11071107

1108+
// Type-of expressions.
1109+
ERROR(expr_typeof_expected_lparen,PointsToFirstBadToken,
1110+
"expected '(' following 'type'", ())
1111+
ERROR(expr_typeof_expected_label_of,PointsToFirstBadToken,
1112+
"expected argument label 'of:' within 'type(...)'", ())
1113+
ERROR(expr_typeof_expected_expr,PointsToFirstBadToken,
1114+
"expected an expression within 'type(of: ...)'", ())
1115+
ERROR(expr_typeof_expected_rparen,PointsToFirstBadToken,
1116+
"expected ')' to complete 'type(of: ...)' expression", ())
1117+
WARNING(expr_dynamictype_deprecated,PointsToFirstBadToken,
1118+
"'.dynamicType' is deprecated. Use 'type(of: ...)' instead", ())
1119+
11081120
//------------------------------------------------------------------------------
11091121
// Attribute-parsing diagnostics
11101122
//------------------------------------------------------------------------------

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ ERROR(did_not_call_method,none,
691691
(Identifier))
692692

693693
ERROR(init_not_instance_member,none,
694-
"'init' is a member of the type; insert '.dynamicType' to initialize "
694+
"'init' is a member of the type; use 'type(of: ...)' to initialize "
695695
"a new object of the same dynamic type", ())
696696
ERROR(super_initializer_not_in_initializer,none,
697697
"'super.init' cannot be called outside of an initializer", ())

include/swift/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,7 @@ class Parser {
11181118
ParserResult<Expr> parseExprSuper(bool isExprBasic);
11191119
ParserResult<Expr> parseExprConfiguration();
11201120
ParserResult<Expr> parseExprStringLiteral();
1121+
ParserResult<Expr> parseExprTypeOf();
11211122

11221123
/// If the token is an escaped identifier being used as an argument
11231124
/// label, but doesn't need to be, diagnose it.

lib/Parse/ParseExpr.cpp

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,12 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
10951095
}
10961096

10971097
case tok::identifier: // foo
1098+
// If starts with 'type(', parse the 'type(of: ...)' metatype expression
1099+
if (Tok.getText() == "type" && peekToken().is(tok::l_paren)) {
1100+
Result = parseExprTypeOf();
1101+
break;
1102+
}
1103+
10981104
// If we are parsing a refutable pattern and are inside a let/var pattern,
10991105
// the identifiers change to be value bindings instead of decl references.
11001106
// Parse and return this as an UnresolvedPatternExpr around a binding. This
@@ -1413,12 +1419,22 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
14131419
}
14141420

14151421
// Handle "x.dynamicType" - A metatype expr.
1422+
// Deprecated in SE-0096: `x.dynamicType` becomes `type(of: x)`
14161423
if (Tok.is(tok::kw_dynamicType)) {
1424+
// Fix-it
1425+
auto range = Result.get()->getSourceRange();
1426+
auto dynamicTypeExprRange = SourceRange(TokLoc, consumeToken());
1427+
diagnose(TokLoc, diag::expr_dynamictype_deprecated)
1428+
.highlight(dynamicTypeExprRange)
1429+
.fixItReplace(dynamicTypeExprRange, ")")
1430+
.fixItInsert(range.Start, "type(of: ");
1431+
14171432
Result = makeParserResult(
1418-
new (Context) DynamicTypeExpr(Result.get(), consumeToken(), Type()));
1433+
new (Context) DynamicTypeExpr(Result.get(), dynamicTypeExprRange.End, Type()));
14191434
continue;
14201435
}
14211436

1437+
14221438
// Handle "x.self" expr.
14231439
if (Tok.is(tok::kw_self)) {
14241440
Result = makeParserResult(
@@ -2995,3 +3011,63 @@ Parser::parseVersionConstraintSpec() {
29953011
return makeParserResult(new (Context) VersionConstraintAvailabilitySpec(
29963012
Platform.getValue(), PlatformLoc, Version, VersionRange));
29973013
}
3014+
3015+
/// parseExprTypeOf
3016+
///
3017+
/// expr-dynamictype:
3018+
/// 'type' '(' 'of:' expr ')'
3019+
///
3020+
ParserResult<Expr> Parser::parseExprTypeOf() {
3021+
3022+
assert(Tok.getText() == "type" && "only 'type' should be handled here");
3023+
3024+
// Consume 'type'
3025+
SourceLoc keywordLoc = consumeToken();
3026+
// Consume '('
3027+
SourceLoc lParenLoc = consumeToken(tok::l_paren);
3028+
3029+
// Parse `of` label
3030+
// If we see a potential argument label followed by a ':', consume
3031+
// it.
3032+
if (Tok.canBeArgumentLabel() && Tok.getText() == "of" && peekToken().is(tok::colon)) {
3033+
consumeToken();
3034+
consumeToken(tok::colon);
3035+
} else {
3036+
diagnose(Tok, diag::expr_typeof_expected_label_of);
3037+
return makeParserError();
3038+
}
3039+
3040+
// Parse the subexpression.
3041+
ParserResult<Expr> subExpr = parseExpr(diag::expr_typeof_expected_expr);
3042+
if (subExpr.hasCodeCompletion())
3043+
return makeParserCodeCompletionResult<Expr>();
3044+
3045+
// Parse the closing ')'
3046+
SourceLoc rParenLoc;
3047+
if (subExpr.isParseError()) {
3048+
skipUntilDeclStmtRBrace(tok::r_paren);
3049+
if (Tok.is(tok::r_paren))
3050+
rParenLoc = consumeToken();
3051+
else
3052+
rParenLoc = Tok.getLoc();
3053+
} else {
3054+
parseMatchingToken(tok::r_paren, rParenLoc,
3055+
diag::expr_typeof_expected_rparen, lParenLoc);
3056+
}
3057+
3058+
// If the subexpression was in error, just propagate the error.
3059+
if (subExpr.isParseError()) {
3060+
if (subExpr.hasCodeCompletion()) {
3061+
auto res = makeParserResult(
3062+
new (Context) DynamicTypeExpr(subExpr.get(), consumeToken(), Type()));
3063+
res.setHasCodeCompletion();
3064+
return res;
3065+
} else {
3066+
return makeParserResult<Expr>(
3067+
new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc)));
3068+
}
3069+
}
3070+
3071+
return makeParserResult(
3072+
new (Context) DynamicTypeExpr(subExpr.get(), rParenLoc, Type()));
3073+
}

0 commit comments

Comments
 (0)