Files
mercury/tests/invalid/bad_format_call.m
Zoltan Somogyi a32d6a16f4 Add the format_call pragma to the language.
doc/reference_manual.texi:
NEWS:
    Document and announce the new pragma.

compiler/prog_data_pragma.m:
compiler/prog_item.m:
    Provide a representation for the new pragma. The part that ends up
    being referred to from the HLDS goes into prog_data_pragma.m,
    the part that is not needed once the HLDS has been constructed
    goes into prog_item.m.

compiler/hlds_pred.m:
    Add a slot to pred_infos for info from the new pragma.

    Fix a bug in the comment on marker_has_format_call.

compiler/add_pragma.m:
    Add the information in these pragmas to the HLDS.

compiler/check_pragma_format_call.m:
    A new module to check the validity of format_call pragmas.
    These checks test whether the arguments named in such pragmas
    have the expected types and modes, which means that
    the check must be done after both type and mode checking.

compiler/check_hlds.m:
compiler/notes/compiler_design.html:
    Add and document the new module.

compiler/hlds_module.m:
    Add a field to the module_info that records the set of pred_ids
    that have format_call pragmas.

compiler/mercury_compile_front_end.m:
    Invoke the check_pragma_format_call pass *provided* that
    the new field in the module_info says it has any pragmas to check.

compiler/parse_pragma.m:
    Add code to parse the new pragma.

compiler/format_call.m:
    Check calls to predicates and functions with the new pragma
    the same way as we check calls to string.format, io.format,
    and stream.string_writer.format.

    This required separating the code that checked calls to such predicates
    from the code that optimized calls to such predicates, since

    - a predicate or function with a format_call pragma that specifies
      more than one argument pair has to have its correctness checked
      for each pair, and

    - a predicate or function with a format_call pragma does not actually
      do any formatting, so that formatting cannot be optimized.

    Fix an old bug, where we included the function result in the function's
    reported arity, which meant that an error message could mention a call
    to a nonexistent function. As part of that fix, the error message
    now specifies whether it is complaining about a call to a predicate
    or a function.

    Change the exported interface of this module a bit
    in order to allow the factoring out of repeated code.

compiler/parse_string_format.m:
    Separate the parsing of format strings from their optimization,
    again because calls to predicates and functions with format_call
    pragmas need to be checked but cannot be optimized.

compiler/polymorphism.m:
    Record the effect on argument numbers of any type_info and/or
    typeclass_info arguments added by this pass.

compiler/convert_parse_tree.m:
compiler/det_analysis.m:
compiler/direct_arg_in_out.m:
compiler/equiv_type.m:
compiler/get_dependencies.m:
compiler/hlds_out_pred.m:
compiler/item_util.m:
compiler/module_qual.qualify_items.m:
compiler/parse_tree_out_pragma.m:
compiler/prog_item_stats.m:
compiler/recompilation.version.m:
compiler/simplify_proc.m:
    Conform to the changes above.

tests/invalid/bad_format_call.{m,err_exp}:
    A new test case to see whether check_pragma_format_call.m detects
    and reports invalid format_call pragmas as expected.

tests/warnings/format_call_warning.{m,exp}:
tests/warnings/format_call_warning_helper.m:
    A new test case to see whether we generate the expected set of error
    messages for incorrect calls to a predicate with a format_call pragma.

tests/invalid/Mmakefile:
tests/warnings/Mercury.options:
tests/warnings/Mmakefile:
    Enable the new test cases.

tests/invalid/string_format_bad.err_exp:
tests/invalid/string_format_unknown.err_exp:
tests/warnings/disabled_warning.exp:
    Expect the predicate vs function distinction to the printed in
    error messages about bad calls to formatting predicates and functions.
2022-09-24 08:42:36 +10:00

85 lines
2.8 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
% Test the generation of error messages for invalid format_call pragmas.
%---------------------------------------------------------------------------%
:- module bad_format_call.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module list.
:- import_module string.
main(!IO) :-
arg_num_test_1("%s", [s("a")], !IO),
ArgNumTest2 = arg_num_test_2("%s", [s("a")]),
io.format("%s\n", [s(ArgNumTest2)], !IO),
type_test_1("%s", [s("a")], !IO),
TypeTest2 = type_test_2("%s", [s("a")]),
io.format("%s\n", [s(TypeTest2)], !IO),
mode_test_1("%s", _, [s("a")], !IO),
ModeTest2 = mode_test_2("%s", [s("a")], _),
io.format("%s\n", [s(ModeTest2)], !IO).
%---------------------------------------------------------------------------%
:- pred arg_num_test_1(string::in, list(poly_type)::in, io::di, io::uo) is det.
:- pragma format_call(pred(arg_num_test_1/4), format_string_values(-2, 5)).
arg_num_test_1(FormatStr, Values, !IO) :-
io.format(FormatStr, Values, !IO).
:- func arg_num_test_2(string, list(poly_type)) = string.
:- pragma format_call(func(arg_num_test_2/2), format_string_values(3, -4)).
arg_num_test_2(FormatStr, Values) = Str :-
string.format(FormatStr, Values, Str).
%---------------------------------------------------------------------------%
:- pred type_test_1(string::in, list(poly_type)::in, io::di, io::uo) is det.
:- pragma format_call(pred(type_test_1/4), format_string_values(2, 3)).
type_test_1(FormatStr, Values, !IO) :-
io.format(FormatStr, Values, !IO).
:- func type_test_2(string, list(poly_type)) = string.
:- pragma format_call(func(type_test_2/2), format_string_values(2, 1)).
type_test_2(FormatStr, Values) = Str :-
string.format(FormatStr, Values, Str).
%---------------------------------------------------------------------------%
:- pred mode_test_1(string::in, string::out, list(poly_type)::in,
io::di, io::uo) is det.
:- pragma format_call(pred(mode_test_1/5), format_string_values(2, 3)).
mode_test_1(FormatStr0, FormatStr, Values, !IO) :-
FormatStr = FormatStr0,
io.format(FormatStr0, Values, !IO).
:- func mode_test_2(string::in, list(poly_type)::in, list(poly_type)::out)
= (string::out) is det.
:- pragma format_call(func(mode_test_2/3), format_string_values(1, 3)).
mode_test_2(FormatStr, Values0, Values) = Str :-
Values = Values0,
string.format(FormatStr, Values, Str).
%---------------------------------------------------------------------------%