Skip to content

Commit 9c83e72

Browse files
committed
Fixup diagnostics around type(of:) and dynamicType handling
Be laxer about the parsing for type(of:) so as not to get in the way of other declarations that may use ‘type’ as their base name.
1 parent 4e5665a commit 9c83e72

File tree

6 files changed

+75
-25
lines changed

6 files changed

+75
-25
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,8 @@ ERROR(expr_typeof_expected_expr,PointsToFirstBadToken,
11141114
"expected an expression within 'type(of: ...)'", ())
11151115
ERROR(expr_typeof_expected_rparen,PointsToFirstBadToken,
11161116
"expected ')' to complete 'type(of: ...)' expression", ())
1117+
ERROR(expr_dynamictype_deprecated,PointsToFirstBadToken,
1118+
"'.dynamicType' is deprecated. Use 'type(of: ...)' instead", ())
11171119

11181120
//------------------------------------------------------------------------------
11191121
// Attribute-parsing diagnostics

lib/Basic/StringExtras.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ bool swift::canBeArgumentLabel(StringRef identifier) {
3636

3737
bool swift::canBeMemberName(StringRef identifier) {
3838
return llvm::StringSwitch<bool>(identifier)
39-
.Case("dynamicType", false)
4039
.Case("init", false)
4140
.Case("Protocol", false)
4241
.Case("self", false)

lib/Parse/ParseExpr.cpp

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,30 @@ getMagicIdentifierLiteralKind(tok Kind) {
950950
}
951951
}
952952

953+
/// See if type(of: <expr>) can be parsed backtracking on failure.
954+
static bool canParseTypeOf(Parser &P) {
955+
if (!(P.Tok.getText() == "type" && P.peekToken().is(tok::l_paren))) {
956+
return false;
957+
}
958+
// Look ahead to parse the parenthesized expression.
959+
Parser::BacktrackingScope Backtrack(P);
960+
P.consumeToken(tok::identifier);
961+
P.consumeToken(tok::l_paren);
962+
// The first argument label must be 'of'.
963+
if (!(P.Tok.getText() == "of" && P.peekToken().is(tok::colon))) {
964+
return false;
965+
}
966+
967+
// Parse to the closing paren.
968+
while (!P.Tok.is(tok::r_paren) && !P.Tok.is(tok::eof)) {
969+
// Anything that looks like another argument label is bogus.
970+
if (P.Tok.is(tok::comma) && P.peekToken().canBeArgumentLabel()) {
971+
return false;
972+
}
973+
P.skipSingle();
974+
}
975+
return true;
976+
}
953977

954978
/// parseExprPostfix
955979
///
@@ -1095,8 +1119,8 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
10951119
}
10961120

10971121
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)) {
1122+
// Attempt to parse for 'type(of: <expr>)'.
1123+
if (canParseTypeOf(*this)) {
11001124
Result = parseExprTypeOf();
11011125
break;
11021126
}
@@ -1424,6 +1448,17 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
14241448
new (Context) DotSelfExpr(Result.get(), TokLoc, consumeToken()));
14251449
continue;
14261450
}
1451+
1452+
// Handle the deprecated 'x.dynamicType' and migrate it to `type(of: x)`
1453+
if (Tok.getText() == "dynamicType") {
1454+
auto range = Result.get()->getSourceRange();
1455+
auto dynamicTypeExprRange = SourceRange(TokLoc, consumeToken());
1456+
diagnose(TokLoc, diag::expr_dynamictype_deprecated)
1457+
.highlight(dynamicTypeExprRange)
1458+
.fixItReplace(dynamicTypeExprRange, ")")
1459+
.fixItInsert(range.Start, "type(of: ");
1460+
continue;
1461+
}
14271462

