Skip to content

Commit 7f8e50f

Browse files
authored
Merge pull request #4642 from jtbandes/swift-3.0-branch
[Swift 3.0] diagnostics improvements
2 parents 86e4a12 + 82c7d31 commit 7f8e50f

File tree

10 files changed

+122
-113
lines changed

10 files changed

+122
-113
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,8 @@ ERROR(operator_decl_no_fixity,none,
388388
"operator must be declared as 'prefix', 'postfix', or 'infix'", ())
389389

390390
// PrecedenceGroup
391+
ERROR(precedencegroup_not_infix,none,
392+
"only infix operators may declare a precedence", ())
391393
ERROR(expected_precedencegroup_name,none,
392394
"expected identifier after 'precedencegroup'", ())
393395
ERROR(expected_precedencegroup_lbrace,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,18 @@ NOTE(any_as_anyobject_fixit, none,
8282
"cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members", ())
8383

8484
ERROR(expected_argument_in_contextual_member,none,
85-
"contextual member %0 expects argument of type %1", (DeclName, Type))
85+
"member %0 expects argument of type %1", (DeclName, Type))
86+
ERROR(expected_parens_in_contextual_member,none,
87+
"member %0 is a function; did you mean to call it?", (DeclName))
8688

8789
ERROR(expected_result_in_contextual_member,none,
8890
"member %0 in %2 produces result of type %1, but context expects %2",
8991
(DeclName, Type, Type))
9092

9193
ERROR(unexpected_argument_in_contextual_member,none,
92-
"contextual member %0 has no associated value", (DeclName))
94+
"member %0 takes no arguments", (DeclName))
95+
ERROR(unexpected_parens_in_contextual_member,none,
96+
"member %0 is not a function", (DeclName))
9397

9498
ERROR(could_not_use_value_member,none,
9599
"member %1 cannot be used on value of type %0", (Type, DeclName))

include/swift/Parse/Parser.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -825,18 +825,10 @@ class Parser {
825825

826826
ParserResult<OperatorDecl> parseDeclOperator(ParseDeclOptions Flags,
827827
DeclAttributes &Attributes);
828-
ParserResult<OperatorDecl> parseDeclPrefixOperator(SourceLoc OperatorLoc,
829-
Identifier Name,
830-
SourceLoc NameLoc,
831-
DeclAttributes &Attrs);
832-
ParserResult<OperatorDecl> parseDeclPostfixOperator(SourceLoc OperatorLoc,
833-
Identifier Name,
834-
SourceLoc NameLoc,
835-
DeclAttributes &Attrs);
836-
ParserResult<OperatorDecl> parseDeclInfixOperator(SourceLoc OperatorLoc,
837-
Identifier Name,
838-
SourceLoc NameLoc,
839-
DeclAttributes &Attrs);
828+
ParserResult<OperatorDecl> parseDeclOperatorImpl(SourceLoc OperatorLoc,
829+
Identifier Name,
830+
SourceLoc NameLoc,
831+
DeclAttributes &Attrs);
840832

841833
ParserResult<PrecedenceGroupDecl>
842834
parseDeclPrecedenceGroup(ParseDeclOptions flags, DeclAttributes &attributes);

lib/Parse/ParseDecl.cpp

Lines changed: 45 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -5574,17 +5574,8 @@ Parser::parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes) {
55745574

55755575
Identifier Name = Context.getIdentifier(Tok.getText());
55765576
SourceLoc NameLoc = consumeToken();
5577-
5578-
ParserResult<OperatorDecl> Result;
5579-
if (Attributes.hasAttribute<PrefixAttr>())
5580-
Result = parseDeclPrefixOperator(OperatorLoc, Name, NameLoc, Attributes);
5581-
else if (Attributes.hasAttribute<PostfixAttr>())
5582-
Result = parseDeclPostfixOperator(OperatorLoc, Name, NameLoc, Attributes);
5583-
else {
5584-
if (!Attributes.hasAttribute<InfixAttr>())
5585-
diagnose(OperatorLoc, diag::operator_decl_no_fixity);
5586-
Result = parseDeclInfixOperator(OperatorLoc, Name, NameLoc, Attributes);
5587-
}
5577+
5578+
auto Result = parseDeclOperatorImpl(OperatorLoc, Name, NameLoc, Attributes);
55885579

55895580
if (!DCC.movedToTopLevel() && !AllowTopLevel) {
55905581
diagnose(OperatorLoc, diag::operator_decl_inner_scope);
@@ -5595,89 +5586,68 @@ Parser::parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes) {
55955586
}
55965587

55975588
ParserResult<OperatorDecl>
5598-
Parser::parseDeclPrefixOperator(SourceLoc OperatorLoc, Identifier Name,
5589+
Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
55995590
SourceLoc NameLoc, DeclAttributes &Attributes) {
5600-
SourceLoc lBraceLoc;
5601-
if (consumeIf(tok::l_brace, lBraceLoc)) {
5602-
auto Diag = diagnose(lBraceLoc, diag::deprecated_operator_body);
5603-
if (Tok.is(tok::r_brace)) {
5604-
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
5605-
NameLoc);
5606-
SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc());
5607-
Diag.fixItRemoveChars(lastGoodLocEnd, rBraceEnd);
5608-
}
5609-
5610-
skipUntilDeclRBrace();
5611-
(void) consumeIf(tok::r_brace);
5612-
}
5591+
bool isPrefix = Attributes.hasAttribute<PrefixAttr>();
5592+
bool isInfix = Attributes.hasAttribute<InfixAttr>();
5593+
bool isPostfix = Attributes.hasAttribute<PostfixAttr>();
56135594

