mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/options.m:
Move --warn-simple-code to the "warnings about dodgy code"
category, as
- most of the issues that it warns about are indeed evidence
of dodgy code, and
- its existing documentation also states that it is intended
to report likely-to-be-incorrect code.
Change the internal name of --warn-simple-code, in order to force
all its existing uses to be reclassified.
Let the --warn-redundant-code part stay in the style issues category,
since the code will work just the same if the redundancies are removed.
NEWS.md:
Announce the new option.
compiler/simplify_goal_call.m:
Reclassify all uses of --warn-simple-code.
Add a missing condition in an if-then-else.
compiler/add_clause.m:
compiler/add_type.m:
compiler/check_type_inst_mode_defns.m:
compiler/convert_import_use.m:
compiler/convert_parse_tree.m:
compiler/det_analysis.m:
compiler/det_infer_goal.m:
compiler/mercury_compile_front_end.m:
compiler/mode_errors.m:
compiler/simplify_goal.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/simplify_info.m:
compiler/simplify_tasks.m:
compiler/state_var.m:
Reclassify all uses of --warn-simple-code.
tests/warnings/help_text.err_exp:
Expect the updated help text.
415 lines
18 KiB
Mathematica
415 lines
18 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2014-2017, 2019-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: simplify_tasks.m.
|
|
%
|
|
% This module handles the specification of what tasks the submodules of
|
|
% simplify.m should perform.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.simplify.simplify_tasks.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.optimization_options.
|
|
|
|
:- import_module list.
|
|
|
|
% Each value of this type represents a task, or a group of related tasks,
|
|
% that simplification should perform.
|
|
:- type simplify_task
|
|
---> simptask_warn_dodgy_simple_code
|
|
% --warn-simple-code
|
|
|
|
; simptask_warn_duplicate_calls
|
|
% --warn-duplicate-calls
|
|
|
|
; simptask_warn_implicit_stream_calls
|
|
% --warn-implicit-stream-calls
|
|
|
|
; simptask_format_calls
|
|
% Invoke format_call.m.
|
|
|
|
; simptask_warn_obsolete
|
|
% --warn-obsolete
|
|
|
|
; simptask_mark_code_model_changes
|
|
% Some compiler passes generate HLDS in which changes in code model
|
|
% are implicit in the determinisms stored in the goal_infos of
|
|
% nested goals (such as a conjunction without outputs being
|
|
% semidet, and some conjuncts being nondet). Make these code model
|
|
% changes visible by adding a scope wrapper.
|
|
|
|
; simptask_after_front_end
|
|
% Do the tasks that should be done at the end of the front end.
|
|
|
|
; simptask_excess_assigns
|
|
% Remove excess assignment unifications.
|
|
|
|
; simptask_merge_code_after_switch
|
|
% Merge the goal that occurs just after a switch into the switch,
|
|
% if we can. There are two kinds of situations in which we can
|
|
% do so. These are described by the comments on the predicates
|
|
% implementing the transforms, try_to_merge_unify_after_switch
|
|
% and try_to_merge_switch_after_switch.
|
|
|
|
; simptask_elim_removable_scopes
|
|
% Remove scopes that do not need processing during LLDS code
|
|
% generation.
|
|
|
|
; simptask_opt_duplicate_calls
|
|
% Optimize duplicate calls.
|
|
|
|
; simptask_constant_prop
|
|
% Partially evaluate calls.
|
|
|
|
; simptask_common_structs
|
|
% Common structure elimination.
|
|
|
|
; simptask_extra_common_structs
|
|
% Do common structure elimination even when it might
|
|
% increase stack usage (used by deforestation).
|
|
|
|
; simptask_try_opt_const_structs
|
|
% If the backend and the options allow it, replace unifications
|
|
% that construct constant terms with the assignment of a
|
|
% ground_term_const cons_id to the relevant variable.
|
|
|
|
; simptask_ignore_par_conjs
|
|
% Replace parallel conjunctions with plain conjunctions.
|
|
|
|
; simptask_warn_suspicious_recursion
|
|
% With simptask_warn_simple_code, we generate warnings
|
|
% for recursive calls in which all input arguments are
|
|
% the same as in the clause head. These calls are guaranteed
|
|
% to represent an infinite loop.
|
|
%
|
|
% If simptask_warn_suspicious_recursion is also set, we also
|
|
% generate a weaker version of that warning for recursive calls
|
|
% in which all *non-state-var* input arguments are the same as
|
|
% in the clause head. In the usual case where the recursion is
|
|
% controlled by the non-state-var input arguments, these calls
|
|
% also represent an infinite loop, but we cannot say that for
|
|
% certain, because in some cases, the predicate is recursing
|
|
% on a data structure that the code *does* refer to using
|
|
% state variable notation.
|
|
|
|
; simptask_warn_no_solution_disjunct
|
|
% Warn about disjuncts that can have no solution.
|
|
|
|
; simptask_split_switch_arms.
|
|
% Invoke split_switch_arms.m to perform its transformation,
|
|
% if the main part of simplification discovers that it has
|
|
% some redundant switches to optimize.
|
|
%
|
|
% For the details of the transformation done by
|
|
% split_switch_arms.m, see its top-of-module comment.
|
|
|
|
%---------------------%
|
|
|
|
:- type maybe_warn_dodgy_simple_code
|
|
---> do_not_warn_dodgy_simple_code
|
|
; warn_dodgy_simple_code.
|
|
|
|
:- type maybe_warn_duplicate_calls
|
|
---> do_not_warn_duplicate_calls
|
|
; warn_duplicate_calls.
|
|
|
|
:- type maybe_warn_implicit_streams
|
|
---> do_not_warn_implicit_streams
|
|
; warn_implicit_streams.
|
|
|
|
:- type maybe_invoke_format_call
|
|
---> do_not_invoke_format_call
|
|
; invoke_format_call.
|
|
|
|
:- type maybe_warn_obsolete
|
|
---> do_not_warn_obsolete
|
|
; warn_obsolete.
|
|
|
|
:- type maybe_mark_cm_changes
|
|
---> do_not_mark_code_model_changes
|
|
; mark_code_model_changes.
|
|
|
|
:- type maybe_after_front_end
|
|
---> not_after_front_end
|
|
; after_front_end.
|
|
|
|
:- type maybe_elim_removable_scopes
|
|
---> do_not_elim_removable_scopes
|
|
; elim_removable_scopes.
|
|
|
|
:- type maybe_opt_extra_structs
|
|
---> do_not_opt_extra_structs
|
|
; opt_extra_structs.
|
|
|
|
:- type maybe_try_opt_const_structs
|
|
---> do_not_try_opt_const_structs
|
|
; try_opt_const_structs.
|
|
|
|
:- type maybe_opt_const_structs
|
|
---> do_not_opt_const_structs
|
|
; opt_const_structs.
|
|
|
|
:- type maybe_ignore_par_conjs
|
|
---> do_not_ignore_par_conjs
|
|
; ignore_par_conjs.
|
|
|
|
:- type maybe_warn_suspicious_rec
|
|
---> do_not_warn_suspicious_rec
|
|
; warn_suspicious_rec.
|
|
|
|
:- type maybe_warn_no_soln_disjunct
|
|
---> do_not_warn_no_soln_disjunct
|
|
; warn_no_soln_disjunct.
|
|
|
|
:- type maybe_opt_split_switch_arms
|
|
---> do_not_opt_split_switch_arms
|
|
; split_opt_switch_arms.
|
|
|
|
% Each value of this type represents the full set of tasks
|
|
% that simplification should perform. The submodules of simplify.m
|
|
% use it to find out whether they should perform a specific task
|
|
% without having to search a list of simplifications.
|
|
%
|
|
% The definition of this type does not need to be visible to modules
|
|
% outside simplify.m, but avoiding such visibility would cost more
|
|
% in extra complexity than it would gain.
|
|
:- type simplify_tasks
|
|
---> simplify_tasks(
|
|
do_warn_dodgy_simple_code :: maybe_warn_dodgy_simple_code,
|
|
do_warn_duplicate_calls :: maybe_warn_duplicate_calls,
|
|
do_warn_implicit_streams :: maybe_warn_implicit_streams,
|
|
do_invoke_format_call :: maybe_invoke_format_call,
|
|
do_warn_obsolete :: maybe_warn_obsolete,
|
|
do_mark_code_model_changes :: maybe_mark_cm_changes,
|
|
do_after_front_end :: maybe_after_front_end,
|
|
do_excess_assign :: maybe_elim_excess_assigns,
|
|
do_merge_code_after_switch :: maybe_merge_code_after_switch,
|
|
do_elim_removable_scopes :: maybe_elim_removable_scopes,
|
|
do_opt_duplicate_calls :: maybe_opt_dup_calls,
|
|
do_constant_prop :: maybe_prop_constants,
|
|
do_opt_common_structs :: maybe_opt_common_structs,
|
|
do_opt_extra_structs :: maybe_opt_extra_structs,
|
|
do_try_opt_const_structs :: maybe_try_opt_const_structs,
|
|
do_opt_const_structs :: maybe_opt_const_structs,
|
|
do_ignore_par_conjunctions :: maybe_ignore_par_conjs,
|
|
do_warn_suspicious_recursion :: maybe_warn_suspicious_rec,
|
|
do_warn_no_solution_disjunct :: maybe_warn_no_soln_disjunct,
|
|
do_switch_split_arms :: maybe_split_switch_arms
|
|
).
|
|
|
|
% XXX Now that each field of the simplify_tasks structure
|
|
% has its own type and thus fields cannot be mistaken for each other,
|
|
% we should consider requiring the compiler modules that invoke
|
|
% simplification to construct a simplify_tasks structure directly,
|
|
% *without* going through simplify task list.
|
|
%
|
|
:- func simplify_tasks_to_list(simplify_tasks) = list(simplify_task).
|
|
:- func list_to_simplify_tasks(globals, list(simplify_task)) = simplify_tasks.
|
|
|
|
:- type maybe_generate_warnings
|
|
---> do_not_generate_warnings
|
|
; generate_warnings.
|
|
|
|
% Find out which simplifications should be run from the options table
|
|
% stored in the globals. The second argument states whether we should
|
|
% generate warnings during this pass of simplification.
|
|
%
|
|
:- pred find_simplify_tasks(globals::in, maybe_generate_warnings::in,
|
|
simplify_tasks::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.options.
|
|
|
|
:- import_module bool.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
simplify_tasks_to_list(SimplifyTasks) = !:List :-
|
|
SimplifyTasks = simplify_tasks(WarnDodgySimple, WarnDupCalls,
|
|
WarnImplicitStreamCalls, DoFormatCalls, WarnObsolete,
|
|
MarkCodeModelChanges, AfterFrontEnd, ExcessAssign,
|
|
MergeCodeAfterSwitch, ElimRemovableScopes,
|
|
OptDuplicateCalls, ConstantProp, OptCommonStructs, OptExtraStructs,
|
|
TryOptConstStructs, _OptConstStructs, IgnoreParConjs,
|
|
WarnSuspiciousRecursion, WarnNoSolutionDisjunct, SplitSwitchArms),
|
|
!:List = [],
|
|
( if WarnDodgySimple = warn_dodgy_simple_code
|
|
then list.cons(simptask_warn_dodgy_simple_code, !List) else true ),
|
|
( if WarnDupCalls = warn_duplicate_calls
|
|
then list.cons(simptask_warn_duplicate_calls, !List) else true ),
|
|
( if WarnImplicitStreamCalls = warn_implicit_streams
|
|
then list.cons(simptask_warn_implicit_stream_calls, !List) else true ),
|
|
( if DoFormatCalls = invoke_format_call
|
|
then list.cons(simptask_format_calls, !List) else true ),
|
|
( if WarnObsolete = warn_obsolete
|
|
then list.cons(simptask_warn_obsolete, !List) else true ),
|
|
( if MarkCodeModelChanges = mark_code_model_changes
|
|
then list.cons(simptask_mark_code_model_changes, !List) else true ),
|
|
( if AfterFrontEnd = after_front_end
|
|
then list.cons(simptask_after_front_end, !List) else true ),
|
|
( if ExcessAssign = elim_excess_assigns
|
|
then list.cons(simptask_excess_assigns, !List) else true ),
|
|
( if MergeCodeAfterSwitch = merge_code_after_switch
|
|
then list.cons(simptask_merge_code_after_switch, !List) else true ),
|
|
( if ElimRemovableScopes = elim_removable_scopes
|
|
then list.cons(simptask_elim_removable_scopes, !List) else true ),
|
|
( if OptDuplicateCalls = opt_dup_calls
|
|
then list.cons(simptask_opt_duplicate_calls, !List) else true ),
|
|
( if ConstantProp = prop_constants
|
|
then list.cons(simptask_constant_prop, !List) else true ),
|
|
( if OptCommonStructs = opt_common_structs
|
|
then list.cons(simptask_common_structs, !List) else true ),
|
|
( if OptExtraStructs = opt_extra_structs
|
|
then list.cons(simptask_extra_common_structs, !List) else true ),
|
|
( if TryOptConstStructs = try_opt_const_structs
|
|
then list.cons(simptask_try_opt_const_structs, !List) else true ),
|
|
( if IgnoreParConjs = ignore_par_conjs
|
|
then list.cons(simptask_ignore_par_conjs, !List) else true ),
|
|
( if WarnSuspiciousRecursion = warn_suspicious_rec
|
|
then list.cons(simptask_warn_suspicious_recursion, !List) else true ),
|
|
( if WarnNoSolutionDisjunct = warn_no_soln_disjunct
|
|
then list.cons(simptask_warn_no_solution_disjunct, !List) else true ),
|
|
( if SplitSwitchArms = split_switch_arms
|
|
then list.cons(simptask_split_switch_arms, !List) else true ).
|
|
|
|
list_to_simplify_tasks(Globals, List) = Tasks :-
|
|
globals.get_opt_tuple(Globals, OptTuple),
|
|
Tasks = simplify_tasks(
|
|
( if list.member(simptask_warn_dodgy_simple_code, List)
|
|
then warn_dodgy_simple_code else do_not_warn_dodgy_simple_code ),
|
|
( if list.member(simptask_warn_duplicate_calls, List)
|
|
then warn_duplicate_calls else do_not_warn_duplicate_calls ),
|
|
( if list.member(simptask_warn_implicit_stream_calls, List)
|
|
then warn_implicit_streams else do_not_warn_implicit_streams ),
|
|
( if list.member(simptask_format_calls, List)
|
|
then invoke_format_call else do_not_invoke_format_call ),
|
|
( if list.member(simptask_warn_obsolete, List)
|
|
then warn_obsolete else do_not_warn_obsolete ),
|
|
( if list.member(simptask_mark_code_model_changes, List)
|
|
then mark_code_model_changes else do_not_mark_code_model_changes ),
|
|
( if list.member(simptask_after_front_end, List)
|
|
then after_front_end else not_after_front_end ),
|
|
( if list.member(simptask_excess_assigns, List)
|
|
then elim_excess_assigns else do_not_elim_excess_assigns ),
|
|
( if list.member(simptask_merge_code_after_switch, List)
|
|
then merge_code_after_switch else do_not_merge_code_after_switch ),
|
|
( if list.member(simptask_elim_removable_scopes, List)
|
|
then elim_removable_scopes else do_not_elim_removable_scopes ),
|
|
( if list.member(simptask_opt_duplicate_calls, List)
|
|
then opt_dup_calls else do_not_opt_dup_calls ),
|
|
( if list.member(simptask_constant_prop, List)
|
|
then prop_constants else do_not_prop_constants ),
|
|
( if list.member(simptask_common_structs, List)
|
|
then opt_common_structs else do_not_opt_common_structs ),
|
|
( if list.member(simptask_extra_common_structs, List)
|
|
then opt_extra_structs else do_not_opt_extra_structs ),
|
|
( if list.member(simptask_try_opt_const_structs, List)
|
|
then try_opt_const_structs else do_not_try_opt_const_structs ),
|
|
( if
|
|
list.member(simptask_try_opt_const_structs, List),
|
|
OptTuple ^ ot_enable_const_struct_user = enable_const_struct_user
|
|
then
|
|
opt_const_structs
|
|
else
|
|
do_not_opt_const_structs
|
|
),
|
|
( if list.member(simptask_ignore_par_conjs, List)
|
|
then ignore_par_conjs else do_not_ignore_par_conjs ),
|
|
( if list.member(simptask_warn_suspicious_recursion, List)
|
|
then warn_suspicious_rec else do_not_warn_suspicious_rec ),
|
|
( if list.member(simptask_warn_no_solution_disjunct, List)
|
|
then warn_no_soln_disjunct else do_not_warn_no_soln_disjunct ),
|
|
( if list.member(simptask_split_switch_arms, List)
|
|
then split_switch_arms else do_not_split_switch_arms )
|
|
).
|
|
|
|
find_simplify_tasks(Globals, WarnThisPass, SimplifyTasks) :-
|
|
globals.lookup_bool_option(Globals, warn_dodgy_simple_code,
|
|
WarnDodgySimple),
|
|
globals.lookup_bool_option(Globals, warn_duplicate_calls, WarnDupCalls),
|
|
globals.lookup_bool_option(Globals, warn_implicit_stream_calls,
|
|
WarnImplicitStreamCalls),
|
|
globals.lookup_bool_option(Globals, warn_known_bad_format_calls,
|
|
WarnKnownBadFormat),
|
|
globals.lookup_bool_option(Globals, warn_unknown_format_calls,
|
|
WarnUnknownFormat),
|
|
globals.get_opt_tuple(Globals, OptTuple),
|
|
OptFormatCalls = OptTuple ^ ot_opt_format_calls,
|
|
( if
|
|
(
|
|
WarnThisPass = generate_warnings,
|
|
( WarnKnownBadFormat = yes ; WarnUnknownFormat = yes )
|
|
;
|
|
OptFormatCalls = opt_format_calls
|
|
)
|
|
then
|
|
InvokeFormatCall = invoke_format_call
|
|
else
|
|
InvokeFormatCall = do_not_invoke_format_call
|
|
),
|
|
globals.lookup_bool_option(Globals, warn_obsolete, WarnObsolete),
|
|
ExcessAssign = OptTuple ^ ot_elim_excess_assigns,
|
|
MergeCodeAfterSwitch = OptTuple ^ ot_merge_code_after_switch,
|
|
OptDuplicateCalls = OptTuple ^ ot_opt_dup_calls,
|
|
ConstantProp = OptTuple ^ ot_prop_constants,
|
|
MarkCodeModelChanges = do_not_mark_code_model_changes,
|
|
AfterFrontEnd = not_after_front_end,
|
|
ElimRemovableScopes = do_not_elim_removable_scopes,
|
|
CommonStructs = OptTuple ^ ot_opt_common_structs,
|
|
ExtraCommonStructs = do_not_opt_extra_structs,
|
|
TryOptConstStructs = do_not_try_opt_const_structs,
|
|
OptConstStructs = do_not_opt_const_structs,
|
|
globals.lookup_bool_option(Globals, ignore_par_conjunctions,
|
|
RemoveParConjunctions),
|
|
globals.lookup_bool_option(Globals, warn_suspicious_recursion,
|
|
WarnSuspiciousRecursion),
|
|
SplitSwitchArms = OptTuple ^ ot_split_switch_arms,
|
|
|
|
SimplifyTasks = simplify_tasks(
|
|
( if WarnDodgySimple = yes, WarnThisPass = generate_warnings
|
|
then warn_dodgy_simple_code else do_not_warn_dodgy_simple_code ),
|
|
( if WarnDupCalls = yes, WarnThisPass = generate_warnings
|
|
then warn_duplicate_calls else do_not_warn_duplicate_calls ),
|
|
( if WarnImplicitStreamCalls = yes, WarnThisPass = generate_warnings
|
|
then warn_implicit_streams else do_not_warn_implicit_streams ),
|
|
InvokeFormatCall,
|
|
( if WarnObsolete = yes, WarnThisPass = generate_warnings
|
|
then warn_obsolete else do_not_warn_obsolete ),
|
|
MarkCodeModelChanges,
|
|
AfterFrontEnd,
|
|
ExcessAssign,
|
|
MergeCodeAfterSwitch,
|
|
ElimRemovableScopes,
|
|
OptDuplicateCalls,
|
|
ConstantProp,
|
|
CommonStructs,
|
|
ExtraCommonStructs,
|
|
TryOptConstStructs,
|
|
OptConstStructs,
|
|
( if RemoveParConjunctions = yes
|
|
then ignore_par_conjs else do_not_ignore_par_conjs ),
|
|
( if WarnSuspiciousRecursion = yes
|
|
then warn_suspicious_rec else do_not_warn_suspicious_rec ),
|
|
% Warnings about "no solution disjuncts" are a category of warnings
|
|
% about simple code that happens to have its own disabling mechanism.
|
|
( if WarnDodgySimple = yes, WarnThisPass = generate_warnings
|
|
then warn_no_soln_disjunct else do_not_warn_no_soln_disjunct ),
|
|
SplitSwitchArms
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module check_hlds.simplify.simplify_tasks.
|
|
%---------------------------------------------------------------------------%
|