14281463
// If we have '.<keyword><code_complete>', try to recover by creating
14291464
// an identifier with the same spelling as the keyword.
@@ -3007,26 +3042,14 @@ ParserResult<Expr> Parser::parseExprTypeOf() {
30073042
SourceLoc lParenLoc = consumeToken(tok::l_paren);
30083043

30093044
// Parse `of` label.
3010-
auto ofRange = Tok.getRange();
3011-
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
3012-
bool hasOf = Tok.getText() == "of";
3013-
if (!hasOf) {
3014-
// User mis-spelled the 'of' label.
3015-
diagnose(Tok, diag::expr_typeof_expected_label_of)
3016-
.fixItReplace({ ofRange.getStart(), ofRange.getEnd() }, "of");
3017-
}
3018-
3019-
// Consume either 'of' or the misspelling.
3045+
if (Tok.getText() == "of" && peekToken().is(tok::colon)) {
3046+
// Consume the label.
30203047
consumeToken();
30213048
consumeToken(tok::colon);
3022-
3023-
if (!hasOf) {
3024-
return makeParserError();
3025-
}
30263049
} else {
3027-
// No label at all; insert it.
3028-
diagnose(Tok, diag::expr_typeof_expected_label_of)
3029-
.fixItInsert(ofRange.getStart(), "of: ");
3050+
// There cannot be a richer diagnostic here because the user may have
3051+
// defined a function `type(...)` that conflicts with the magic expr.
3052+
diagnose(Tok, diag::expr_typeof_expected_label_of);
30303053
}
30313054

30323055
// Parse the subexpression.

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType,
12401240
if (isSelfInitUse(VMI))
12411241
Kind = DIUseKind::SelfInit;
12421242
else
1243-
// Otherwise, this is a simple reference to "dynamicType", which is
1243+
// Otherwise, this is a simple reference to "type(of:)", which is
12441244
// always fine, even if self is uninitialized.
12451245
continue;
12461246
}
@@ -1386,7 +1386,7 @@ void ElementUseCollector::collectDelegatingClassInitSelfUses() {
13861386
if (isSelfInitUse(VMI))
13871387
Kind = DIUseKind::SelfInit;
13881388
else
1389-
// Otherwise, this is a simple reference to "dynamicType", which is
1389+
// Otherwise, this is a simple reference to "type(of:)", which is
13901390
// always fine, even if self is uninitialized.
13911391
continue;
13921392
}

test/Parse/type_expr.swift

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func unqualifiedType() {
5353
_ = Foo.instMeth
5454

5555
_ = Foo // expected-error{{expected member name or constructor call after type name}} expected-note{{add arguments}} {{10-10=()}} expected-note{{use '.self'}} {{10-10=.self}}
56+
_ = Foo.dynamicType // expected-error {{expected member name or constructor call after type name}}
57+
// expected-error@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{10-22=)}}
58+
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
59+
// expected-note@-3 {{use '.self' to reference the type object}}
5660

5761
_ = Bad // expected-error{{expected member name or constructor call after type name}}
5862
// expected-note@-1{{use '.self' to reference the type object}}{{10-10=.self}}
@@ -69,6 +73,10 @@ func qualifiedType() {
6973
_ = Foo.Bar.instMeth
7074

7175
_ = Foo.Bar // expected-error{{expected member name or constructor call after type name}} expected-note{{add arguments}} {{14-14=()}} expected-note{{use '.self'}} {{14-14=.self}}
76+
_ = Foo.Bar.dynamicType // expected-error {{expected member name or constructor call after type name}}
77+
// expected-error@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{14-26=)}}
78+
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
79+
// expected-note@-3 {{use '.self' to reference the type object}}
7280
}
7381

7482
/* TODO allow '.Type' in expr context
@@ -102,9 +110,27 @@ func genQualifiedType() {
102110
_ = Gen<Foo>.Bar.instMeth
103111

104112
_ = Gen<Foo>.Bar
113+
_ = Gen<Foo>.Bar.dynamicType // expected-error {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{19-31=)}}
114+
}
115+
116+
func typeOfShadowing() {
117+
// Try to shadow type(of:)
118+
func type<T>(of t: T.Type, flag: Bool) -> T.Type {
119+
return t
120+
}
121+
122+
func type<T>(_ t: T.Type) -> T.Type {
123+
return t
124+
}
125+
126+
func type<T>(fo t: T.Type) -> T.Type {
127+
return t
128+
}
129+
105130
_ = type(of: Gen<Foo>.Bar) // No error here.
106-
_ = type(Gen<Foo>.Bar) // expected-error {{expected argument label 'of:' within 'type(...)'}} {{12-12=of: }}
107-
_ = type(fo: Gen<Foo>.Bar) // expected-error {{expected argument label 'of:' within 'type(...)'}}
131+
_ = type(Gen<Foo>.Bar) // No error here.
132+
_ = type(of: Gen<Foo>.Bar.self, flag: false) // No error here.
133+
_ = type(fo: Foo.Bar.self) // No error here.
108134
}
109135

110136
func archetype<T: Zim>(_: T) {

test/SILGen/optional_chain_addressor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
func foo(x: UnsafeMutablePointer<UnsafeMutablePointer<()>?>) {
44
_ = x.pointee?.pointee
5-
_ = type(of: x.pointee)
5+
_ = x.pointee.map { type(of: $0) }
66
}

0 commit comments

Comments
 (0)