Skip to content

Commit ec3f7dd

Browse files
authored
Fix diagnostic for argument count mismatch on call to generic constraint (#6292)
The error message was saying "generic interface" but should say "generic constraint" There is one test that demonstrates the error message for interfaces, but it's in tests for overloads, so add a more clearly dedicated test for interface too.
1 parent 9085e9e commit ec3f7dd

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-7
lines changed

toolchain/check/call.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum class EntityKind : uint8_t {
3636
Function = 0,
3737
GenericClass = 1,
3838
GenericInterface = 2,
39+
GenericNamedConstraint = 3,
3940
};
4041
} // namespace
4142

@@ -62,15 +63,16 @@ static auto ResolveCalleeInCall(Context& context, SemIR::LocId loc_id,
6263
if (arg_ids.size() != params.size()) {
6364
CARBON_DIAGNOSTIC(CallArgCountMismatch, Error,
6465
"{0} argument{0:s} passed to "
65-
"{1:=0:function|=1:generic class|=2:generic interface}"
66+
"{1:=0:function|=1:generic class|=2:generic "
67+
"interface|=3:generic constraint}"
6668
" expecting {2} argument{2:s}",
6769
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect,
6870
Diagnostics::IntAsSelect);
69-
CARBON_DIAGNOSTIC(
70-
InCallToEntity, Note,
71-
"calling {0:=0:function|=1:generic class|=2:generic interface}"
72-
" declared here",
73-
Diagnostics::IntAsSelect);
71+
CARBON_DIAGNOSTIC(InCallToEntity, Note,
72+
"calling {0:=0:function|=1:generic class|=2:generic "
73+
"interface|=3:generic constraint}"
74+
" declared here",
75+
Diagnostics::IntAsSelect);
7476
context.emitter()
7577
.Build(loc_id, CallArgCountMismatch, arg_ids.size(),
7678
static_cast<int>(entity_kind_for_diagnostic), params.size())
@@ -137,8 +139,13 @@ static auto PerformCallToGenericInterfaceOrNamedConstaint(
137139
SemIR::SpecificId enclosing_specific_id,
138140
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
139141
const auto& entity = EntityFromInterfaceOrNamedConstraint(context, id);
142+
143+
auto entity_kind_for_diagnostic = EntityKind::GenericInterface;
144+
if constexpr (std::same_as<IdT, SemIR::NamedConstraintId>) {
145+
entity_kind_for_diagnostic = EntityKind::GenericNamedConstraint;
146+
}
140147
auto callee_specific_id =
141-
ResolveCalleeInCall(context, loc_id, entity, EntityKind::GenericInterface,
148+
ResolveCalleeInCall(context, loc_id, entity, entity_kind_for_diagnostic,
142149
enclosing_specific_id,
143150
/*self_type_id=*/SemIR::InstId::None,
144151
/*self_id=*/SemIR::InstId::None, arg_ids);

toolchain/check/testdata/interface/generic.carbon

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ fn G(T:! Generic(B)) {
6262
F(T);
6363
}
6464

65+
// --- fail_args_count_mismatch.carbon
66+
library "[[@TEST_NAME]]";
67+
68+
interface Generic(T:! type) {}
69+
70+
// CHECK:STDERR: fail_args_count_mismatch.carbon:[[@LINE+7]]:10: error: 2 arguments passed to generic interface expecting 1 argument [CallArgCountMismatch]
71+
// CHECK:STDERR: fn F(T:! Generic((), ())) {}
72+
// CHECK:STDERR: ^~~~~~~~~~~~~~~
73+
// CHECK:STDERR: fail_args_count_mismatch.carbon:[[@LINE-5]]:1: note: calling generic interface declared here [InCallToEntity]
74+
// CHECK:STDERR: interface Generic(T:! type) {}
75+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76+
// CHECK:STDERR:
77+
fn F(T:! Generic((), ())) {}
78+
6579
// CHECK:STDOUT: --- generic.carbon
6680
// CHECK:STDOUT:
6781
// CHECK:STDOUT: constants {
@@ -519,3 +533,74 @@ fn G(T:! Generic(B)) {
519533
// CHECK:STDOUT: %T.loc10_6.1 => constants.%T.7ca
520534
// CHECK:STDOUT: }
521535
// CHECK:STDOUT:
536+
// CHECK:STDOUT: --- fail_args_count_mismatch.carbon
537+
// CHECK:STDOUT:
538+
// CHECK:STDOUT: constants {
539+
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
540+
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
541+
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic]
542+
// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete]
543+
// CHECK:STDOUT: %Generic.type.c21: type = generic_interface_type @Generic [concrete]
544+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
545+
// CHECK:STDOUT: %Generic.generic: %Generic.type.c21 = struct_value () [concrete]
546+
// CHECK:STDOUT: %Generic.type.68b: type = facet_type <@Generic, @Generic(%T)> [symbolic]
547+
// CHECK:STDOUT: %Self: %Generic.type.68b = symbolic_binding Self, 1 [symbolic]
548+
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
549+
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
550+
// CHECK:STDOUT: }
551+
// CHECK:STDOUT:
552+
// CHECK:STDOUT: file {
553+
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
554+
// CHECK:STDOUT: .Generic = %Generic.decl
555+
// CHECK:STDOUT: .F = %F.decl
556+
// CHECK:STDOUT: }
557+
// CHECK:STDOUT: %Generic.decl: %Generic.type.c21 = interface_decl @Generic [concrete = constants.%Generic.generic] {
558+
// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
559+
// CHECK:STDOUT: } {
560+
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
561+
// CHECK:STDOUT: %T.loc3_19.2: type = symbolic_binding T, 0 [symbolic = %T.loc3_19.1 (constants.%T)]
562+
// CHECK:STDOUT: }
563+
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
564+
// CHECK:STDOUT: %T.patt: <error> = symbolic_binding_pattern T, 0 [concrete]
565+
// CHECK:STDOUT: } {
566+
// CHECK:STDOUT: %.1: <error> = splice_block <error> [concrete = <error>] {
567+
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
568+
// CHECK:STDOUT: %Generic.ref: %Generic.type.c21 = name_ref Generic, file.%Generic.decl [concrete = constants.%Generic.generic]
569+
// CHECK:STDOUT: %.loc12_19: %empty_tuple.type = tuple_literal ()
570+
// CHECK:STDOUT: %.loc12_23: %empty_tuple.type = tuple_literal ()
571+
// CHECK:STDOUT: }
572+
// CHECK:STDOUT: %T: <error> = symbolic_binding T, 0 [concrete = <error>]
573+
// CHECK:STDOUT: }
574+
// CHECK:STDOUT: }
575+
// CHECK:STDOUT:
576+
// CHECK:STDOUT: generic interface @Generic(%T.loc3_19.2: type) {
577+
// CHECK:STDOUT: %T.loc3_19.1: type = symbolic_binding T, 0 [symbolic = %T.loc3_19.1 (constants.%T)]
578+
// CHECK:STDOUT:
579+
// CHECK:STDOUT: !definition:
580+
// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(%T.loc3_19.1)> [symbolic = %Generic.type (constants.%Generic.type.68b)]
581+
// CHECK:STDOUT: %Self.2: @Generic.%Generic.type (%Generic.type.68b) = symbolic_binding Self, 1 [symbolic = %Self.2 (constants.%Self)]
582+
// CHECK:STDOUT:
583+
// CHECK:STDOUT: interface {
584+
// CHECK:STDOUT: %Self.1: @Generic.%Generic.type (%Generic.type.68b) = symbolic_binding Self, 1 [symbolic = %Self.2 (constants.%Self)]
585+
// CHECK:STDOUT:
586+
// CHECK:STDOUT: !members:
587+
// CHECK:STDOUT: .Self = %Self.1
588+
// CHECK:STDOUT: witness = ()
589+
// CHECK:STDOUT: }
590+
// CHECK:STDOUT: }
591+
// CHECK:STDOUT:
592+
// CHECK:STDOUT: generic fn @F(%T: <error>) {
593+
// CHECK:STDOUT: !definition:
594+
// CHECK:STDOUT:
595+
// CHECK:STDOUT: fn() {
596+
// CHECK:STDOUT: !entry:
597+
// CHECK:STDOUT: return
598+
// CHECK:STDOUT: }
599+
// CHECK:STDOUT: }
600+
// CHECK:STDOUT:
601+
// CHECK:STDOUT: specific @Generic(constants.%T) {
602+
// CHECK:STDOUT: %T.loc3_19.1 => constants.%T
603+
// CHECK:STDOUT: }
604+
// CHECK:STDOUT:
605+
// CHECK:STDOUT: specific @F(<error>) {}
606+
// CHECK:STDOUT:

toolchain/check/testdata/named_constraint/generic.carbon

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ constraint Generic(T:! type) {}
6161
// CHECK:STDERR:
6262
constraint Generic(T:! type) {}
6363

64+
// --- fail_args_count_mismatch.carbon
65+
library "[[@TEST_NAME]]";
66+
67+
constraint Generic(T:! type) {}
68+
69+
// CHECK:STDERR: fail_args_count_mismatch.carbon:[[@LINE+7]]:10: error: 2 arguments passed to generic constraint expecting 1 argument [CallArgCountMismatch]
70+
// CHECK:STDERR: fn F(T:! Generic((), ())) {}
71+
// CHECK:STDERR: ^~~~~~~~~~~~~~~
72+
// CHECK:STDERR: fail_args_count_mismatch.carbon:[[@LINE-5]]:1: note: calling generic constraint declared here [InCallToEntity]
73+
// CHECK:STDERR: constraint Generic(T:! type) {}
74+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75+
// CHECK:STDERR:
76+
fn F(T:! Generic((), ())) {}
77+
6478
// CHECK:STDOUT: --- generic.carbon
6579
// CHECK:STDOUT:
6680
// CHECK:STDOUT: constants {

0 commit comments

Comments
 (0)