mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
func foo(x: UnsafeMutablePointer<UnsafeMutablePointer<()>?>) {
|
||||
_ = x.pointee?.pointee
|
||||
_ = type(of: x.pointee)
|
||||
_ = x.pointee.map { type(of: $0) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user