mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-05-01 01:04:43 +00:00
The objective of this step is two-fold:
- to fix --inhibit-warnings, making it shut up all warning
and informational messages; and
- to ensure that it *stays* fixed, even when after new diagnostics
are added.
As part of this fix, this diff adds a whole bunch of new warning
options, in order to control the warnings that previously were
not controlled by any option. (There was no need for new
informational options.)
As it happens, we have long used severity_informational for messages
that did not report any information about the code being compiled,
but to report actions that the compiler was taking. Create a new
option category, oc_report, for the new options that now control
those diagnostics.
---------------------
compiler/error_spec.m:
Change severity_warning and severity_informational to take an option
as as argument. The semantics is that the diagnostic in which
the severity occurs is conditional on that option, meaning that
it is printed only if that option is set to "yes".
Delete the severity_conditional function symbol from the severity
type, since the mechanism just above handles its only use case.
Define subtypes to represent error_specs in a standard form.
compiler/error_sort.m:
Provide operations to convert error specs into their standard form.
Make the sorting operation itself operate on the standard form.
compiler/write_error_spec.m:
Convert error_specs to standard form before writing them out,
in order to avoid duplicating the code for their standardization.
Change the code that writes out error_specs to operate on the
standard form. Implement the test implicit in the warning and
and informational severities in this code.
compiler/error_util.m:
compiler/compiler_util.m:
Delete operations that do not make sense with the new severity type.
---------------------
compiler/options.m:
Add new options to control all the previously-uncontrolled
warning and informational messages.
NEWS.md:
Announce the *public* new options.
compiler/option_categories.m:
compiler/print_help.m:
Add the new option category, and fake-include it in the help text
and the user guide. (The inclusion is fake because none of the
options in the new category are user visible, meaning the section
containing them is not visible either.)
---------------------
compiler/det_infer_goal.m:
Start a severity warning diagnostic with "Warning:"
instead of "Error:".
compiler/mark_trace_goals.m:
Fix an incorrect error message.
compiler/purity.m:
Replace a correct/incorrect color pair with two inconsistent colors,
because there is a reasonable probability of each one being right.
---------------------
compiler/accumulator.m:
compiler/add_clause.m:
compiler/add_mode.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/check_module_interface.m:
compiler/check_type_inst_mode_defns.m:
compiler/check_typeclass.m:
compiler/color_schemes.m:
compiler/common.m:
compiler/convert_import_use.m:
compiler/convert_parse_tree.m:
compiler/dead_proc_elim.m:
compiler/det_check_proc.m:
compiler/det_check_switch.m:
compiler/det_infer_goal.m:
compiler/du_type_layout.m:
compiler/format_call_errors.m:
compiler/grab_modules.m:
compiler/hlds_call_tree.m:
compiler/inst_check.m:
compiler/introduce_parallelism.m:
compiler/make_hlds_error.m:
compiler/make_hlds_warn.m:
compiler/mark_tail_calls.m:
compiler/mark_trace_goals.m:
compiler/mercury_compile_main.m:
compiler/mercury_compile_make_hlds.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/module_qual.qual_errors.m:
compiler/opt_deps_spec.m:
compiler/options_file.m:
compiler/parse_goal.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/pre_typecheck.m:
compiler/purity.m:
compiler/read_modules.m:
compiler/recompilation.check.m:
compiler/simplify_goal.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/split_parse_tree_src.m:
compiler/state_var.m:
compiler/stratify.m:
compiler/style_checks.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_errors.m:
compiler/term_errors.m:
compiler/termination.m:
compiler/typecheck_clauses.m:
compiler/typecheck_error_overload.m:
compiler/typecheck_error_undef.m:
compiler/typecheck_errors.m:
compiler/typecheck_msgs.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/warn_unread_modules.m:
compiler/write_module_interface_files.m:
Conform to the changes above, mostly by either
- adding an option to all warning and informational messages,
sometimes using existing warning options and sometimes new ones,
or
- turning already explicitly-conditional-on-an-option messages
into implicitly-conditional-on-that-option messages.
---------------------
tests/invalid/one_member.m:
Conform to the change in det_infer_goal.m.
tests/invalid/require_tailrec_1.err_exp:
tests/invalid/require_tailrec_2.err_exp:
Actually obey the options for these modules in Mercury.options.
tests/invalid_purity/purity.err_exp:
tests/warnings/purity_warnings.err_exp:
Conform to the change in purity.m.
tests/warnings/moved_trace_goal.err_exp:
Conform to the change in mark_trace_goals.m.
tests/warnings/help_text.err_exp:
Expect the documentation of all the new options.
401 lines
14 KiB
Mathematica
401 lines
14 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2012 The University of Melbourne.
|
|
% Copyright (C) 2022-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: error_sort.m.
|
|
% Main author: zs.
|
|
%
|
|
% This module sorts error_specs and error_msgs.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.error_sort.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.error_spec.
|
|
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The purpose of standardizing error_specs is to remove differences
|
|
% between error_specs that exist only in the structure of the error_specs
|
|
% themselves, as opposed to the text that we output for them.
|
|
%
|
|
% For example, the compiler could in theory generate (and once upon a time,
|
|
% it did generate) error specs that differ in that some error msg
|
|
% components consist of
|
|
%
|
|
% - "always(...)" in one, and
|
|
% - "option_is_set(OptionName, yes, always(...))" in the other.
|
|
%
|
|
% But if OptionName is yes, then this difference has no effect.
|
|
:- pred standardize_error_specs(globals::in,
|
|
list(error_spec)::in, list(std_error_spec)::out) is det.
|
|
:- pred standardize_error_specs_option_table(option_table::in,
|
|
list(error_spec)::in, list(std_error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred sort_std_error_specs(globals::in,
|
|
list(std_error_spec)::in, list(std_error_spec)::out) is det.
|
|
:- pred sort_std_error_specs_opt_table(option_table::in,
|
|
list(std_error_spec)::in, list(std_error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type error_msg_group
|
|
---> error_msg_group(error_msg, list(error_msg)).
|
|
|
|
:- pred sort_error_msg_groups(list(error_msg_group)::in,
|
|
list(error_msg_group)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func flatten_error_msg_groups(list(error_msg_group)) = list(error_msg).
|
|
:- func flatten_error_msg_group(error_msg_group) = list(error_msg).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred sort_error_msgs(list(error_msg)::in, list(error_msg)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module getopt.
|
|
:- import_module maybe.
|
|
:- import_module term_context.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
standardize_error_specs(Globals, Specs, StdSpecs) :-
|
|
globals.get_options(Globals, OptionTable),
|
|
standardize_error_specs_option_table(OptionTable, Specs, StdSpecs).
|
|
|
|
standardize_error_specs_option_table(OptionTable, Specs, StdSpecs) :-
|
|
list.filter_map(remove_conditionals_in_spec(OptionTable),
|
|
Specs, StdSpecs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
sort_std_error_specs(Globals, StdSpecs, SortedStdSpecs) :-
|
|
globals.get_options(Globals, OptionTable),
|
|
sort_std_error_specs_opt_table(OptionTable, StdSpecs, SortedStdSpecs).
|
|
|
|
sort_std_error_specs_opt_table(OptionTable, StdSpecs, SortedStdSpecs) :-
|
|
getopt.lookup_bool_option(OptionTable, reverse_error_order,
|
|
ReverseErrorOrder),
|
|
list.sort_and_remove_dups(
|
|
compare_std_error_specs(ReverseErrorOrder),
|
|
StdSpecs, SortedStdSpecs).
|
|
|
|
:- pred remove_conditionals_in_spec(option_table::in,
|
|
error_spec::in, std_error_spec::out) is semidet.
|
|
|
|
remove_conditionals_in_spec(OptionTable, Spec0, StdSpec) :-
|
|
require_det (
|
|
(
|
|
Spec0 = error_spec(Id, Severity0, Phase, Msgs0),
|
|
MaybeStdSeverity = yes(Severity0),
|
|
list.filter_map(remove_conditionals_in_msg(OptionTable),
|
|
Msgs0, StdMsgs)
|
|
;
|
|
Spec0 = spec(Id, Severity0, Phase, Context0, Pieces0),
|
|
MaybeStdSeverity = yes(Severity0),
|
|
StdMsgs = [error_msg(yes(Context0), treat_based_on_posn, 0u,
|
|
[always(Pieces0)])]
|
|
;
|
|
Spec0 = no_ctxt_spec(Id, Severity0, Phase, Pieces0),
|
|
MaybeStdSeverity = yes(Severity0),
|
|
StdMsgs = [error_msg(no, treat_based_on_posn, 0u,
|
|
[always(Pieces0)])]
|
|
;
|
|
Spec0 = conditional_spec(Id, Option, MatchValue,
|
|
Severity0, Phase, Msgs0),
|
|
getopt.lookup_bool_option(OptionTable, Option, OptionValue),
|
|
( if OptionValue = MatchValue then
|
|
MaybeStdSeverity = yes(Severity0),
|
|
list.filter_map(remove_conditionals_in_msg(OptionTable),
|
|
Msgs0, StdMsgs)
|
|
else
|
|
MaybeStdSeverity = no,
|
|
StdMsgs = []
|
|
)
|
|
)
|
|
),
|
|
( if
|
|
MaybeStdSeverity = yes(StdSeverity),
|
|
StdMsgs = [_ | _]
|
|
then
|
|
StdSpec = error_spec(Id, StdSeverity, Phase, StdMsgs)
|
|
else
|
|
% Spec0 would result in nothing being printed.
|
|
fail
|
|
).
|
|
|
|
:- pred remove_conditionals_in_msg(option_table::in,
|
|
error_msg::in, std_error_msg::out) is semidet.
|
|
|
|
remove_conditionals_in_msg(OptionTable, Msg0, StdMsg) :-
|
|
require_det (
|
|
(
|
|
Msg0 = msg(Context, Pieces0),
|
|
MaybeContext = yes(Context),
|
|
TreatAsFirst = treat_based_on_posn,
|
|
ExtraIndent = 0u,
|
|
Components0 = [always(Pieces0)]
|
|
;
|
|
Msg0 = no_ctxt_msg(Pieces0),
|
|
MaybeContext = no,
|
|
TreatAsFirst = treat_based_on_posn,
|
|
ExtraIndent = 0u,
|
|
Components0 = [always(Pieces0)]
|
|
;
|
|
Msg0 = simple_msg(Context, Components0),
|
|
MaybeContext = yes(Context),
|
|
TreatAsFirst = treat_based_on_posn,
|
|
ExtraIndent = 0u
|
|
;
|
|
Msg0 = error_msg(MaybeContext, TreatAsFirst, ExtraIndent,
|
|
Components0)
|
|
;
|
|
Msg0 = blank_msg(MaybeContext),
|
|
TreatAsFirst = always_treat_as_first,
|
|
ExtraIndent = 0u,
|
|
Components0 = [always([blank_line])]
|
|
),
|
|
list.foldl(remove_conditionals_in_msg_component(OptionTable),
|
|
Components0, cord.init, StdComponentCord),
|
|
StdComponents = cord.list(StdComponentCord),
|
|
StdMsg = error_msg(MaybeContext, TreatAsFirst,
|
|
ExtraIndent, StdComponents)
|
|
),
|
|
% Don't return StdMsg if StdComponents is empty.
|
|
StdComponents = [_ | _].
|
|
|
|
:- pred remove_conditionals_in_msg_component(option_table::in,
|
|
error_msg_component::in,
|
|
cord(std_error_msg_component)::in, cord(std_error_msg_component)::out)
|
|
is det.
|
|
|
|
remove_conditionals_in_msg_component(OptionTable, Component,
|
|
!StdComponentCord) :-
|
|
(
|
|
Component = option_is_set(Option, MatchValue, EmbeddedComponents),
|
|
% We could recurse down into EmbeddedComponents, but we currently
|
|
% have any places in the compiler that can generate two error messages
|
|
% that differ only in nested option settings, so there would be
|
|
% no point.
|
|
getopt.lookup_bool_option(OptionTable, Option, OptionValue),
|
|
( if OptionValue = MatchValue then
|
|
list.foldl(remove_conditionals_in_msg_component(OptionTable),
|
|
EmbeddedComponents, cord.init, StdEmbeddedComponents),
|
|
!:StdComponentCord = !.StdComponentCord ++ StdEmbeddedComponents
|
|
else
|
|
true
|
|
)
|
|
;
|
|
% We don't want to eliminate the verbose only part of a message
|
|
% even if verbose_errors isn't set. We want to keep them around
|
|
% until we print the component, so that we can record the presence
|
|
% of such verbose components, and generate a reminder of their
|
|
% existence at the end of the compilation.
|
|
%
|
|
% Besides, the compiler can't (yet) generate two error_msg_components
|
|
% that differ only in the presence of a verbose error.
|
|
( Component = always(_)
|
|
; Component = verbose_only(_, _)
|
|
; Component = verbose_and_nonverbose(_, _)
|
|
),
|
|
cord.snoc(coerce(Component), !StdComponentCord)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred compare_std_error_specs(bool::in,
|
|
std_error_spec::in, std_error_spec::in, comparison_result::out) is det.
|
|
|
|
compare_std_error_specs(ReverseErrorOrder, SpecA, SpecB, Result) :-
|
|
SpecA = error_spec(_, _, _, MsgsA),
|
|
SpecB = error_spec(_, _, _, MsgsB),
|
|
compare_std_error_msg_lists(ReverseErrorOrder, MsgsA, MsgsB, MsgsResult),
|
|
(
|
|
MsgsResult = (=),
|
|
compare(Result, SpecA, SpecB)
|
|
;
|
|
( MsgsResult = (>)
|
|
; MsgsResult = (<)
|
|
),
|
|
Result = MsgsResult
|
|
).
|
|
|
|
:- pred compare_std_error_msg_lists(bool::in,
|
|
list(std_error_msg)::in, list(std_error_msg)::in,
|
|
comparison_result::out) is det.
|
|
|
|
compare_std_error_msg_lists(ReverseErrorOrder, MsgsA, MsgsB, Result) :-
|
|
(
|
|
MsgsA = [],
|
|
MsgsB = [],
|
|
Result = (=)
|
|
;
|
|
MsgsA = [],
|
|
MsgsB = [_ | _],
|
|
Result = (<)
|
|
;
|
|
MsgsA = [_ | _],
|
|
MsgsB = [],
|
|
Result = (>)
|
|
;
|
|
MsgsA = [HeadMsgA | TailMsgsA],
|
|
MsgsB = [HeadMsgB | TailMsgsB],
|
|
compare_error_msgs(ReverseErrorOrder,
|
|
coerce(HeadMsgA), coerce(HeadMsgB), HeadResult),
|
|
(
|
|
HeadResult = (=),
|
|
compare_std_error_msg_lists(ReverseErrorOrder,
|
|
TailMsgsA, TailMsgsB, Result)
|
|
;
|
|
( HeadResult = (>)
|
|
; HeadResult = (<)
|
|
),
|
|
Result = HeadResult
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
sort_error_msg_groups(MsgGroups0, MsgGroups) :-
|
|
list.sort_and_remove_dups(compare_error_msg_groups, MsgGroups0, MsgGroups).
|
|
|
|
:- pred compare_error_msg_groups(error_msg_group::in, error_msg_group::in,
|
|
comparison_result::out) is det.
|
|
|
|
compare_error_msg_groups(GroupA, GroupB, Result) :-
|
|
GroupA = error_msg_group(HeadMsgA, TailMsgsA),
|
|
GroupB = error_msg_group(HeadMsgB, TailMsgsB),
|
|
compare_error_msgs(no, HeadMsgA, HeadMsgB, Result0),
|
|
(
|
|
Result0 = (=),
|
|
(
|
|
TailMsgsA = [],
|
|
TailMsgsB = [],
|
|
Result = (=)
|
|
;
|
|
TailMsgsA = [],
|
|
TailMsgsB = [_HeadTailMsgB | _TailTailMsgsB],
|
|
Result = (<)
|
|
;
|
|
TailMsgsA = [_HeadTailMsgA | _TailTailMsgsA],
|
|
TailMsgsB = [],
|
|
Result = (>)
|
|
;
|
|
TailMsgsA = [HeadTailMsgA | TailTailMsgsA],
|
|
TailMsgsB = [HeadTailMsgB | TailTailMsgsB],
|
|
TailGroupA = error_msg_group(HeadTailMsgA, TailTailMsgsA),
|
|
TailGroupB = error_msg_group(HeadTailMsgB, TailTailMsgsB),
|
|
compare_error_msg_groups(TailGroupA, TailGroupB, Result)
|
|
)
|
|
;
|
|
( Result0 = (<)
|
|
; Result0 = (>)
|
|
),
|
|
Result = Result0
|
|
).
|
|
|
|
flatten_error_msg_groups(Groups) = Msgs :-
|
|
MsgLists = list.map(flatten_error_msg_group, Groups),
|
|
list.condense(MsgLists, Msgs).
|
|
|
|
flatten_error_msg_group(Group) = Msgs :-
|
|
Group= error_msg_group(HeadMsg, TailMsgs),
|
|
Msgs = [HeadMsg | TailMsgs].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
sort_error_msgs(Msgs0, Msgs) :-
|
|
list.sort_and_remove_dups(compare_error_msgs(no), Msgs0, Msgs).
|
|
|
|
:- pred compare_error_msgs(bool::in, error_msg::in, error_msg::in,
|
|
comparison_result::out) is det.
|
|
|
|
compare_error_msgs(ReverseErrorOrder, MsgA, MsgB, Result) :-
|
|
extract_msg_maybe_context(MsgA, MaybeContextA),
|
|
extract_msg_maybe_context(MsgB, MaybeContextB),
|
|
% The context comparison makes sense only if both Msgs have a context.
|
|
% If one or both Msgs lack a context, then go on to compare the components.
|
|
( if
|
|
MaybeContextA = yes(ContextA),
|
|
MaybeContextB = yes(ContextB)
|
|
then
|
|
compare(ContextResult, ContextA, ContextB)
|
|
else
|
|
ContextResult = (=)
|
|
),
|
|
(
|
|
ContextResult = (=),
|
|
ComponentsA = project_msg_components(MsgA),
|
|
ComponentsB = project_msg_components(MsgB),
|
|
compare(ComponentsResult, ComponentsA, ComponentsB),
|
|
(
|
|
ComponentsResult = (=),
|
|
compare(Result, MsgA, MsgB)
|
|
;
|
|
( ComponentsResult = (>)
|
|
; ComponentsResult = (<)
|
|
),
|
|
Result = ComponentsResult
|
|
)
|
|
;
|
|
ContextResult = (>),
|
|
(
|
|
ReverseErrorOrder = no,
|
|
Result = ContextResult
|
|
;
|
|
ReverseErrorOrder = yes,
|
|
Result = (<)
|
|
)
|
|
;
|
|
ContextResult = (<),
|
|
(
|
|
ReverseErrorOrder = no,
|
|
Result = ContextResult
|
|
;
|
|
ReverseErrorOrder = yes,
|
|
Result = (>)
|
|
)
|
|
).
|
|
|
|
:- func project_msg_components(error_msg) = list(error_msg_component).
|
|
|
|
project_msg_components(Msg) = Components :-
|
|
(
|
|
( Msg = msg(_, Pieces)
|
|
; Msg = no_ctxt_msg(Pieces)
|
|
),
|
|
Components = [always(Pieces)]
|
|
;
|
|
Msg = simple_msg(_, Components)
|
|
;
|
|
Msg = error_msg(_, _, _, Components)
|
|
;
|
|
Msg = blank_msg(_),
|
|
Components = [always([blank_line])]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.error_sort.
|
|
%---------------------------------------------------------------------------%
|