Files
mercury/compiler/simplify_goal_scope.m
Zoltan Somogyi 783f4b2be4 Fix singleton warnings for code with 'some [...]' goals.
The code in make_hlds_warn.m that is intended to generate singleton warnings
hasn't ever been able to handle code containing 'some [...]' goals properly.
The reason is that

- add_clause.m invokes make_hlds_warn.m only *after* it does quantification
  on the body of the clause being added to the HLDS, but

- quantification has always replaced all lists of quantified variables
  with the empty list.

This meant that

- we never could report code in which the only occurrence of a variable
  was in a list of quantified variables, which is something we *should*
  warn about, and

- we always did generate a singleton warning for code such as
  "some [Val] map.search(Map, Key, Val)", which is something we *should not*
  warn about.

This diff fixes this problem.

The main change is a mechanism that allows us to tell quantification.m
to keep lists of quantified variables intact. However, since the rest
of the compiler does not react well to these lists not being empty,
this diff

- gets make_hlds_warn.m to report whether the clause body goal, in which
  quantification.m was told to preserve any lists of quantified variables,
  *actually contained* any nonempty lists of quantified variables, and

- if it did, then we invoke quantification.m again, this time telling it
  to nuke all lists of quantified variables.

This nuking has to be done relatively rarely, because only a very small
fraction of clauses contain any explicit quantification.

(An alternative design would be for make_hlds_warn.m to always nuke
any nonempty list of quantified variables it traversed. However, this would
require *always* rebuilding the clause body goal, which would probably
be slower on average.)

The above is the main change in this diff. However, the change that is
responsible for the bulk of the diff is the addition of a flag to
exist_quant scopes to specify whether that scope was created by the user
or by the compiler. This is needed because if make_hlds_warn.m sees code
such as "some [Val] map.search(Map, Key, Val)", it definitely *should*
generate a warning about Val being singleton (if it does not occur outside
this code) if the "some [Val]" scope was put there by the compiler.

compiler/make_hlds_warn.m:
    Treat user-generated exist_quant scopes as before (the old code did
    the right thing to generate warnings, it was just given wrong inputs).
    Treat compiler-generated exist_quant scopes as if they weren't there,
    for warning-generating purposes.

    To make this distinction possible, use separate code to handle
    exist_quant and promise_solutions scopes.

    Record whether the goal traversal has seen any nonempty lists of quantified
    variables, and return this info to the caller in add_clause.m.

    Encode the nonempty nature of a list in the argument structure of a
    predicate.

    Update some obsolete terminology in variable and field names.

    Clarify the logic of some code.

compiler/quantification.m:
    Add the keep_quant/do_not_keep_quant switch described above.

    Add some documentation of the predicates to which it is applicable.

    Add free_goal_expr_vars, a version of free_goal_vars that takes
    only a goal expr, without the goal info. At one point, I thought
    this diff needed it. It does not, so the new function is not used,
    but there is also not much point in deleting it, Simplify the code
    of free_goal_vars, deleting one of its callees after inlining it
    at its only call site.

    Replace a appended-to-at-the-front-and-then-reversed list with a cord.

compiler/hlds_goal.m:
    Add the created-by-user-or-compiler flag to exist_quant scopes.

compiler/add_clause.m:
    Move the code that invokes make_hlds_warn.m to warn about singletons
    into the clauses_info_add_clause predicate, whose subcontractor
    add_clause_transform does the initial quantification. The reason
    for this move is that we have never generated singleton variable warnings
    for clauses that were read in from .opt files, or for clauses which are
    known to have syntax errors. With the new setup, if we such clauses,
    clauses_info_add_clause can, and does, tell add_clause_transform
    to tell quantification.m to nuke lists of quantified variable
    right away. It is only for the clauses we *can* warn about
    that clauses_info_add_clause will tell add_clause_transform
    to keep those variables, and will then itself invoke the code
    in make_hlds_warn.m that warns about singletons, followed, if needed,
    by a var-list-nuking reinvocation of quantification.

    This centralization of the code relevant to warning code in
    clauses_info_add_clause also allows the deletion of several of its
    output arguments, since its two callers used those arguments
    only to invoke the warning-generation code. It also eliminates
    the duplication of code in those two callers.

