From 6d8d087357e58b69a5d95f642c19b72055c74079 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Thu, 17 Oct 2024 10:20:56 -0700 Subject: [PATCH] Add s plural format to IntAsSelect --- toolchain/check/call.cpp | 7 +++--- toolchain/check/convert.cpp | 22 +++++++++---------- .../testdata/array/fail_out_of_bound.carbon | 2 +- .../testdata/array/fail_type_mismatch.carbon | 4 ++-- .../testdata/builtins/float/negate.carbon | 6 ++--- .../check/testdata/builtins/int/sadd.carbon | 2 +- .../testdata/builtins/int/snegate.carbon | 8 +++---- .../check/testdata/builtins/int/uadd.carbon | 2 +- .../testdata/builtins/int/unegate.carbon | 8 +++---- .../check/testdata/class/fail_init.carbon | 4 ++-- .../check/testdata/class/fail_method.carbon | 2 +- .../check/testdata/class/generic/call.carbon | 4 ++-- .../testdata/class/virtual_modifiers.carbon | 2 +- .../function/call/fail_param_count.carbon | 12 +++++----- .../function/generic/redeclare.carbon | 6 ++--- .../testdata/struct/fail_assign_empty.carbon | 2 +- .../struct/fail_assign_to_empty.carbon | 2 +- .../struct/fail_too_few_values.carbon | 2 +- .../testdata/tuple/fail_assign_nested.carbon | 2 +- .../tuple/fail_too_few_element.carbon | 2 +- toolchain/check/testdata/tuple/import.carbon | 2 +- .../tuple/no_prelude/fail_assign_empty.carbon | 2 +- .../no_prelude/fail_assign_to_empty.carbon | 2 +- toolchain/diagnostics/format_providers.cpp | 7 +++++- toolchain/diagnostics/format_providers.h | 20 +++++++++++------ .../diagnostics/format_providers_test.cpp | 9 +++++++- 26 files changed, 81 insertions(+), 62 deletions(-) diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp index e86e22299bf64..8052ef726d3e8 100644 --- a/toolchain/check/call.cpp +++ b/toolchain/check/call.cpp @@ -9,6 +9,7 @@ #include "toolchain/check/convert.h" #include "toolchain/check/deduce.h" #include "toolchain/check/function.h" +#include "toolchain/diagnostics/format_providers.h" #include "toolchain/sem_ir/builtin_function_kind.h" #include "toolchain/sem_ir/builtin_inst_kind.h" #include "toolchain/sem_ir/entity_with_params_base.h" @@ -42,9 +43,9 @@ static auto ResolveCalleeInCall(Context& context, SemIR::LocId loc_id, auto params = context.inst_blocks().GetOrEmpty(callee_info.param_refs_id); if (arg_ids.size() != params.size()) { CARBON_DIAGNOSTIC(CallArgCountMismatch, Error, - "{0} argument(s) passed to {1} expecting " - "{2} argument(s).", - int, llvm::StringLiteral, int); + "{0} argument{0:s} passed to {1} expecting " + "{2} argument{2:s}", + IntAsSelect, llvm::StringLiteral, IntAsSelect); CARBON_DIAGNOSTIC(InCallToEntity, Note, "calling {0} declared here", llvm::StringLiteral); context.emitter() diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index f705504159a3f..cb7bb28fb8f05 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -236,12 +236,12 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, if (tuple_elem_types.size() != array_bound) { CARBON_DIAGNOSTIC( ArrayInitFromLiteralArgCountMismatch, Error, - "cannot initialize array of {0} element(s) from {1} initializer(s)", - uint64_t, size_t); + "cannot initialize array of {0} element{0:s} from {1} initializer{1:s}", + IntAsSelect, IntAsSelect); CARBON_DIAGNOSTIC(ArrayInitFromExprArgCountMismatch, Error, - "cannot initialize array of {0} element(s) from tuple " - "with {1} element(s).", - uint64_t, size_t); + "cannot initialize array of {0} element{0:s} from tuple " + "with {1} element{1:s}", + IntAsSelect, IntAsSelect); context.emitter().Emit(value_loc_id, literal_elems.empty() ? ArrayInitFromExprArgCountMismatch @@ -320,9 +320,9 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type, // Check that the tuples are the same size. if (src_elem_types.size() != dest_elem_types.size()) { CARBON_DIAGNOSTIC(TupleInitElementCountMismatch, Error, - "cannot initialize tuple of {0} element(s) from tuple " - "with {1} element(s).", - size_t, size_t); + "cannot initialize tuple of {0} element{0:s} from tuple " + "with {1} element{1:s}", + IntAsSelect, IntAsSelect); context.emitter().Emit(value_loc_id, TupleInitElementCountMismatch, dest_elem_types.size(), src_elem_types.size()); return SemIR::InstId::BuiltinError; @@ -414,9 +414,9 @@ static auto ConvertStructToStructOrClass(Context& context, if (src_elem_fields.size() != dest_elem_fields.size()) { CARBON_DIAGNOSTIC( StructInitElementCountMismatch, Error, - "cannot initialize {0:class|struct} with {1} field(s) from struct " - "with {2} field(s).", - BoolAsSelect, size_t, size_t); + "cannot initialize {0:class|struct} with {1} field{1:s} from struct " + "with {2} field{2:s}", + BoolAsSelect, IntAsSelect, IntAsSelect); context.emitter().Emit(value_loc_id, StructInitElementCountMismatch, ToClass, dest_elem_fields.size(), src_elem_fields.size()); diff --git a/toolchain/check/testdata/array/fail_out_of_bound.carbon b/toolchain/check/testdata/array/fail_out_of_bound.carbon index 72e46fd91824b..3bce7d61fe46e 100644 --- a/toolchain/check/testdata/array/fail_out_of_bound.carbon +++ b/toolchain/check/testdata/array/fail_out_of_bound.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/array/fail_out_of_bound.carbon -// CHECK:STDERR: fail_out_of_bound.carbon:[[@LINE+3]]:19: error: cannot initialize array of 1 element(s) from 3 initializer(s) +// CHECK:STDERR: fail_out_of_bound.carbon:[[@LINE+3]]:19: error: cannot initialize array of 1 element from 3 initializers // CHECK:STDERR: var a: [i32; 1] = (1, 2, 3); // CHECK:STDERR: ^~~~~~~~~ var a: [i32; 1] = (1, 2, 3); diff --git a/toolchain/check/testdata/array/fail_type_mismatch.carbon b/toolchain/check/testdata/array/fail_type_mismatch.carbon index 3385651830656..1309cf63e1c97 100644 --- a/toolchain/check/testdata/array/fail_type_mismatch.carbon +++ b/toolchain/check/testdata/array/fail_type_mismatch.carbon @@ -27,14 +27,14 @@ var t1: (i32, String, String); // CHECK:STDERR: var b: [i32; 3] = t1; -// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+4]]:19: error: cannot initialize array of 3 element(s) from 2 initializer(s) +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+4]]:19: error: cannot initialize array of 3 elements from 2 initializers // CHECK:STDERR: var c: [i32; 3] = (1, 2); // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: var c: [i32; 3] = (1, 2); var t2: (i32, i32); -// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:19: error: cannot initialize array of 3 element(s) from tuple with 2 element(s). +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:19: error: cannot initialize array of 3 elements from tuple with 2 elements // CHECK:STDERR: var d: [i32; 3] = t2; // CHECK:STDERR: ^~ var d: [i32; 3] = t2; diff --git a/toolchain/check/testdata/builtins/float/negate.carbon b/toolchain/check/testdata/builtins/float/negate.carbon index 6ebaf8fa75b46..556fc7d3bcf00 100644 --- a/toolchain/check/testdata/builtins/float/negate.carbon +++ b/toolchain/check/testdata/builtins/float/negate.carbon @@ -40,7 +40,7 @@ fn BadReturnType(a: f64) -> bool = "float.negate"; fn JustRight(a: f64) -> f64 = "float.negate"; fn RuntimeCallTooFew(a: f64) -> f64 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument passed to function expecting 0 arguments // CHECK:STDERR: return TooFew(a); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-17]]:1: note: calling function declared here @@ -51,7 +51,7 @@ fn RuntimeCallTooFew(a: f64) -> f64 { } fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 arguments passed to function expecting 2 arguments // CHECK:STDERR: return TooMany(a, b, c); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-23]]:1: note: calling function declared here @@ -62,7 +62,7 @@ fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { } fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: error: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: return BadReturnType(a, b); // CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-29]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/builtins/int/sadd.carbon b/toolchain/check/testdata/builtins/int/sadd.carbon index 1816af3aa8466..4145550867fa3 100644 --- a/toolchain/check/testdata/builtins/int/sadd.carbon +++ b/toolchain/check/testdata/builtins/int/sadd.carbon @@ -56,7 +56,7 @@ var too_many: [i32; TooMany(1, 2, 3)]; // CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1, 2)]; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 3 argument(s) passed to function expecting 2 argument(s). +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 3 arguments passed to function expecting 2 arguments // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2, 3)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/builtins/int/snegate.carbon b/toolchain/check/testdata/builtins/int/snegate.carbon index d11ba5d1e0a87..e5a37b3a9ff49 100644 --- a/toolchain/check/testdata/builtins/int/snegate.carbon +++ b/toolchain/check/testdata/builtins/int/snegate.carbon @@ -58,7 +58,7 @@ var too_many: [i32; TooMany(1, 2)]; // CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1)]; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 2 argument(s) passed to function expecting 1 argument(s). +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: note: calling function declared here @@ -68,7 +68,7 @@ var bad_return_type: [i32; BadReturnType(1)]; var bad_call: [i32; JustRight(1, 2)]; fn RuntimeCallTooFew(a: i32) -> i32 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument passed to function expecting 0 arguments // CHECK:STDERR: return TooFew(a); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-42]]:1: note: calling function declared here @@ -79,7 +79,7 @@ fn RuntimeCallTooFew(a: i32) -> i32 { } fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 arguments passed to function expecting 2 arguments // CHECK:STDERR: return TooMany(a, b, c); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-48]]:1: note: calling function declared here @@ -90,7 +90,7 @@ fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { } fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: return BadReturnType(a, b); // CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-54]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/builtins/int/uadd.carbon b/toolchain/check/testdata/builtins/int/uadd.carbon index ef5eb9f531130..a593589c3000d 100644 --- a/toolchain/check/testdata/builtins/int/uadd.carbon +++ b/toolchain/check/testdata/builtins/int/uadd.carbon @@ -56,7 +56,7 @@ var too_many: [i32; TooMany(1, 2, 3)]; // CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1, 2)]; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:21: error: 3 argument(s) passed to function expecting 2 argument(s). +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:21: error: 3 arguments passed to function expecting 2 arguments // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2, 3)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/builtins/int/unegate.carbon b/toolchain/check/testdata/builtins/int/unegate.carbon index 2f858e0e74e3a..6ebcf71170033 100644 --- a/toolchain/check/testdata/builtins/int/unegate.carbon +++ b/toolchain/check/testdata/builtins/int/unegate.carbon @@ -58,7 +58,7 @@ var too_many: [i32; TooMany(1, 2)]; // CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1)]; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 2 argument(s) passed to function expecting 1 argument(s). +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: note: calling function declared here @@ -68,7 +68,7 @@ var bad_return_type: [i32; BadReturnType(1)]; var bad_call: [i32; JustRight(1, 2)]; fn RuntimeCallTooFew(a: i32) -> i32 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 1 argument passed to function expecting 0 arguments // CHECK:STDERR: return TooFew(a); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-42]]:1: note: calling function declared here @@ -79,7 +79,7 @@ fn RuntimeCallTooFew(a: i32) -> i32 { } fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: error: 3 arguments passed to function expecting 2 arguments // CHECK:STDERR: return TooMany(a, b, c); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-48]]:1: note: calling function declared here @@ -90,7 +90,7 @@ fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { } fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { - // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: error: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: return BadReturnType(a, b); // CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-54]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/class/fail_init.carbon b/toolchain/check/testdata/class/fail_init.carbon index 78c3ad62f792c..4d68df1d8f64a 100644 --- a/toolchain/check/testdata/class/fail_init.carbon +++ b/toolchain/check/testdata/class/fail_init.carbon @@ -14,7 +14,7 @@ class Class { } fn F() { - // CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: cannot initialize class with 2 field(s) from struct with 1 field(s). + // CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: cannot initialize class with 2 fields from struct with 1 field // CHECK:STDERR: {.a = 1} as Class; // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: @@ -24,7 +24,7 @@ fn F() { // CHECK:STDERR: ^~~~~~~~~~~~~~~~ // CHECK:STDERR: {.a = 1, .c = 2} as Class; - // CHECK:STDERR: fail_init.carbon:[[@LINE+3]]:3: error: cannot initialize class with 2 field(s) from struct with 3 field(s). + // CHECK:STDERR: fail_init.carbon:[[@LINE+3]]:3: error: cannot initialize class with 2 fields from struct with 3 fields // CHECK:STDERR: {.a = 1, .b = 2, .c = 3} as Class; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ {.a = 1, .b = 2, .c = 3} as Class; diff --git a/toolchain/check/testdata/class/fail_method.carbon b/toolchain/check/testdata/class/fail_method.carbon index 9bcfb871f0fd2..05baebfb17f4d 100644 --- a/toolchain/check/testdata/class/fail_method.carbon +++ b/toolchain/check/testdata/class/fail_method.carbon @@ -28,7 +28,7 @@ fn F(c: Class) { // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: Class.WithSelf(); - // CHECK:STDERR: fail_method.carbon:[[@LINE+7]]:3: error: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_method.carbon:[[@LINE+7]]:3: error: 1 argument passed to function expecting 0 arguments // CHECK:STDERR: Class.WithSelf(c); // CHECK:STDERR: ^~~~~~~~~~~~~~~ // CHECK:STDERR: fail_method.carbon:[[@LINE-21]]:3: note: calling function declared here diff --git a/toolchain/check/testdata/class/generic/call.carbon b/toolchain/check/testdata/class/generic/call.carbon index aa0ca37bb4ee8..1a60c3732c6a3 100644 --- a/toolchain/check/testdata/class/generic/call.carbon +++ b/toolchain/check/testdata/class/generic/call.carbon @@ -25,7 +25,7 @@ library "[[@TEST_NAME]]"; class Class(T:! type, N:! i32) {} -// CHECK:STDERR: fail_too_few.carbon:[[@LINE+7]]:8: error: 1 argument(s) passed to generic class expecting 2 argument(s). +// CHECK:STDERR: fail_too_few.carbon:[[@LINE+7]]:8: error: 1 argument passed to generic class expecting 2 arguments // CHECK:STDERR: var a: Class(i32*); // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_too_few.carbon:[[@LINE-5]]:1: note: calling generic class declared here @@ -40,7 +40,7 @@ library "[[@TEST_NAME]]"; class Class(T:! type, N:! i32) {} -// CHECK:STDERR: fail_too_many.carbon:[[@LINE+7]]:8: error: 3 argument(s) passed to generic class expecting 2 argument(s). +// CHECK:STDERR: fail_too_many.carbon:[[@LINE+7]]:8: error: 3 arguments passed to generic class expecting 2 arguments // CHECK:STDERR: var a: Class(i32*, 1, 2); // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_too_many.carbon:[[@LINE-5]]:1: note: calling generic class declared here diff --git a/toolchain/check/testdata/class/virtual_modifiers.carbon b/toolchain/check/testdata/class/virtual_modifiers.carbon index 14ab62b715d3c..5a7ec1d84f330 100644 --- a/toolchain/check/testdata/class/virtual_modifiers.carbon +++ b/toolchain/check/testdata/class/virtual_modifiers.carbon @@ -45,7 +45,7 @@ import Modifiers; fn F() { // TODO: The vptr shouldn't be counted for programmer-facing behavior. - // CHECK:STDERR: fail_todo_init.carbon:[[@LINE+3]]:27: error: cannot initialize class with 1 field(s) from struct with 0 field(s). + // CHECK:STDERR: fail_todo_init.carbon:[[@LINE+3]]:27: error: cannot initialize class with 1 field from struct with 0 fields // CHECK:STDERR: var v: Modifiers.Base = {}; // CHECK:STDERR: ^~ var v: Modifiers.Base = {}; diff --git a/toolchain/check/testdata/function/call/fail_param_count.carbon b/toolchain/check/testdata/function/call/fail_param_count.carbon index 9efecc772ad3d..584b26f5173de 100644 --- a/toolchain/check/testdata/function/call/fail_param_count.carbon +++ b/toolchain/check/testdata/function/call/fail_param_count.carbon @@ -13,7 +13,7 @@ fn Run1(a: i32) {} fn Run2(a: i32, b: i32) {} fn Main() { - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 1 argument passed to function expecting 0 arguments // CHECK:STDERR: Run0(1); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-8]]:1: note: calling function declared here @@ -21,7 +21,7 @@ fn Main() { // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: Run0(1); - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 2 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 2 arguments passed to function expecting 0 arguments // CHECK:STDERR: Run0(0, 1); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-16]]:1: note: calling function declared here @@ -30,7 +30,7 @@ fn Main() { // CHECK:STDERR: Run0(0, 1); - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 0 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 0 arguments passed to function expecting 1 argument // CHECK:STDERR: Run1(); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-24]]:1: note: calling function declared here @@ -38,7 +38,7 @@ fn Main() { // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ // CHECK:STDERR: Run1(); - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 2 arguments passed to function expecting 1 argument // CHECK:STDERR: Run1(0, 1); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-32]]:1: note: calling function declared here @@ -47,7 +47,7 @@ fn Main() { // CHECK:STDERR: Run1(0, 1); - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 0 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+7]]:3: error: 0 arguments passed to function expecting 2 arguments // CHECK:STDERR: Run2(); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-40]]:1: note: calling function declared here @@ -55,7 +55,7 @@ fn Main() { // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: Run2(); - // CHECK:STDERR: fail_param_count.carbon:[[@LINE+6]]:3: error: 1 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_param_count.carbon:[[@LINE+6]]:3: error: 1 argument passed to function expecting 2 arguments // CHECK:STDERR: Run2(0); // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_param_count.carbon:[[@LINE-48]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/function/generic/redeclare.carbon b/toolchain/check/testdata/function/generic/redeclare.carbon index 31d843fe48847..59b1cdcd4e987 100644 --- a/toolchain/check/testdata/function/generic/redeclare.carbon +++ b/toolchain/check/testdata/function/generic/redeclare.carbon @@ -32,7 +32,7 @@ fn F(T:! type, U:! type) -> T*; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fn F(T:! type, U:! type) -> U* { - // CHECK:STDERR: fail_different_return_type.carbon:[[@LINE+7]]:10: error: 1 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_different_return_type.carbon:[[@LINE+7]]:10: error: 1 argument passed to function expecting 2 arguments // CHECK:STDERR: return F(T); // CHECK:STDERR: ^~ // CHECK:STDERR: fail_different_return_type.carbon:[[@LINE-13]]:1: note: calling function declared here @@ -56,7 +56,7 @@ fn F(T:! type, U:! type) -> T*; // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fn F(U:! type, T:! type) -> T* { - // CHECK:STDERR: fail_reorder.carbon:[[@LINE+7]]:10: error: 1 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_reorder.carbon:[[@LINE+7]]:10: error: 1 argument passed to function expecting 2 arguments // CHECK:STDERR: return F(T); // CHECK:STDERR: ^~ // CHECK:STDERR: fail_reorder.carbon:[[@LINE-13]]:1: note: calling function declared here @@ -80,7 +80,7 @@ fn F(T:! type, U:! type) -> T*; // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fn F(U:! type, T:! type) -> U* { - // CHECK:STDERR: fail_rename.carbon:[[@LINE+6]]:10: error: 1 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: fail_rename.carbon:[[@LINE+6]]:10: error: 1 argument passed to function expecting 2 arguments // CHECK:STDERR: return F(T); // CHECK:STDERR: ^~ // CHECK:STDERR: fail_rename.carbon:[[@LINE-13]]:1: note: calling function declared here diff --git a/toolchain/check/testdata/struct/fail_assign_empty.carbon b/toolchain/check/testdata/struct/fail_assign_empty.carbon index 62cde58fbbc5d..d325a3d399a75 100644 --- a/toolchain/check/testdata/struct/fail_assign_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_empty.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_assign_empty.carbon -// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+3]]:20: error: cannot initialize struct with 1 field(s) from struct with 0 field(s). +// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+3]]:20: error: cannot initialize struct with 1 field from struct with 0 fields // CHECK:STDERR: var x: {.a: i32} = {}; // CHECK:STDERR: ^~ var x: {.a: i32} = {}; diff --git a/toolchain/check/testdata/struct/fail_assign_to_empty.carbon b/toolchain/check/testdata/struct/fail_assign_to_empty.carbon index 64f2042591797..bab28f527ee75 100644 --- a/toolchain/check/testdata/struct/fail_assign_to_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_to_empty.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_assign_to_empty.carbon -// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+3]]:13: error: cannot initialize struct with 0 field(s) from struct with 1 field(s). +// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+3]]:13: error: cannot initialize struct with 0 fields from struct with 1 field // CHECK:STDERR: var x: {} = {.a = 1}; // CHECK:STDERR: ^~~~~~~~ var x: {} = {.a = 1}; diff --git a/toolchain/check/testdata/struct/fail_too_few_values.carbon b/toolchain/check/testdata/struct/fail_too_few_values.carbon index 53583a2dba152..188b97e3bb7e9 100644 --- a/toolchain/check/testdata/struct/fail_too_few_values.carbon +++ b/toolchain/check/testdata/struct/fail_too_few_values.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_too_few_values.carbon -// CHECK:STDERR: fail_too_few_values.carbon:[[@LINE+3]]:29: error: cannot initialize struct with 2 field(s) from struct with 1 field(s). +// CHECK:STDERR: fail_too_few_values.carbon:[[@LINE+3]]:29: error: cannot initialize struct with 2 fields from struct with 1 field // CHECK:STDERR: var x: {.a: i32, .b: i32} = {.a = 1}; // CHECK:STDERR: ^~~~~~~~ var x: {.a: i32, .b: i32} = {.a = 1}; diff --git a/toolchain/check/testdata/tuple/fail_assign_nested.carbon b/toolchain/check/testdata/tuple/fail_assign_nested.carbon index 353b5a09ce0f5..d6caa51d36602 100644 --- a/toolchain/check/testdata/tuple/fail_assign_nested.carbon +++ b/toolchain/check/testdata/tuple/fail_assign_nested.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/tuple/fail_assign_nested.carbon -// CHECK:STDERR: fail_assign_nested.carbon:[[@LINE+3]]:36: error: cannot initialize tuple of 2 element(s) from tuple with 3 element(s). +// CHECK:STDERR: fail_assign_nested.carbon:[[@LINE+3]]:36: error: cannot initialize tuple of 2 elements from tuple with 3 elements // CHECK:STDERR: var x: ((i32, i32), (i32, i32)) = ((1, 2, 3), (4, 5, 6)); // CHECK:STDERR: ^~~~~~~~~ var x: ((i32, i32), (i32, i32)) = ((1, 2, 3), (4, 5, 6)); diff --git a/toolchain/check/testdata/tuple/fail_too_few_element.carbon b/toolchain/check/testdata/tuple/fail_too_few_element.carbon index c15c8c710baa3..e44cb01abd3fc 100644 --- a/toolchain/check/testdata/tuple/fail_too_few_element.carbon +++ b/toolchain/check/testdata/tuple/fail_too_few_element.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/tuple/fail_too_few_element.carbon -// CHECK:STDERR: fail_too_few_element.carbon:[[@LINE+3]]:21: error: cannot initialize tuple of 2 element(s) from tuple with 1 element(s). +// CHECK:STDERR: fail_too_few_element.carbon:[[@LINE+3]]:21: error: cannot initialize tuple of 2 elements from tuple with 1 element // CHECK:STDERR: var x: (i32, i32) = (2, ); // CHECK:STDERR: ^~~~~ var x: (i32, i32) = (2, ); diff --git a/toolchain/check/testdata/tuple/import.carbon b/toolchain/check/testdata/tuple/import.carbon index b0b2b29407596..06aaf181f73bd 100644 --- a/toolchain/check/testdata/tuple/import.carbon +++ b/toolchain/check/testdata/tuple/import.carbon @@ -31,7 +31,7 @@ var c: C((1, 2)) = F(); impl package Implicit; -// CHECK:STDERR: fail_bad_type.impl.carbon:[[@LINE+4]]:14: error: cannot initialize tuple of 2 element(s) from tuple with 3 element(s). +// CHECK:STDERR: fail_bad_type.impl.carbon:[[@LINE+4]]:14: error: cannot initialize tuple of 2 elements from tuple with 3 elements // CHECK:STDERR: var c_bad: C((1, 2, 3)) = F(); // CHECK:STDERR: ^~~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/check/testdata/tuple/no_prelude/fail_assign_empty.carbon b/toolchain/check/testdata/tuple/no_prelude/fail_assign_empty.carbon index 575a17c71d6fb..336ba90c655e6 100644 --- a/toolchain/check/testdata/tuple/no_prelude/fail_assign_empty.carbon +++ b/toolchain/check/testdata/tuple/no_prelude/fail_assign_empty.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/tuple/no_prelude/fail_assign_empty.carbon -// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+3]]:16: error: cannot initialize tuple of 1 element(s) from tuple with 0 element(s). +// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+3]]:16: error: cannot initialize tuple of 1 element from tuple with 0 elements // CHECK:STDERR: var x: ((),) = (); // CHECK:STDERR: ^~ var x: ((),) = (); diff --git a/toolchain/check/testdata/tuple/no_prelude/fail_assign_to_empty.carbon b/toolchain/check/testdata/tuple/no_prelude/fail_assign_to_empty.carbon index 228c3308e0d4b..2fabe24bb1120 100644 --- a/toolchain/check/testdata/tuple/no_prelude/fail_assign_to_empty.carbon +++ b/toolchain/check/testdata/tuple/no_prelude/fail_assign_to_empty.carbon @@ -8,7 +8,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/tuple/no_prelude/fail_assign_to_empty.carbon -// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+3]]:13: error: cannot initialize tuple of 0 element(s) from tuple with 1 element(s). +// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+3]]:13: error: cannot initialize tuple of 0 elements from tuple with 1 element // CHECK:STDERR: var x: () = ((),); // CHECK:STDERR: ^~~~~ var x: () = ((),); diff --git a/toolchain/diagnostics/format_providers.cpp b/toolchain/diagnostics/format_providers.cpp index 70500798404a3..764f39cdfb28f 100644 --- a/toolchain/diagnostics/format_providers.cpp +++ b/toolchain/diagnostics/format_providers.cpp @@ -38,7 +38,12 @@ auto llvm::format_provider::format( auto llvm::format_provider::format( const Carbon::IntAsSelect& wrapper, raw_ostream& out, StringRef style) -> void { - if (style.empty()) { + if (style == "s") { + if (wrapper.value != 1) { + out << "s"; + } + return; + } else if (style.empty()) { llvm::format_provider::format(wrapper.value, out, style); return; } diff --git a/toolchain/diagnostics/format_providers.h b/toolchain/diagnostics/format_providers.h index 97d8af0ca755b..abd65c8c9a292 100644 --- a/toolchain/diagnostics/format_providers.h +++ b/toolchain/diagnostics/format_providers.h @@ -10,12 +10,13 @@ namespace Carbon { -// Selects a formatv string based on the value. If the format style is not -// provided, as in `{0}`, the value uses standard formatting. +// Selects a formatv string based on the value. // -// When used, the true and false outputs are separated by a `|`. -// -// For example, `{0:true|false}` would yield standard bool formatting. +// Supported format styles are: +// - None, as in `{0}`. This uses standard integer formatting. +// - Selector, as in `{0:true|false}`. The output string used is separated by a +// `|`, with the true case first. the example would yield standard bool +// formatting. // // If needed, the _full_ style string can be wrapped with `'` in order to // preserve prefix or suffix whitespace (which is stripped by formatv). For @@ -28,8 +29,13 @@ struct BoolAsSelect { bool value; }; -// Selects a formatv string based on the value. If the format style is not -// provided, as in `{0}`, the value uses standard formatting. +// Selects a formatv string based on the value. +// +// Supported format styles are: +// - None, as in `{0}`. This uses standard integer formatting. +// - Selector, as in `{0:=0:zero|:default}`. This is detailed below. +// - Plural `s`, as in `{0:s}`. This outputs an `s` when the value is not 1, +// equivalent to `{0:=1:|:s}`. // // The style is a series of match cases, separated by `|`. Each case is a pair // formatted as `:`. diff --git a/toolchain/diagnostics/format_providers_test.cpp b/toolchain/diagnostics/format_providers_test.cpp index 0d6cf68eecf34..a0a938c2a96ac 100644 --- a/toolchain/diagnostics/format_providers_test.cpp +++ b/toolchain/diagnostics/format_providers_test.cpp @@ -75,12 +75,19 @@ TEST(IntAsSelect, QuotedSpaces) { EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq(" default ")); } -TEST(IntAsSelect, PluralExample) { +TEST(IntAsSelect, CasesWithNormalFormat) { constexpr char Format[] = "{0} argument{0:=1:|:s}"; EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("0 arguments")); EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("1 argument")); EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq("2 arguments")); } +TEST(IntAsSelect, PluralS) { + constexpr char Format[] = "{0} argument{0:s}"; + EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("0 arguments")); + EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("1 argument")); + EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq("2 arguments")); +} + } // namespace } // namespace Carbon