5614-
auto *Res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc,
5615-
Name, NameLoc);
5616-
Res->getAttrs() = Attributes;
5617-
return makeParserResult(Res);
5618-
}
5619-
5620-
ParserResult<OperatorDecl>
5621-
Parser::parseDeclPostfixOperator(SourceLoc OperatorLoc,
5622-
Identifier Name, SourceLoc NameLoc,
5623-
DeclAttributes &Attributes) {
5624-
SourceLoc lBraceLoc;
5625-
if (consumeIf(tok::l_brace, lBraceLoc)) {
5626-
auto Diag = diagnose(lBraceLoc, diag::deprecated_operator_body);
5627-
if (Tok.is(tok::r_brace)) {
5628-
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
5629-
NameLoc);
5630-
SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc());
5631-
Diag.fixItRemoveChars(lastGoodLocEnd, rBraceEnd);
5632-
}
5633-
5634-
skipUntilDeclRBrace();
5635-
(void) consumeIf(tok::r_brace);
5636-
}
5637-
5638-
auto Res = new (Context) PostfixOperatorDecl(CurDeclContext, OperatorLoc,
5639-
Name, NameLoc);
5640-
Res->getAttrs() = Attributes;
5641-
return makeParserResult(Res);
5642-
}
5643-
5644-
ParserResult<OperatorDecl>
5645-
Parser::parseDeclInfixOperator(SourceLoc operatorLoc, Identifier name,
5646-
SourceLoc nameLoc, DeclAttributes &attributes) {
5595+
// Parse (or diagnose) a specified precedence group.
56475596
SourceLoc colonLoc;
56485597
Identifier precedenceGroupName;
56495598
SourceLoc precedenceGroupNameLoc;
56505599
if (consumeIf(tok::colon, colonLoc)) {
56515600
if (Tok.is(tok::identifier)) {
56525601
precedenceGroupName = Context.getIdentifier(Tok.getText());
56535602
precedenceGroupNameLoc = consumeToken(tok::identifier);
5603+
5604+
if (isPrefix || isPostfix)
5605+
diagnose(colonLoc, diag::precedencegroup_not_infix)
5606+
.fixItRemove({colonLoc, precedenceGroupNameLoc});
56545607
}
56555608
}
5656-
5609+
5610+
// Diagnose deprecated operator body syntax `operator + { ... }`.
56575611
SourceLoc lBraceLoc;
56585612
if (consumeIf(tok::l_brace, lBraceLoc)) {
5659-
if (Tok.is(tok::r_brace)) {
5660-
SourceLoc lastGoodLoc = precedenceGroupNameLoc;
5661-
if (lastGoodLoc.isInvalid())
5662-
lastGoodLoc = nameLoc;
5663-
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
5664-
lastGoodLoc);
5665-
SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc());
5666-
diagnose(lBraceLoc, diag::deprecated_operator_body)
5667-
.fixItRemoveChars(lastGoodLocEnd, rBraceEnd);
5668-
} else {
5613+
if (isInfix && !Tok.is(tok::r_brace)) {
56695614
diagnose(lBraceLoc, diag::deprecated_operator_body_use_group);
5615+
} else {
5616+
auto Diag = diagnose(lBraceLoc, diag::deprecated_operator_body);
5617+
if (Tok.is(tok::r_brace)) {
5618+
SourceLoc lastGoodLoc = precedenceGroupNameLoc;
5619+
if (lastGoodLoc.isInvalid())
5620+
lastGoodLoc = NameLoc;
5621+
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
5622+
lastGoodLoc);
5623+
SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc());
5624+
Diag.fixItRemoveChars(lastGoodLocEnd, rBraceEnd);
5625+
}
56705626
}
56715627