compiler/instance_method_clauses.m:
    Conform to the change in add_clause.m.

compiler/add_foreign_proc.m:
compiler/assertion.m:
compiler/constraint.m:
compiler/cse_detection.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/goal_util.m:
compiler/hlds_desc.m:
compiler/hlds_out_goal.m:
compiler/interval.m:
compiler/lambda.m:
compiler/mark_tail_calls.m:
compiler/ml_code_gen.m:
compiler/mode_constraints.m:
compiler/modecheck_goal.m:
compiler/polymorphism_goal.m:
compiler/pre_quantification.m:
compiler/purity.m:
compiler/saved_vars.m:
compiler/simplify_goal_scope.m:
compiler/simplify_proc.m:
compiler/state_var.m:
compiler/stm_expand.m:
compiler/superhomogeneous.m:
compiler/switch_detection.m:
compiler/try_expand.m:
compiler/typecheck.m:
compiler/unique_modes.m:
    Conform to the change in hlds_goal.m and/or quantification.m.

compiler/options.m:
    Add a way to detect the presence of this fix in the installed compiler.

tests/valid/Mmakefile:
    Enable the old test case for this problem, some_singleton,
    which we haven't passed until now.

tests/warnings/Mmakefile:
    Enable the missing_singleton_warning test case, which we haven't passed
    until now.
2023-06-10 09:59:00 +02:00

607 lines
25 KiB
Mathematica

