Skip to content

Commit 82c7d31

Browse files
committed
[QoI] improve diagnostics for contextual members with argument mismatch
1 parent ca030da commit 82c7d31

File tree

5 files changed

+43
-24
lines changed

5 files changed

+43
-24
lines changed

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))

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/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)