56725628
skipUntilDeclRBrace();
56735629
(void) consumeIf(tok::r_brace);
56745630
}
5675-
5676-
auto res = new (Context) InfixOperatorDecl(CurDeclContext, operatorLoc,
5677-
name, nameLoc, colonLoc,
5678-
precedenceGroupName,
5679-
precedenceGroupNameLoc);
5680-
res->getAttrs() = attributes;
5631+
5632+
5633+
OperatorDecl *res;
5634+
if (Attributes.hasAttribute<PrefixAttr>())
5635+
res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc,
5636+
Name, NameLoc);
5637+
else if (Attributes.hasAttribute<PostfixAttr>())
5638+
res = new (Context) PostfixOperatorDecl(CurDeclContext, OperatorLoc,
5639+
Name, NameLoc);
5640+
else {
5641+
if (!Attributes.hasAttribute<InfixAttr>())
5642+
diagnose(OperatorLoc, diag::operator_decl_no_fixity);
5643+
5644+
res = new (Context) InfixOperatorDecl(CurDeclContext, OperatorLoc,
5645+
Name, NameLoc, colonLoc,
5646+
precedenceGroupName,
5647+
precedenceGroupNameLoc);
5648+
}
5649+
5650+
res->getAttrs() = Attributes;
56815651
return makeParserResult(res);
56825652
}
56835653

lib/Parse/ParseStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ namespace {
860860
Expr *Guard = nullptr;
861861
};
862862

863-
/// Contexts in which a guarded pattern can appears.
863+
/// Contexts in which a guarded pattern can appear.
864864
enum class GuardedPatternContext {
865865
Case,
866866
Catch,

lib/Sema/CSDiag.cpp

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6049,7 +6049,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
60496049
return true;
60506050
}
60516051

6052-
auto argumentTy = candidateInfo[0].getArgumentType();
6052+
auto candidateArgTy = candidateInfo[0].getArgumentType();
60536053

