Files
mercury/tests/warnings/format_call_warning.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

101 lines
3.5 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
:- module format_call_warning.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module format_call_warning_helper.
:- import_module int.
:- import_module list.
:- import_module string.
main(!IO) :-
CurLevel = 6,
Msg = "The record temperature is",
TempA = 42.3,
TempB = 43.2,
% This call should get warnings for all four fs/vl pairs.
maybe_log_msg(CurLevel, 1,
"%%s: 5.2f", [f(TempA)], [f(TempB)],
"%5.2f", [s(Msg), f(TempA)], [s(Msg), f(TempB)], !IO),
% This call should get a warning for only the second fs/vl pair.
maybe_log_msg(CurLevel, 1,
"%5.2f", [f(TempA)], [f(TempB), s(Msg)],
"%s: %5.2f", [s(Msg), f(TempA)], [s(Msg), f(TempB)], !IO),
% This call should not get any warnings.
maybe_log_msg(CurLevel, 1,
"%5.2f", [f(TempA)], [f(TempB)],
"%s: %5.2f", [s(Msg), f(TempA)], [s(Msg), f(TempB)], !IO),
% This call should get a warning.
maybe_log_simple_msg(CurLevel, 1, "%s: %5.2f", [s(Msg), s(Msg)], !IO),
% This call should get a warning.
maybe_log_imported_msg(CurLevel, 1, "%s: %5.2f",
[f(TempA), f(TempB)], !IO).
%---------------------------------------------------------------------------%
:- pred maybe_log_msg(int::in, int::in,
string::in, list(poly_type)::in, list(poly_type)::in,
string::in, list(poly_type)::in, list(poly_type)::in,
io::di, io::uo) is det.
:- pragma format_call(pred(maybe_log_msg/10),
[format_string_values(3, 4), format_string_values(3, 5),
format_string_values(6, 7), format_string_values(6, 8)]).
maybe_log_msg(CurLogLevel, MsgLevel,
FormatStrA, ValuesListA1, ValuesListA2,
FormatStrB, ValuesListB1, ValuesListB2, !IO) :-
Diff = MsgLevel - CurLogLevel,
% The first four calls to io.format below use <format string/values list>
% pairs that are listed in the format_call pragma. This means that
% callers of maybe_log_msg should have checked their compatibility,
% which means that we *don't* want to warn about being unable to check
% their compatibility *here*.
( if Diff >= 15 then
io.format(FormatStrA, ValuesListA1, !IO)
else if Diff >= 10 then
io.format(FormatStrA, ValuesListA2, !IO)
else if Diff >= 5 then
io.format(FormatStrB, ValuesListB1, !IO)
else if Diff >= 0 then
io.format(FormatStrB, ValuesListB2, !IO)
else
% While ValuesListB2 is listed in the format_call pragma, the
% format string does not come from there. Therefore the compiler
% *should* generate a warning about being unable to check this call
% due to having no idea about the value of ValuesListB2.
io.format("%d", ValuesListB2, !IO)
).
:- pred maybe_log_simple_msg(int::in, int::in,
string::in, list(poly_type)::in, io::di, io::uo) is det.
:- pragma format_call(pred(maybe_log_simple_msg/6),
format_string_values(3, 4)).
maybe_log_simple_msg(CurLogLevel, MsgLevel,
FormatStr, ValuesList, !IO) :-
Diff = MsgLevel - CurLogLevel,
( if Diff >= 0 then
io.format(FormatStr, ValuesList, !IO)
else
true
).
%---------------------------------------------------------------------------%