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.
This commit is contained in:
Robert Widmann
2016-07-30 02:01:05 -07:00
parent 4e5665a8bd
commit 9c83e7223e
6 changed files with 75 additions and 25 deletions

View File

@@ -1114,6 +1114,8 @@ ERROR(expr_typeof_expected_expr,PointsToFirstBadToken,
"expected an expression within 'type(of: ...)'", ())
ERROR(expr_typeof_expected_rparen,PointsToFirstBadToken,
"expected ')' to complete 'type(of: ...)' expression", ())
ERROR(expr_dynamictype_deprecated,PointsToFirstBadToken,
"'.dynamicType' is deprecated. Use 'type(of: ...)' instead", ())
//------------------------------------------------------------------------------
// Attribute-parsing diagnostics

View File

@@ -36,7 +36,6 @@ bool swift::canBeArgumentLabel(StringRef identifier) {
bool swift::canBeMemberName(StringRef identifier) {
return llvm::StringSwitch<bool>(identifier)
.Case("dynamicType", false)
.Case("init", false)
.Case("Protocol", false)
.Case("self", false)

View File

@@ -950,6 +950,30 @@ getMagicIdentifierLiteralKind(tok Kind) {
}
}
/// See if type(of: <expr>) can be parsed backtracking on failure.
static bool canParseTypeOf(Parser &P) {
if (!(P.Tok.getText() == "type" && P.peekToken().is(tok::l_paren))) {
return false;
}
// Look ahead to parse the parenthesized expression.
Parser::BacktrackingScope Backtrack(P);
P.consumeToken(tok::identifier);
P.consumeToken(tok::l_paren);
// The first argument label must be 'of'.
if (!(P.Tok.getText() == "of" && P.peekToken().is(tok::colon))) {
return false;
}
// Parse to the closing paren.
while (!P.Tok.is(tok::r_paren) && !P.Tok.is(tok::eof)) {
// Anything that looks like another argument label is bogus.
if (P.Tok.is(tok::comma) && P.peekToken().canBeArgumentLabel()) {
return false;
}
P.skipSingle();
}
return true;
}
/// parseExprPostfix
///
@@ -1095,8 +1119,8 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
}
case tok::identifier: // foo
// If starts with 'type(', parse the 'type(of: ...)' metatype expression
if (Tok.getText() == "type" && peekToken().is(tok::l_paren)) {
// Attempt to parse for 'type(of: <expr>)'.
if (canParseTypeOf(*this)) {
Result = parseExprTypeOf();
break;
}
@@ -1425,6 +1449,17 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
continue;
}
// Handle the deprecated 'x.dynamicType' and migrate it to `type(of: x)`
if (Tok.getText() == "dynamicType") {
auto range = Result.get()->getSourceRange();
auto dynamicTypeExprRange = SourceRange(TokLoc, consumeToken());
diagnose(TokLoc, diag::expr_dynamictype_deprecated)
.highlight(dynamicTypeExprRange)
.fixItReplace(dynamicTypeExprRange, ")")
.fixItInsert(range.Start, "type(of: ");
continue;
}
// If we have '.<keyword><code_complete>', try to recover by creating
// an identifier with the same spelling as the keyword.
if (Tok.isKeyword() && peekToken().is(tok::code_complete)) {
@@ -3007,26 +3042,14 @@ ParserResult<Expr> Parser::parseExprTypeOf() {
SourceLoc lParenLoc = consumeToken(tok::l_paren);
// Parse `of` label.
auto ofRange = Tok.getRange();
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
bool hasOf = Tok.getText() == "of";
if (!hasOf) {
// User mis-spelled the 'of' label.
diagnose(Tok, diag::expr_typeof_expected_label_of)
.fixItReplace({ ofRange.getStart(), ofRange.getEnd() }, "of");
}
// Consume either 'of' or the misspelling.
if (Tok.getText() == "of" && peekToken().is(tok::colon)) {
// Consume the label.
consumeToken();
consumeToken(tok::colon);
if (!hasOf) {
return makeParserError();
}
} else {
// No label at all; insert it.
diagnose(Tok, diag::expr_typeof_expected_label_of)
.fixItInsert(ofRange.getStart(), "of: ");
// There cannot be a richer diagnostic here because the user may have
// defined a function `type(...)` that conflicts with the magic expr.
diagnose(Tok, diag::expr_typeof_expected_label_of);
}
// Parse the subexpression.

View File

@@ -1240,7 +1240,7 @@ collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType,
if (isSelfInitUse(VMI))
Kind = DIUseKind::SelfInit;
else
// Otherwise, this is a simple reference to "dynamicType", which is
// Otherwise, this is a simple reference to "type(of:)", which is
// always fine, even if self is uninitialized.
continue;
}
@@ -1386,7 +1386,7 @@ void ElementUseCollector::collectDelegatingClassInitSelfUses() {
if (isSelfInitUse(VMI))
Kind = DIUseKind::SelfInit;
else
// Otherwise, this is a simple reference to "dynamicType", which is
// Otherwise, this is a simple reference to "type(of:)", which is
// always fine, even if self is uninitialized.
continue;
}

View File

@@ -53,6 +53,10 @@ func unqualifiedType() {
_ = Foo.instMeth
_ = 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}}
_ = Foo.dynamicType // expected-error {{expected member name or constructor call after type name}}
// expected-error@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{10-22=)}}
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
// expected-note@-3 {{use '.self' to reference the type object}}
_ = Bad // expected-error{{expected member name or constructor call after type name}}
// expected-note@-1{{use '.self' to reference the type object}}{{10-10=.self}}
@@ -69,6 +73,10 @@ func qualifiedType() {
_ = Foo.Bar.instMeth
_ = 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}}
_ = Foo.Bar.dynamicType // expected-error {{expected member name or constructor call after type name}}
// expected-error@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{14-26=)}}
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
// expected-note@-3 {{use '.self' to reference the type object}}
}
/* TODO allow '.Type' in expr context
@@ -102,9 +110,27 @@ func genQualifiedType() {
_ = Gen<Foo>.Bar.instMeth
_ = Gen<Foo>.Bar
_ = Gen<Foo>.Bar.dynamicType // expected-error {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}} {{7-7=type(of: }} {{19-31=)}}
}
func typeOfShadowing() {
// Try to shadow type(of:)
func type<T>(of t: T.Type, flag: Bool) -> T.Type {
return t
}
func type<T>(_ t: T.Type) -> T.Type {
return t
}
func type<T>(fo t: T.Type) -> T.Type {
return t
}
_ = type(of: Gen<Foo>.Bar) // No error here.
_ = type(Gen<Foo>.Bar) // expected-error {{expected argument label 'of:' within 'type(...)'}} {{12-12=of: }}
_ = type(fo: Gen<Foo>.Bar) // expected-error {{expected argument label 'of:' within 'type(...)'}}
_ = type(Gen<Foo>.Bar) // No error here.
_ = type(of: Gen<Foo>.Bar.self, flag: false) // No error here.
_ = type(fo: Foo.Bar.self) // No error here.
}
func archetype<T: Zim>(_: T) {

View File

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