Skip to content

Commit bc3a7d1

Browse files
committed
[QoI] improve diagnostics for contextual members with argument mismatch
1 parent 14ad9f9 commit bc3a7d1

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
@@ -6069,7 +6069,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
60696069
return true;
60706070
}
60716071

6072-
auto argumentTy = candidateInfo[0].getArgumentType();
6072+
auto candidateArgTy = candidateInfo[0].getArgumentType();
60736073

60746074
// Depending on how we matched, produce tailored diagnostics.
60756075
switch (candidateInfo.closeness) {
@@ -6088,9 +6088,9 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
60886088
case CC_ExactMatch: { // This is a perfect match for the arguments.
60896089

60906090
// If we have an exact match, then we must have an argument list, check it.
6091-
if (argumentTy) {
6091+
if (candidateArgTy) {
60926092
assert(E->getArgument() && "Exact match without argument?");
6093-
if (!typeCheckArgumentChildIndependently(E->getArgument(), argumentTy,
6093+
if (!typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
60946094
candidateInfo))
60956095
return true;
60966096
}
@@ -6124,16 +6124,16 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
61246124

61256125
case CC_ArgumentLabelMismatch: { // Argument labels are not correct.
61266126
auto argExpr = typeCheckArgumentChildIndependently(E->getArgument(),
6127-
argumentTy,
6127+
candidateArgTy,
61286128
candidateInfo);
61296129
if (!argExpr) return true;
61306130

61316131
// Construct the actual expected argument labels that our candidate
61326132
// expected.
6133-
assert(argumentTy &&
6133+
assert(candidateArgTy &&
61346134
"Candidate must expect an argument to have a label mismatch");
61356135
SmallVector<Identifier, 2> argLabelsScratch;
6136-
auto arguments = decomposeArgType(argumentTy,
6136+
auto arguments = decomposeArgType(candidateArgTy,
61376137
candidateInfo[0].getArgumentLabels(
61386138
argLabelsScratch));
61396139

@@ -6151,26 +6151,40 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
61516151
case CC_ArgumentCountMismatch: // This candidate has wrong # arguments.
61526152
// If we have no argument, the candidates must have expected one.
61536153
if (!E->getArgument()) {
6154-
if (!argumentTy)
6154+
if (!candidateArgTy)
61556155
return false; // Candidate must be incorrect for some other reason.
61566156

61576157
// Pick one of the arguments that are expected as an exemplar.
6158-
diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member,
6159-
E->getName(), argumentTy);
6158+
if (candidateArgTy->isVoid()) {
6159+
// If this member is () -> T, suggest adding parentheses.
6160+
diagnose(E->getNameLoc(), diag::expected_parens_in_contextual_member,
6161+
E->getName())
6162+
.fixItInsertAfter(E->getEndLoc(), "()");
6163+
} else {
6164+
diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member,
6165+
E->getName(), candidateArgTy);
6166+
}
61606167
return true;
61616168
}
61626169

6163-
// If an argument value was specified, but this is a simple enumerator, then
6164-
// we fail with a nice error message.
6165-
auto argTy = candidateInfo[0].getArgumentType();
6166-
if (!argTy) {
6167-
diagnose(E->getNameLoc(), diag::unexpected_argument_in_contextual_member,
6168-
E->getName());
6170+
// If an argument value was specified, but this member expects no arguments,
6171+
// then we fail with a nice error message.
6172+
if (!candidateArgTy) {
6173+
if (E->getArgument()->getType()->isVoid()) {
6174+
diagnose(E->getNameLoc(), diag::unexpected_parens_in_contextual_member,
6175+
E->getName())
6176+
.fixItRemove(E->getArgument()->getSourceRange());
6177+
} else {
6178+
diagnose(E->getNameLoc(), diag::unexpected_argument_in_contextual_member,
6179+
E->getName())
6180+
.highlight(E->getArgument()->getSourceRange());
6181+
}
61696182
return true;
61706183
}
61716184

6172-
assert(E->getArgument() && argTy && "Exact match without an argument?");
6173-
return !typeCheckArgumentChildIndependently(E->getArgument(), argTy,
6185+
assert(E->getArgument() && candidateArgTy &&
6186+
"Exact match without an argument?");
6187+
return !typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
61746188
candidateInfo);
61756189
}
61766190

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
@@ -575,7 +575,7 @@ enum SomeErrorType {
575575

576576
static func someErrorFromString(_ str: String) -> SomeErrorType? {
577577
if str == "standalone" { return .StandaloneError }
578-
if str == "underlying" { return .UnderlyingError } // expected-error {{contextual member 'UnderlyingError' expects argument of type 'String'}}
578+
if str == "underlying" { return .UnderlyingError } // expected-error {{member 'UnderlyingError' expects argument of type 'String'}}
579579
return nil
580580
}
581581
}

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)