%----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%----------------------------------------------------------------------------%
% Copyright (C) 2014 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_goal_scope.m.
%
% This module handles simplification of scope goals.
%
%----------------------------------------------------------------------------%
:- module check_hlds.simplify.simplify_goal_scope.
:- interface.
:- import_module check_hlds.simplify.common.
:- import_module check_hlds.simplify.simplify_info.
:- import_module hlds.
:- import_module hlds.hlds_goal.
:- import_module hlds.instmap.
% Handle simplification of scope goals.
%
:- pred simplify_goal_scope(
hlds_goal_expr::in(goal_expr_scope), hlds_goal_expr::out,
hlds_goal_info::in, hlds_goal_info::out,
simplify_nested_context::in, instmap::in,
common_info::in, common_info::out,
simplify_info::in, simplify_info::out) is det.
% If the goal nested inside this scope goal is another scope goal,
% then merge the two scopes, if this is possible. Repeat for as many
% nested scopes as possible.
%
:- pred try_to_merge_nested_scopes(scope_reason::in, hlds_goal::in,
hlds_goal_info::in, hlds_goal::out) is det.
%----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.simplify.simplify_goal.
:- import_module check_hlds.simplify.simplify_tasks.
:- import_module hlds.const_struct.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_module.
:- import_module hlds.make_goal.
:- import_module hlds.pred_table.
:- import_module libs.
:- import_module libs.globals.
:- import_module libs.optimization_options.
:- import_module libs.options.
:- import_module libs.trace_params.
:- import_module mdbcomp.
:- import_module mdbcomp.builtin_modules.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_foreign.
:- import_module parse_tree.var_table.
:- import_module bool.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module pair.
:- import_module require.
:- import_module set.
simplify_goal_scope(GoalExpr0, GoalExpr, GoalInfo0, GoalInfo,
NestedContext0, InstMap0, Common0, Common, !Info) :-
GoalExpr0 = scope(Reason0, SubGoal0),
( if Reason0 = from_ground_term(TermVar, from_ground_term_construct) then
simplify_info_get_module_info(!.Info, ModuleInfo0),
module_info_get_const_struct_db(ModuleInfo0, ConstStructDb0),
const_struct_db_get_ground_term_enabled(ConstStructDb0,
ConstStructEnabled),
(
ConstStructEnabled = do_not_enable_const_struct_user,
module_info_get_globals(ModuleInfo0, Globals),
globals.get_opt_tuple(Globals, OptTuple),
CommonStruct = OptTuple ^ ot_opt_common_structs,
(
CommonStruct = opt_common_structs,
% Traversing the construction unifications inside the scope
% would allow common.m to
%
% - replace some of those constructions with references to
% other variables that were constructed the same way, and
% - remember those constructions, so that other constructions
% outside the scope could be replaced with references to
% variables built inside the scope.
%
% Since unifying a variable with a statically constructed
% ground term yields code that is at least as fast as unifying
% that variable with another variable that is already bound to
% that term, and probably faster because it does not require
% saving the other variable across calls, neither of these
% actions would be an advantage. On the other hand, both would
% complicate the required treatment of
% from_ground_term_construct scopes in liveness.m, slowing down
% the liveness pass, as well as this pass. Since the code
% inside the scope is already as simple as it can be, we
% leave it alone.
GoalExpr = GoalExpr0,
GoalInfo = GoalInfo0,
Common = Common0
;
CommonStruct = do_not_opt_common_structs,
% Looking inside the scope may allow us to reduce the number of
% memory cells we may need to allocate dynamically. This
% improvement in the generated code trumps the cost in compile
% time. However, we need to update the reason, since leaving it
% as from_ground_term_construct would tell liveness.m that the
% code inside the scope hasn't had either of the actions
% mentioned in the comment above applied to it, and in this
% case, we cannot guarantee that.
simplify_goal(SubGoal0, SubGoal, NestedContext0, InstMap0,
Common0, Common, !Info),
NewReason = from_ground_term(TermVar, from_ground_term_other),
GoalExpr = scope(NewReason, SubGoal),
GoalInfo = GoalInfo0
)
;
ConstStructEnabled = enable_const_struct_user,
( if
SubGoal0 = hlds_goal(SubGoalExpr, _),
SubGoalExpr = conj(plain_conj, Conjuncts),
Conjuncts = [HeadConjunctPrime | TailConjunctsPrime]
then
HeadConjunct = HeadConjunctPrime,
TailConjuncts = TailConjunctsPrime
else
unexpected($pred,
"from_ground_term_construct scope is not conjunction")
),
simplify_info_get_var_table(!.Info, VarTable),
simplify_info_get_defined_where(!.Info, DefinedWhere),
simplify_construct_ground_terms(DefinedWhere, VarTable, TermVar,
HeadConjunct, TailConjuncts, [], ElimVars,
map.init, VarArgMap, ConstStructDb0, ConstStructDb),
module_info_set_const_struct_db(ConstStructDb,
ModuleInfo0, ModuleInfo),
simplify_info_add_elim_vars(ElimVars, !Info),
simplify_info_set_module_info(ModuleInfo, !Info),
map.to_assoc_list(VarArgMap, VarArgs),
( if
VarArgs = [TermVar - TermArg],
TermArg = csa_const_struct(TermConstNumPrime)
then
TermConstNum = TermConstNumPrime
else
unexpected($pred, "unexpected VarArgMap")
),
lookup_const_struct_num(ConstStructDb, TermConstNum,
TermConstStruct),
TermConsId = TermConstStruct ^ cs_cons_id,
ConsId = ground_term_const(TermConstNum, TermConsId),
RHS = rhs_functor(ConsId, is_not_exist_constr, []),
Unification = construct(TermVar, ConsId, [], [],
construct_statically(born_static), cell_is_shared,
no_construct_sub_info),
InstMapDelta = goal_info_get_instmap_delta(GoalInfo0),
instmap_delta_lookup_var(InstMapDelta, TermVar, TermInst),
UnifyMode = unify_modes_li_lf_ri_rf(free, TermInst,
TermInst, TermInst),
UnifyContext = unify_context(umc_explicit, []),
GoalExpr = unify(TermVar, RHS, UnifyMode, Unification,
UnifyContext),
GoalInfo = GoalInfo0,
Common = Common0
)
else
( if Reason0 = disable_warnings(HeadWarning, TailWarnings) then
simplify_info_get_simplify_tasks(!.Info, Tasks0),
list.foldl(disable_simplify_warning,
[HeadWarning | TailWarnings], Tasks0, ScopeTasks),
simplify_info_set_simplify_tasks(ScopeTasks, !Info),
simplify_goal(SubGoal0, SubGoal, NestedContext0, InstMap0,
Common0, Common1, !Info),
simplify_info_set_simplify_tasks(Tasks0, !Info)
else
simplify_goal(SubGoal0, SubGoal, NestedContext0, InstMap0,
Common0, Common1, !Info)
),
try_to_merge_nested_scopes(Reason0, SubGoal, GoalInfo0, Goal1),
Goal1 = hlds_goal(GoalExpr1, _GoalInfo1),
( if GoalExpr1 = scope(FinalReason, FinalSubGoal) then
(
( FinalReason = disable_warnings(_, _)
; FinalReason = promise_purity(_)
; FinalReason = from_ground_term(_, _)
; FinalReason = barrier(removable)
),
Goal = Goal1,
Common = Common1
;
( FinalReason = require_detism(_)
; FinalReason = require_complete_switch(_)
; FinalReason = require_switch_arms_detism(_, _)
),
% The scope has served its purpose, and it is not needed
% anymore.
Goal = FinalSubGoal,
Common = Common1
;
( FinalReason = exist_quant(_, _)
; FinalReason = commit(_)
; FinalReason = promise_solutions(_, _)
; FinalReason = barrier(not_removable)
; FinalReason = loop_control(_, _, _)
),
Goal = Goal1,
% Replacing calls, constructions or deconstructions outside
% a commit with references to variables created inside the
% commit would increase the set of output variables of the goal
% inside the commit. This is not allowed because it could
% change the determinism.
%
% Thus we need to reset the common_info to what it was before
% processing the goal inside the commit, to ensure that we
% don't make any such replacements when processing the rest
% of the goal.
%
% We do the same for several other kinds of scopes from which
% we do not want to "export" common unifications.
Common = Common0
;
FinalReason = trace_goal(MaybeCompiletimeExpr,
MaybeRuntimeExpr, _, _, _),
( if simplify_do_after_front_end(!.Info) then
simplify_goal_trace_goal(MaybeCompiletimeExpr,
MaybeRuntimeExpr, FinalSubGoal, Goal1, Goal, !Info)
else
Goal = Goal1
),
% We throw away the updated Common1 for the same reason
% as in the case above: we don't want to add any outputs
% to the trace_goal scope, since such scopes should not
% have ANY outputs.
Common = Common0
)
else
Goal = Goal1,
Common = Common1
),
Goal = hlds_goal(GoalExpr, GoalInfo)
).
:- pred disable_simplify_warning(goal_warning::in,
simplify_tasks::in, simplify_tasks::out) is det.
disable_simplify_warning(Warning, !Tasks) :-
(
Warning = goal_warning_singleton_vars
% Warning about singleton vars is done when clauses are added
% to the HLDS, not during simplification.
;
Warning = goal_warning_occurs_check
% Warning about occurs check violations is done during the creation
% of the HLDS, not during simplification.
;
Warning = goal_warning_non_tail_recursive_calls
% Warning about non-tail-recursive calls is done during
% code generation, not during simplification. (What calls
% are tail recursive depends on the backend.)
;
Warning = goal_warning_suspicious_recursion,
!Tasks ^ do_warn_suspicious_recursion := do_not_warn_suspicious_rec
;
Warning = goal_warning_no_solution_disjunct,
!Tasks ^ do_warn_no_solution_disjunct := do_not_warn_no_soln_disjunct
;
Warning = goal_warning_unknown_format_calls
% Unknown format warnings are generated by format_calls.m, which
% does its own traversal of the procedure body. Therefore that warning
% needs to be disabled during *that* traversal, not during the
% traversal that our caller is doing.
).
%-----------------------------------------------------------------------------%
:- type var_to_arg_map == map(prog_var, const_struct_arg).
:- pred simplify_construct_ground_terms(defined_where::in, var_table::in,
prog_var::in, hlds_goal::in, list(hlds_goal)::in,
list(prog_var)::in, list(prog_var)::out,
var_to_arg_map::in, var_to_arg_map::out,
const_struct_db::in, const_struct_db::out) is det.
simplify_construct_ground_terms(DefinedWhere, VarTable, TermVar,
Conjunct, Conjuncts, !ElimVars, !VarArgMap, !ConstStructDb) :-
Conjunct = hlds_goal(GoalExpr, GoalInfo),
( if
GoalExpr = unify(_, _, _, Unify, _),
Unify = construct(LHSVarPrime, ConsIdPrime, RHSVarsPrime, _, _, _, _)
then
LHSVar = LHSVarPrime,
ConsId = ConsIdPrime,
RHSVars = RHSVarsPrime
else
unexpected($pred, "not construction unification")
),
lookup_var_type(VarTable, LHSVar, TermType),
(
RHSVars = [],
Arg = csa_constant(ConsId, TermType)
;
RHSVars = [_ | _],
list.map_foldl(map.det_remove, RHSVars, RHSArgs, !VarArgMap),
InstMapDelta = goal_info_get_instmap_delta(GoalInfo),
instmap_delta_lookup_var(InstMapDelta, LHSVar, TermInst),
ConstStruct = const_struct(ConsId, RHSArgs, TermType, TermInst,
DefinedWhere),
lookup_insert_const_struct(ConstStruct, ConstNum, !ConstStructDb),
Arg = csa_const_struct(ConstNum)
),
map.det_insert(LHSVar, Arg, !VarArgMap),
(
Conjuncts = [],
expect(unify(TermVar, LHSVar), $pred, "last var is not TermVar")
;
Conjuncts = [HeadConjunct | TailConjuncts],
!:ElimVars = [LHSVar | !.ElimVars],
simplify_construct_ground_terms(DefinedWhere, VarTable, TermVar,
HeadConjunct, TailConjuncts,
!ElimVars, !VarArgMap, !ConstStructDb)
).
%---------------------------------------------------------------------------%
:- pred simplify_goal_trace_goal(maybe(trace_expr(trace_compiletime))::in,
maybe(trace_expr(trace_runtime))::in, hlds_goal::in, hlds_goal::in,
hlds_goal::out, simplify_info::in, simplify_info::out) is det.
simplify_goal_trace_goal(MaybeCompiletimeExpr, MaybeRuntimeExpr, SubGoal,
Goal0, Goal, !Info) :-
(
MaybeCompiletimeExpr = yes(CompiletimeExpr),
KeepGoal = evaluate_compile_time_condition(CompiletimeExpr, !.Info)
;
MaybeCompiletimeExpr = no,
% A missing compile time condition means that the
% trace goal is always compiled in.
KeepGoal = yes
),
(
KeepGoal = no,
Goal0 = hlds_goal(_GoalExpr0, GoalInfo0),
Context = goal_info_get_context(GoalInfo0),
Goal = true_goal_with_context(Context),
simplify_info_get_deleted_call_callees(!.Info, DeletedCallCallees0),
SubGoalCalledProcs = goal_proc_refs(SubGoal),
set.union(SubGoalCalledProcs,
DeletedCallCallees0, DeletedCallCallees),
simplify_info_set_deleted_call_callees(DeletedCallCallees, !Info)
;
KeepGoal = yes,
(
MaybeRuntimeExpr = no,
% We keep the scope as a marker of the existence of the
% trace scope.
Goal = Goal0
;
KeepGoal = yes,
MaybeRuntimeExpr = yes(RuntimeExpr),
% We want to execute SubGoal if and only if RuntimeExpr turns out
% to be true. We could have the code generators treat this kind of
% scope as if it were an if-then-else, but that would require
% duplicating most of the code required to handle code generation
% for if-then-elses. Instead, we transform the scope into an
% if-then-else, thus reducing the problem to one that has already
% been solved.
%
% The evaluation of the runtime condition is done as a special kind
% of foreign_proc, i.e. one that has yes(RuntimeExpr) as its
% foreign_trace_cond field. This kind of foreign_proc also acts
% as the marker for the fact that the then-part originated as
% the goal of a trace scope.
simplify_info_get_module_info(!.Info, ModuleInfo),
module_info_get_globals(ModuleInfo, Globals),
globals.get_target(Globals, Target),
PrivateBuiltin = mercury_private_builtin_module,
EvalPredName = "trace_evaluate_runtime_condition",
some [!EvalAttributes] (
(
Target = target_c,
!:EvalAttributes = default_attributes(lang_c)
;
Target = target_java,
!:EvalAttributes = default_attributes(lang_java)
;
Target = target_csharp,
!:EvalAttributes = default_attributes(lang_csharp)
),
set_may_call_mercury(proc_will_not_call_mercury,
!EvalAttributes),
set_thread_safe(proc_thread_safe, !EvalAttributes),
set_purity(purity_semipure, !EvalAttributes),
set_terminates(proc_terminates, !EvalAttributes),
set_may_throw_exception(proc_will_not_throw_exception,
!EvalAttributes),
set_may_modify_trail(proc_will_not_modify_trail,
!EvalAttributes),
set_may_call_mm_tabled(proc_will_not_call_mm_tabled,
!EvalAttributes),
EvalAttributes = !.EvalAttributes
),
EvalFeatures = [],
% The code field of the call_foreign_proc goal is ignored when
% its foreign_trace_cond field is set to `yes', as we do here.
EvalCode = "",
Goal0 = hlds_goal(_GoalExpr0, GoalInfo0),
Context = goal_info_get_context(GoalInfo0),
generate_call_foreign_proc(ModuleInfo, pf_predicate,
PrivateBuiltin, EvalPredName,
[], [], [], instmap_delta_bind_no_var, only_mode,
detism_semi, purity_semipure, EvalFeatures, EvalAttributes,
yes(RuntimeExpr), EvalCode, Context, CondGoal),
GoalExpr = if_then_else([], CondGoal, SubGoal, true_goal),
Goal = hlds_goal(GoalExpr, GoalInfo0)
)
).
:- func evaluate_compile_time_condition(trace_expr(trace_compiletime),
simplify_info) = bool.
evaluate_compile_time_condition(TraceExpr, Info) = Result :-
(
TraceExpr = trace_base(BaseExpr),
Result = evaluate_compile_time_condition_comptime(BaseExpr, Info)
;
TraceExpr = trace_not(ExprA),
ResultA = evaluate_compile_time_condition(ExprA, Info),
Result = bool.not(ResultA)
;
TraceExpr = trace_op(Op, ExprA, ExprB),
ResultA = evaluate_compile_time_condition(ExprA, Info),
ResultB = evaluate_compile_time_condition(ExprB, Info),
(
Op = trace_or,
Result = bool.or(ResultA, ResultB)
;
Op = trace_and,
Result = bool.and(ResultA, ResultB)
)
).
:- func evaluate_compile_time_condition_comptime(trace_compiletime,
simplify_info) = bool.
evaluate_compile_time_condition_comptime(CompTime, Info) = Result :-
simplify_info_get_module_info(Info, ModuleInfo),
module_info_get_globals(ModuleInfo, Globals),
(
CompTime = trace_flag(FlagName),
globals.lookup_accumulating_option(Globals, trace_goal_flags, Flags),
( if list.member(FlagName, Flags) then
Result = yes
else
Result = no
)
;
CompTime = trace_grade(Grade),
(
Grade = trace_grade_debug,
globals.lookup_bool_option(Globals, exec_trace, Result)
;
Grade = trace_grade_ssdebug,
globals.lookup_bool_option(Globals, source_to_source_debug, Result)
% XXX Should we take into account force_disable_ssdebug as well?
;
Grade = trace_grade_prof,
globals.lookup_bool_option(Globals, profile_calls, ProfCalls),
globals.lookup_bool_option(Globals, profile_time, ProfTime),
globals.lookup_bool_option(Globals, profile_memory, ProfMem),
bool.or_list([ProfCalls, ProfTime, ProfMem], Result)
;
Grade = trace_grade_profdeep,
globals.lookup_bool_option(Globals, profile_deep, Result)
;
Grade = trace_grade_par,
globals.lookup_bool_option(Globals, parallel, Result)
;
Grade = trace_grade_trail,
globals.lookup_bool_option(Globals, use_trail, Result)
;
Grade = trace_grade_rbmm,
globals.lookup_bool_option(Globals, use_regions, Result)
;
Grade = trace_grade_llds,
globals.lookup_bool_option(Globals, highlevel_code, NotResult),
bool.not(NotResult, Result)
;
Grade = trace_grade_mlds,
globals.lookup_bool_option(Globals, highlevel_code, Result)
;
Grade = trace_grade_c,
globals.get_target(Globals, Target),
( if Target = target_c then
Result = yes
else
Result = no
)
;
Grade = trace_grade_csharp,
globals.get_target(Globals, Target),
( if Target = target_csharp then
Result = yes
else
Result = no
)
;
Grade = trace_grade_java,
globals.get_target(Globals, Target),
( if Target = target_java then
Result = yes
else
Result = no
)
)
;
CompTime = trace_trace_level(RequiredLevel),
simplify_info_get_eff_trace_level_optimized(Info, EffTraceLevel, _),
(
RequiredLevel = trace_level_shallow,
Result = at_least_at_shallow(EffTraceLevel)
;
RequiredLevel = trace_level_deep,
Result = at_least_at_deep(EffTraceLevel)
)
).
%---------------------------------------------------------------------------%
try_to_merge_nested_scopes(Reason0, InnerGoal0, OuterGoalInfo, Goal) :-
loop_over_any_nested_scopes(Reason0, Reason, InnerGoal0, InnerGoal),
InnerGoal = hlds_goal(_, GoalInfo),
( if
Reason = exist_quant(_, _),
Detism = goal_info_get_determinism(GoalInfo),
OuterDetism = goal_info_get_determinism(OuterGoalInfo),
Detism = OuterDetism
then
% If the inner and outer detisms match, then we do not need
% the `some' scope.
Goal = InnerGoal
else
Goal = hlds_goal(scope(Reason, InnerGoal), OuterGoalInfo)
).
:- pred loop_over_any_nested_scopes(scope_reason::in, scope_reason::out,
hlds_goal::in, hlds_goal::out) is det.
loop_over_any_nested_scopes(Reason0, Reason, Goal0, Goal) :-
( if
Goal0 = hlds_goal(scope(Reason1, Goal1), _),
( if
Reason0 = exist_quant(Vars0, _),
Reason1 = exist_quant(Vars1, _)
then
Reason2 = exist_quant(Vars0 ++ Vars1, compiler_quant)
else if
Reason0 = barrier(Removable0),
Reason1 = barrier(Removable1)
then
( if
Removable0 = removable,
Removable1 = removable
then
Removable2 = removable
else
Removable2 = not_removable
),
Reason2 = barrier(Removable2)
else if
Reason0 = commit(ForcePruning0),
Reason1 = commit(ForcePruning1)
then
( if
ForcePruning0 = dont_force_pruning,
ForcePruning1 = dont_force_pruning
then
ForcePruning2 = dont_force_pruning
else
ForcePruning2 = force_pruning
),
Reason2 = commit(ForcePruning2)
else
fail
)
then
loop_over_any_nested_scopes(Reason2, Reason, Goal1, Goal)
else
Reason = Reason0,
Goal = Goal0
).
%---------------------------------------------------------------------------%
:- end_module check_hlds.simplify.simplify_goal_scope.
%---------------------------------------------------------------------------%