60546054
// Depending on how we matched, produce tailored diagnostics.
60556055
switch (candidateInfo.closeness) {
@@ -6068,9 +6068,9 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
60686068
case CC_ExactMatch: { // This is a perfect match for the arguments.
60696069

60706070
// If we have an exact match, then we must have an argument list, check it.
6071-
if (argumentTy) {
6071+
if (candidateArgTy) {
60726072
assert(E->getArgument() && "Exact match without argument?");
6073-
if (!typeCheckArgumentChildIndependently(E->getArgument(), argumentTy,
6073+
if (!typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
60746074
candidateInfo))
60756075
return true;
60766076
}
@@ -6104,16 +6104,16 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
61046104

61056105
case CC_ArgumentLabelMismatch: { // Argument labels are not correct.
61066106
auto argExpr = typeCheckArgumentChildIndependently(E->getArgument(),
6107-
argumentTy,
6107+
candidateArgTy,
61086108
candidateInfo);
61096109
if (!argExpr) return true;
61106110

61116111
// Construct the actual expected argument labels that our candidate
61126112
// expected.
6113-
assert(argumentTy &&
6113+
assert(candidateArgTy &&
61146114
"Candidate must expect an argument to have a label mismatch");
61156115
SmallVector<Identifier, 2> argLabelsScratch;
6116-
auto arguments = decomposeArgType(argumentTy,
6116+
auto arguments = decomposeArgType(candidateArgTy,
61176117
candidateInfo[0].getArgumentLabels(
61186118
argLabelsScratch));
61196119

@@ -6131,26 +6131,40 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
61316131
case CC_ArgumentCountMismatch: // This candidate has wrong # arguments.
61326132
// If we have no argument, the candidates must have expected one.
61336133
if (!E->getArgument()) {
6134-
if (!argumentTy)
6134+
if (!candidateArgTy)
61356135
return false; // Candidate must be incorrect for some other reason.
61366136

61376137
// Pick one of the arguments that are expected as an exemplar.
6138-
diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member,
6139-
E->getName(), argumentTy);
6138+
if (candidateArgTy->isVoid()) {
6139+
// If this member is () -> T, suggest adding parentheses.
6140+
diagnose(E->getNameLoc(), diag::expected_parens_in_contextual_member,
6141+
E->getName())
6142+
.fixItInsertAfter(E->getEndLoc(), "()");
6143+
} else {
6144+
diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member,
6145+
E->getName(), candidateArgTy);
6146+
}
61406147
return true;
61416148
}
61426149

6143-
// If an argument value was specified, but this is a simple enumerator, then
6144-
// we fail with a nice error message.
6145-
auto argTy = candidateInfo[0].getArgumentType();
6146-
if (!argTy) {
6147-
diagnose(E->getNameLoc(), diag::unexpected_argument_in_contextual_member,
6148-
E->getName());
6150+
// If an argument value was specified, but this member expects no arguments,
6151+
// then we fail with a nice error message.
6152+
if (!candidateArgTy) {
6153+
if (E->getArgument()->getType()->isVoid()) {
6154+
diagnose(E->getNameLoc(), diag::unexpected_parens_in_contextual_member,
6155+
E->getName())
6156+
.fixItRemove(E->getArgument()->getSourceRange());
6157+
} else {
6158+
diagnose(E->getNameLoc(), diag::unexpected_argument_in_contextual_member,
6159+
E->getName())
6160+
.highlight(E->getArgument()->getSourceRange());
6161+
}
61496162
return true;
61506163
}
61516164

6152-
assert(E->getArgument() && argTy && "Exact match without an argument?");
6153-
return !typeCheckArgumentChildIndependently(E->getArgument(), argTy,
6165+
assert(E->getArgument() && candidateArgTy &&
6166+
"Exact match without an argument?");
6167+
return !typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
61546168
candidateInfo);
61556169
}
61566170

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,13 +428,13 @@ let _: [Color] = [1,2].map { _ in .Unknown("") }// expected-error {{missing argu
428428

429429
let _: (Int) -> (Int, Color) = { ($0, .Unknown("")) } // expected-error {{missing argument label 'description:' in call}} {{48-48=description: }}
430430
let _: Color = .Unknown("") // expected-error {{missing argument label 'description:' in call}} {{25-25=description: }}
431-
let _: Color = .Unknown // expected-error {{contextual member 'Unknown' expects argument of type '(description: String)'}}
431+
let _: Color = .Unknown // expected-error {{member 'Unknown' expects argument of type '(description: String)'}}
432432
let _: Color = .Unknown(42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
433433
let _ : Color = .rainbow(42) // expected-error {{argument passed to call that takes no arguments}}
434434

435435
let _ : (Int, Float) = (42.0, 12) // expected-error {{cannot convert value of type 'Double' to specified type 'Int'}}
436436

437-
let _ : Color = .rainbow // expected-error {{contextual member 'rainbow' expects argument of type '()'}}
437+
let _ : Color = .rainbow // expected-error {{member 'rainbow' is a function; did you mean to call it?}} {{25-25=()}}
438438

439439
let _: Color = .overload(a : 1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
440440
let _: Color = .overload(1.0) // expected-error {{ambiguous reference to member 'overload'}}

test/Constraints/members.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ enum SomeErrorType {
557557

558558
static func someErrorFromString(_ str: String) -> SomeErrorType? {
559559
if str == "standalone" { return .StandaloneError }
560-
if str == "underlying" { return .UnderlyingError } // expected-error {{contextual member 'UnderlyingError' expects argument of type 'String'}}
560+
if str == "underlying" { return .UnderlyingError } // expected-error {{member 'UnderlyingError' expects argument of type 'String'}}
561561
return nil
562562
}
563563
}

test/Parse/operator_decl.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,33 @@ infix operator +++ {} // expected-warning {{operator should no longer be declare
66
infix operator +++* { // expected-warning {{operator should no longer be declared with body; use a precedence group instead}} {{none}}
77
associativity right
88
}
9-
infix operator +++** : A { } // expected-warning {{operator should no longer be declared with body}} {{25-29=}}
9+
infix operator +++*+ : A { } // expected-warning {{operator should no longer be declared with body}} {{25-29=}}
10+
11+
12+
prefix operator +++** : A { }
13+
// expected-error@-1 {{only infix operators may declare a precedence}} {{23-27=}}
14+
// expected-warning@-2 {{operator should no longer be declared with body}} {{26-30=}}
15+
16+
prefix operator ++*++ : A
17+
// expected-error@-1 {{only infix operators may declare a precedence}} {{23-26=}}
18+
19+
postfix operator ++*+* : A { }
20+
// expected-error@-1 {{only infix operators may declare a precedence}} {{24-28=}}
21+
// expected-warning@-2 {{operator should no longer be declared with body}} {{27-31=}}
22+
23+
postfix operator ++**+ : A
24+
// expected-error@-1 {{only infix operators may declare a precedence}} {{24-27=}}
25+
26+
operator ++*** : A
27+
// expected-error@-1 {{operator must be declared as 'prefix', 'postfix', or 'infix'}}
28+
29+
operator +*+++ { }
30+
// expected-error@-1 {{operator must be declared as 'prefix', 'postfix', or 'infix'}}
31+
// expected-warning@-2 {{operator should no longer be declared with body}} {{15-19=}}
32+
33+
operator +*++* : A { }
34+
// expected-error@-1 {{operator must be declared as 'prefix', 'postfix', or 'infix'}}
35+
// expected-warning@-2 {{operator should no longer be declared with body}} {{19-23=}}
1036

1137
prefix operator // expected-error {{expected operator name in operator declaration}}
1238

test/decl/enum/enumtest.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,9 @@ func f() {
219219
}
220220

221221
func union_error(_ a: ZeroOneTwoThree) {
222-
var _ : ZeroOneTwoThree = .Zero(1) // expected-error {{contextual member 'Zero' has no associated value}}
223-
var _ : ZeroOneTwoThree = .One // expected-error {{contextual member 'One' expects argument of type 'Int'}}
222+
var _ : ZeroOneTwoThree = .Zero(1) // expected-error {{member 'Zero' takes no arguments}}
223+
var _ : ZeroOneTwoThree = .Zero() // expected-error {{member 'Zero' is not a function}} {{34-36=}}
224+
var _ : ZeroOneTwoThree = .One // expected-error {{member 'One' expects argument of type 'Int'}}
224225
var _ : ZeroOneTwoThree = .foo // expected-error {{type 'ZeroOneTwoThree' has no member 'foo'}}
225226
var _ : ZeroOneTwoThree = .foo() // expected-error {{type 'ZeroOneTwoThree' has no member 'foo'}}
226227
}

0 commit comments

Comments
 (0)