Files
mercury/compiler/prop_mode_constraints.m
Zoltan Somogyi 656493dfdf Use separate types for the status of different entity kinds.
We used the old import_status type to represent the status of six different
kinds of entities:

- types
- insts
- modes
- typeclasses
- instances
- predicates

even though some statuses that made sense for one kind of entity didn't for
another another (e.g. predicates can be pseudo imported/exported, but the
other five kinds of entities cannot).

Create the new types type_status, inst_status, ..., pred_status to represent
the status of these entities in the HLDS. For now, these are just wrappers
around the renamed old_import_status type, but I plan to replace them with
status types that *are* specialized to the applicable kind of entity,
along the lines of compiler/notes/status_proposal. This is a necessary
first step towards that proposal.

compiler/status.m:
    Define the six new entity-kind-specific status types, and replicate
    the test predicates that used to work on the import_status type
    to work on these instead.

    Define a status type, item_mercury_status, that contains just the info
    that is common to all entities in an item block, for use during
    the process of adding items to the HLDS.

    Move the predicates that converted section markers to statuses
    from here to make_hlds_passes.m, since that is the only place
    where they are used, or can be used.

    Move the combine_status predicate here from add_type.m, since
    it is needed for combining the statuses of other kinds of entities
    as well, not just types.

compiler/hlds_data.m:
    Change the HLDS types that record the information we have about
    types, du type fields, insts, modes, typeclasses and instances
    to have kind-specific status fields, instead of the old generic
    import_status type.

    Change the prefix on the field names of the hlds_instance_defn type
    to avoid a name clash, and to make them more meaningful.

    Change the prefix on the field names of the hlds_class_defn type
    to make them more meaningful.

compiler/hlds_pred.m:
    Change the HLDS type that records the information we have about predicates
    to have a kind-specific status field, instead of the old generic
    import_status type.

    Update the predicates that test predicate statuses accordingly.

compiler/hlds_module.m:
    Change the HLDS types that record the information we have about
    type constructors to be type_status, not the old generic import_status.

compiler/make_hlds_passes.m:
    As we process each item block, pass along an item_mercury_status
    instead of an import_status. The code used to use only a subset
    of the possible values of the import_status type, since we can never say
    that all the entities in an item block are e.g. pseudo-exported.
    An item_mercury_status has just the information we actually *know*
    about the item block as a whole. We convert the item_mercury_status
    to a kind-specific status if and when we need to, but for several purposes,
    the item_mercury_status is enough on its own.

    In a few cases, add a new predicate to do this conversion.

    Pass the need_qualifier flag separately from the status. It is needed
    in only a few places, but this was not apparent when we always passed it
    around paired with the import_status.

    Move the predicates that converted section markers to statuses
    to here from status.m, since here is the only place where they are used,
    or can be used.

compiler/add_class.m:
    Convert the statuses of typeclasses and instances to the statuses
    of the predicates implementing their virtual and concrete methods.

compiler/check_typeclass.m:
    Simplify some over-complex code.

compiler/add_special_pred.m:
    Convert the statuses of types to the statuses of the predicates
    implementing their unify, index, compare and solver init operations.
    Note some places where the process of this conversion is (to say the least)
    unclear and undocumented.

compiler/hlds_out_util.m:
    Provide utility predicates to print all the new kinds of statuses.
    These replace the old predicate that did the same in hlds_out_pred.m,
    but printing e.g. type statuses in hlds_out_pred doesn't seem right.

compiler/intermod.m:
    Conform to the changes above.

    Consistently use switches on the booleans returned by xxx_status_to_write,
    instead wrapping a semidet predicate around it and calling that.
    The switches yield code that is both smaller and more maintainable.

compiler/make_hlds_error.m:
    Conform to the changes above.

    Delete a simple wrapper predicate that was used only in one place.
    That place now does the wrapping itself.

compiler/qual_info.m:
    Replace the import_status field in the qual_info with a simple
    is_opt_imported/is_not_opt_imported flag, since that was the only
    thing we used the import_status field for.

compiler/accumulator.m:
compiler/add_clause.m:
compiler/add_foreign_enum.m:
compiler/add_foreign_proc.m:
compiler/add_mode.m:
compiler/add_mutable_aux_preds.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_solver.m:
compiler/add_type.m:
compiler/base_typeclass_info.m:
compiler/ctgc.util.m:
compiler/dead_proc_elim.m:
compiler/dep_par_conj.m:
compiler/dependency_graph.m:
compiler/det_report.m:
compiler/elds_to_erlang.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/export.m:
compiler/float_regs.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_out_module.m:
compiler/hlds_out_pred.m:
compiler/inst_check.m:
compiler/lambda.m:
compiler/lco.m:
compiler/make_hlds.m:
compiler/make_hlds_warn.m:
compiler/make_tags.m:
compiler/ml_proc_gen.m:
compiler/ml_type_gen.m:
compiler/mode_errors.m:
compiler/oisu_check.m:
compiler/par_loop_control.m:
compiler/polymorphism.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/prop_mode_constraints.m:
compiler/recompilation.usage.m:
compiler/simplify_proc.m:
compiler/smm_common.m:
compiler/special_pred.m:
compiler/ssdebug.m:
compiler/status.m:
compiler/stm_expand.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.versions.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_initial.m:
compiler/term_constr_main.m:
compiler/termination.m:
compiler/trace_params.m:
compiler/type_class_info.m:
compiler/type_constraints.m:
compiler/type_ctor_info.m:
compiler/typecheck.m:
compiler/typecheck_info.m:
compiler/typeclasses.m:
compiler/unify_proc.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
    Conform to the changes above.
2015-09-12 09:07:45 +10:00

570 lines
25 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2004-2012 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: prop_mode_constraints.m.
% Main author: richardf.
%
% XXX This module essentially serves as interface between the old
% mode_constraints module (by dmo) and the new abstract_mode_constraints
% and build_mode_constraints modules (by richardf). Ultimately its contents
% should probably be moved into those modules respectively.
%
%-----------------------------------------------------------------------------%
:- module check_hlds.prop_mode_constraints.
:- interface.
:- import_module check_hlds.abstract_mode_constraints.
:- import_module check_hlds.build_mode_constraints.
:- import_module hlds.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module mdbcomp.
:- import_module mdbcomp.goal_path.
:- import_module io.
:- import_module list.
:- import_module map.
%-----------------------------------------------------------------------------%
% Maps each predicate to information about its goal ids and its mode
% constraint.
:- type pred_constraints_map ==
map(pred_id, {containing_goal_map, mode_constraints}).
%-----------------------------------------------------------------------------%
% prop_mode_constraints_in_scc(SCC, !ModuleInfo, !VarSet, !VarMap,
% !PredConstraintsMap):
%
% For each predicate in SCC:
%
% - Add producer/consumer constraints to PredConstraintsMap.
% - Add goal path annotations to its clauses in ModuleInfo.
% - Add any constraint variables it requires to VarSet and VarMap.
%
:- pred prop_mode_constraints_in_scc(list(pred_id)::in,
module_info::in, module_info::out, mc_var_info::in, mc_var_info::out,
pred_constraints_map::in, pred_constraints_map::out) is det.
% ensure_unique_arguments(PredId, !ModuleInfo):
%
% Creates variables and introduces unifications in predicate PredId where
% appropriate to ensure that no program variable is used as an argument of
% more than one predicate (including the head of the caller, PredId).
%
:- pred ensure_unique_arguments(pred_id::in, module_info::in, module_info::out)
is det.
% Check whether a predicate has been imported according to the
% status_is_imported pred in the hlds_pred module.
%
:- pred module_info_pred_status_is_imported(module_info::in, pred_id::in)
is semidet.
% Write in human readable form to the current output stream
% the information in the pred_constraints_map, indicating which
% predicate each set of constraints applies to.
%
:- pred pretty_print_pred_constraints_map(module_info::in, mc_varset::in,
pred_constraints_map::in, io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.goal_path.
:- import_module hlds.hlds_args.
:- import_module hlds.hlds_clauses.
:- import_module hlds.hlds_error_util.
:- import_module hlds.hlds_goal.
:- import_module hlds.make_goal.
:- import_module hlds.status.
:- import_module hlds.vartypes.
:- import_module parse_tree.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.set_of_var.
:- import_module bool.
:- import_module require.
:- import_module string.
:- import_module term.
:- import_module varset.
%-----------------------------------------------------------------------------%
prop_mode_constraints_in_scc(SCC0, !ModuleInfo, !VarInfo, !Constraints) :-
% Process only predicates from this module.
list.filter(module_info_pred_status_is_imported(!.ModuleInfo),
SCC0, _, SCC),
% Prepare the solver variables for the home path of each predicate
% of the SCC - needed for calls to predicates in the same SCC
% that do not have mode declarations.
add_mc_vars_for_scc_heads(!.ModuleInfo, SCC, !VarInfo),
% Now go through the SCC and add the constraint
% variables and then constraints predicate by predicate
list.foldl3(prop_mode_constraints_in_pred, SCC,
!ModuleInfo, !VarInfo, !Constraints).
% prop_mode_constraints_in_pred(PredId, !ModuleInfo, !VarSet, !VarMap,
% !Constraints):
%
% Performs a number of tasks for predicate PredId:
% 1) Fill out the goal_id information in the ModuleInfo structure.
% 2) Add producer/consumer constraint variables for program
% variables corresponding to any location at which they are
% nonlocal to VarSet and VarMap. (Elsewhere is is clear as to
% whether they are produced or consumed.)
% 3) Add mode declaration constraints to Constraints.
% 4) Add goal constraints to Constraints.
%
% NOTE: This relies on the head variables for any predicate without mode
% declarations that is called by this one (PredId) to have the constraint
% variables corresponding to the empty goal path (i.e. the whole body
% of the predicate) to already be VarMap (and therefore also in VarSet).
%
:- pred prop_mode_constraints_in_pred(pred_id::in,
module_info::in, module_info::out, mc_var_info::in, mc_var_info::out,
pred_constraints_map::in, pred_constraints_map::out) is det.
prop_mode_constraints_in_pred(PredId, !ModuleInfo, !VarInfo, !Constraints) :-
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
do_prop_mode_constraints_in_pred(!.ModuleInfo, PredId, PredInfo0, PredInfo,
!VarInfo, !Constraints),
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo).
% The working part of prop_mode_constraints_in_pred/8, with the pred_info
% unpacked from the ModuleInfo.
%
:- pred do_prop_mode_constraints_in_pred(module_info::in, pred_id::in,
pred_info::in, pred_info::out, mc_var_info::in, mc_var_info::out,
pred_constraints_map::in, pred_constraints_map::out) is det.
do_prop_mode_constraints_in_pred(ModuleInfo, PredId, !PredInfo, !VarInfo,
!PredConstraintsMap) :-
% XXX Currently the constraints simply say that if a variable is bound
% at a disjunct it is bound at the disjunction by making the relevant
% variables equivalent. Setting GoalPathOptimisation to yes will cause
% the disjucts to be given the same path as the disjunction, so that
% the relevant constraint variables will not need to be constrained
% equivalent - they will be the same variable. It will do the same
% for other path types with similar equivalence constraints -
% refer to the goal_path module for a more detailed description.
% GoalPathOptimisation = no.
%
% XXX The above comment is obsolete, in that the current version of the
% goal_path module leaves the task of making the relevant variables
% equivalent to THIS module.
pred_info_get_clauses_info(!.PredInfo, ClausesInfo0),
fill_goal_id_slots_in_clauses(ModuleInfo, ContainingGoalMap,
ClausesInfo0, ClausesInfo),
pred_info_set_clauses_info(ClausesInfo, !PredInfo),
% If mode inference requested, just add constraints for the clause body,
% otherwise, process the predicate for each of the procedures.
( pred_info_infer_modes(!.PredInfo) ->
add_clauses_constraints(ModuleInfo, PredId, !.PredInfo, !VarInfo,
init_pred_p_c_constraints, BodyConstraints)
;
prop_mode_constraints_in_mode_declared_pred(ModuleInfo, PredId,
!.PredInfo, !VarInfo, BodyConstraints)
),
map.set(PredId, {ContainingGoalMap, BodyConstraints},
!PredConstraintsMap).
% prop_mode_constraints_in_mode_declared_pred(ModuleInfo, PredId, PredInfo,
% !VarInfo, FullConstraints):
%
% Uses the clauses and mode declarations in PredInfo (which should be
% for predicate PredId taken from ModuleInfo) to create producer/consumer
% constraints for program variables in predicate PredId. VarInfo is updated
% with any constraint variables used.
%
:- pred prop_mode_constraints_in_mode_declared_pred(module_info::in,
pred_id::in, pred_info::in, mc_var_info::in, mc_var_info::out,
mode_constraints::out) is det.
prop_mode_constraints_in_mode_declared_pred(ModuleInfo, PredId, PredInfo,
!VarInfo, FullConstraints) :-
ProcIds = pred_info_all_procids(PredInfo),
add_clauses_constraints(ModuleInfo, PredId, PredInfo, !VarInfo,
init_pred_p_c_constraints, BodyConstr),
% Store procedure specific constraints in the constraints structure
list.map(pred_info_proc_info(PredInfo), ProcIds, ProcInfos),
list.foldl2_corresponding(
prop_mode_constraints_in_mode_declared_proc(ModuleInfo, PredId),
ProcIds, ProcInfos, !VarInfo, BodyConstr, FullConstraints).
% prop_mode_constraints_in_mode_declared_proc(ModuleInfo, PredId, ProcId,
% ProcInfo, !VarInfo, !PredConstraints):
%
% Adds constraints based on the mode declaration in ProcInfo to
% the PredConstraints structure, associating them specifically with ProcId.
% Relies on the constraint variables associated with the head variables
% of PredId at the empty goal path being stored in VarInfo.
%
:- pred prop_mode_constraints_in_mode_declared_proc(module_info::in,
pred_id::in, proc_id::in, proc_info::in, mc_var_info::in,
mc_var_info::out, mode_constraints::in, mode_constraints::out) is det.
prop_mode_constraints_in_mode_declared_proc(ModuleInfo, PredId, ProcId,
ProcInfo, !VarInfo, !PredConstraints) :-
proc_info_get_argmodes(ProcInfo, ArgModes),
proc_info_get_headvars(ProcInfo, Args),
add_mode_decl_constraints(ModuleInfo, PredId, ProcId, ArgModes, Args,
!VarInfo, !PredConstraints).
%----------------------------------------------------------------------------%
ensure_unique_arguments(PredId, !ModuleInfo) :-
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
clauses_info_get_clauses_rep(ClausesInfo0, ClausesRep0, ItemNumbers),
clauses_info_get_varset(ClausesInfo0, VarSet0),
clauses_info_get_vartypes(ClausesInfo0, VarTypes0),
clauses_info_get_headvars(ClausesInfo0, HeadVars),
SeenSoFar = set_of_var.list_to_set(proc_arg_vector_to_list(HeadVars)),
get_clause_list_for_replacement(ClausesRep0, Clauses0),
BodyGoals0 = list.map(func(X) = clause_body(X), Clauses0),
list.map_foldl3(ensure_unique_arguments_in_goal, BodyGoals0, BodyGoals,
SeenSoFar, _, VarSet0, VarSet, VarTypes0, VarTypes),
Clauses = list.map_corresponding(func(C, B) = C ^ clause_body := B,
Clauses0, BodyGoals),
set_clause_list(Clauses, ClausesRep),
some [!ClausesInfo] (
!:ClausesInfo = ClausesInfo0,
clauses_info_set_varset(VarSet, !ClausesInfo),
clauses_info_set_vartypes(VarTypes, !ClausesInfo),
clauses_info_set_clauses_rep(ClausesRep, ItemNumbers, !ClausesInfo),
pred_info_set_clauses_info(!.ClausesInfo, PredInfo0, PredInfo)
),
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo).
% ensure_unique_arguments_in_goal(!Goal, !SeenSoFar, !VarSet, !VarTypes):
%
% Create variables and introduce unifications in Goal, where appropriate,
% to ensure that no program variable in SeenSoFar is used as an argument in
% a predicate call and that no program variable is used as an argument for
% more than one predicate call.
% Created variables are added to VarSet, VarTypes and SeenSoFar. Variables
% used as arguments in predicate calls are added to SeenSoFar.
%
:- pred ensure_unique_arguments_in_goal(hlds_goal::in, hlds_goal::out,
set_of_progvar::in, set_of_progvar::out, prog_varset::in, prog_varset::out,
vartypes::in, vartypes::out) is det.
ensure_unique_arguments_in_goal(!Goal, !SeenSoFar, !VarSet, !VarTypes) :-
some [!GoalExpr, !GoalInfo] (
!.Goal = hlds_goal(!:GoalExpr, !:GoalInfo),
(
!.GoalExpr = conj(ConjType, Goals0),
(
ConjType = plain_conj,
list.map_foldl3(ensure_unique_arguments_in_goal,
Goals0, Goals1, !SeenSoFar, !VarSet, !VarTypes),
flatten_conjunction(Goals1, Goals),
!:GoalExpr = conj(plain_conj, Goals)
;
ConjType = parallel_conj,
list.map_foldl3(ensure_unique_arguments_in_goal,
Goals0, Goals, !SeenSoFar, !VarSet, !VarTypes),
!:GoalExpr = conj(parallel_conj, Goals)
)
;
!.GoalExpr = plain_call(CalleePredId, CalleeProcId, Args0,
Builtin, UnifyContext, SymName),
Context = goal_info_get_context(!.GoalInfo),
make_unifications(Context, Unifications, Args0, Args, !SeenSoFar,
!VarSet, !VarTypes),
(
% No arguments changed.
Unifications = []
;
% Some of the argument variables have been replaced.
% Need to put the call with its new args in a conjunction
% with the unifications.
Unifications = [_ | _],
CallGoalExpr = plain_call(CalleePredId, CalleeProcId, Args,
Builtin, UnifyContext, SymName),
replace_call_with_conjunction(CallGoalExpr, Unifications,
Args, !:GoalExpr, !GoalInfo)
)
;
!.GoalExpr = generic_call(Details, Args0, Modes, MaybeArgRegs,
Determinism),
Context = goal_info_get_context(!.GoalInfo),
make_unifications(Context, Unifications, Args0, Args, !SeenSoFar,
!VarSet, !VarTypes),
(
% No arguments changed.
Unifications = []
;
% Some of the argument variables have been replaced.
% Need to put the call with its new args in a conjunction
% with the unifications.
Unifications = [_ | _],
CallGoalExpr = generic_call(Details, Args, Modes, MaybeArgRegs,
Determinism),
replace_call_with_conjunction(CallGoalExpr, Unifications,
Args, !:GoalExpr, !GoalInfo)
)
;
!.GoalExpr = switch(_SwitchVar, _CanFail, _Cases0),
unexpected($module, $pred, "switch")
;
!.GoalExpr = unify(_, _, _, _, _)
;
!.GoalExpr = disj(Goals0),
list.map_foldl3(ensure_unique_arguments_in_goal, Goals0, Goals,
!SeenSoFar, !VarSet, !VarTypes),
!:GoalExpr = disj(Goals)
;
!.GoalExpr = negation(Goal0),
ensure_unique_arguments_in_goal(Goal0, Goal, !SeenSoFar, !VarSet,
!VarTypes),
!:GoalExpr = negation(Goal)
;
!.GoalExpr = scope(Reason, Goal0),
% XXX We should special-case the handling of
% from_ground_term_construct scopes.
ensure_unique_arguments_in_goal(Goal0, Goal, !SeenSoFar, !VarSet,
!VarTypes),
!:GoalExpr = scope(Reason, Goal)
;
!.GoalExpr = if_then_else(ExistVars, Cond0, Then0, Else0),
ensure_unique_arguments_in_goal(Cond0, Cond, !SeenSoFar, !VarSet,
!VarTypes),
ensure_unique_arguments_in_goal(Then0, Then, !SeenSoFar, !VarSet,
!VarTypes),
ensure_unique_arguments_in_goal(Else0, Else, !SeenSoFar, !VarSet,
!VarTypes),
!:GoalExpr = if_then_else(ExistVars, Cond, Then, Else)
;
!.GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
;
!.GoalExpr = shorthand(ShortHand0),
(
ShortHand0 = atomic_goal(GoalType, Outer, Inner,
MaybeOutputVars, MainGoal0, OrElseGoals0, OrElseInners),
ensure_unique_arguments_in_goal(MainGoal0, MainGoal,
!SeenSoFar, !VarSet, !VarTypes),
list.map_foldl3(ensure_unique_arguments_in_goal,
OrElseGoals0, OrElseGoals, !SeenSoFar, !VarSet, !VarTypes),
ShortHand = atomic_goal(GoalType, Outer, Inner,
MaybeOutputVars, MainGoal, OrElseGoals, OrElseInners),
!:GoalExpr = shorthand(ShortHand)
;
ShortHand0 = try_goal(MaybeIO, ResultVar, SubGoal0),
ensure_unique_arguments_in_goal(SubGoal0, SubGoal, !SeenSoFar,
!VarSet, !VarTypes),
ShortHand = try_goal(MaybeIO, ResultVar, SubGoal),
!:GoalExpr = shorthand(ShortHand)
;
ShortHand0 = bi_implication(_, _),
unexpected($module, $pred, "bi_implication")
)
),
!:Goal = hlds_goal(!.GoalExpr, !.GoalInfo)
).
% flatten_conjunction(!Goals) flattens the conjunction Goals - that
% is, moves the conjuncts from nested conjunctions into Goals.
%
:- pred flatten_conjunction(list(hlds_goal)::in, list(hlds_goal)::out) is det.
flatten_conjunction(!Goals) :-
list.foldr(add_to_before_conjunction, !.Goals, [], !:Goals).
% add_to_before_conjunction(Goal, !Goals) adds Goal to the front of the
% conjunction Goals. It keeps the conjunction flat, so nested conjunctions
% are flattened and their conjuncts prepended to Goals.
%
:- pred add_to_before_conjunction(hlds_goal::in,
list(hlds_goal)::in, list(hlds_goal)::out) is det.
add_to_before_conjunction(Goal, !Goals) :-
( Goal = hlds_goal(conj(plain_conj, SubGoals), _) ->
!:Goals = SubGoals ++ !.Goals
;
!:Goals = [Goal | !.Goals]
).
% make_unifications(Context, MaybeUnifications, Args0, Args, !SeenSoFar,
% !VarSet, !VarTypes):
%
% If any of the given arguments in Args0 is in SeenSoFar, creates a new
% argument (in VarSet and VarTypes) to replace it (in Args), and generates
% a unification between new argument and old (with context Context).
%
:- pred make_unifications(prog_context::in, list(hlds_goal)::out,
list(prog_var)::in, list(prog_var)::out,
set_of_progvar::in, set_of_progvar::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
make_unifications(Context, Unifications, !Args, !SeenSoFar,
!VarSet, !VarTypes) :-
list.map_foldl4(make_unification(Context), !Args,
[], Unifications, !SeenSoFar, !VarSet, !VarTypes).
% make_unification(Context, Var0, Var, !Unifications, !SeenSoFar,
% !VarSet, !VarTypes):
%
% If Var0 is in SeenSoFar, creates a new argument Var (in VarSet and
% VarTypes), and generates a unification between Var0 and Var.
%
:- pred make_unification(prog_context::in, prog_var::in, prog_var::out,
list(hlds_goal)::in, list(hlds_goal)::out,
set_of_progvar::in, set_of_progvar::out, prog_varset::in, prog_varset::out,
vartypes::in, vartypes::out) is det.
make_unification(Context, Var0, Var, !Unifications, !SeenSoFar, !VarSet,
!VarTypes) :-
( set_of_var.contains(!.SeenSoFar, Var0) ->
% Make new variable.
OldVarName = varset.lookup_name(!.VarSet, Var0),
lookup_var_type(!.VarTypes, Var0, OldVarType),
NewVarName = "Arg_" ++ OldVarName,
varset.new_uniquely_named_var(NewVarName, Var, !VarSet),
add_var_type(Var, OldVarType, !VarTypes),
% Make new unification.
create_atomic_complicated_unification(Var0, rhs_var(Var), Context,
umc_implicit("Making call args unique for cbma"), [], purity_pure,
UnificationGoal0),
UnificationGoal0 =
hlds_goal(UnificationGoalExpr, UnificationGoalInfo0),
goal_info_set_nonlocals(set_of_var.list_to_set([Var0, Var]),
UnificationGoalInfo0, UnificationGoalInfo),
UnificationGoal =
hlds_goal(UnificationGoalExpr, UnificationGoalInfo),
!:Unifications = [UnificationGoal | !.Unifications]
;
Var = Var0
),
set_of_var.insert(Var, !SeenSoFar).
% replace_call_with_conjunction(NewCallGoalExpr, Unifications, NewArgs,
% GoalExpr, !GoalInfo):
%
% Makes a conjunction out of CallGoalExpr and Unifications - the
% conjunction becomes GoalExpr and the goal info for the conjunction
% becomes !:GoalInfo. Goal info for CallGoalExpr and GoalExpr is
% created with the assumption that GoalExpr replaces a call and that
% CallGoalExpr is that call with its arguments replaced by NewArgs
% (where Unifications contains unfications between old arguments
% and their new replacements).
%
:- pred replace_call_with_conjunction(hlds_goal_expr::in, list(hlds_goal)::in,
list(prog_var)::in, hlds_goal_expr::out,
hlds_goal_info::in, hlds_goal_info::out) is det.
replace_call_with_conjunction(CallGoalExpr, Unifications, NewArgs, GoalExpr,
!GoalInfo) :-
CallGoalInfo0 = !.GoalInfo,
Context = goal_info_get_context(CallGoalInfo0),
CallNonlocals0 = goal_info_get_nonlocals(CallGoalInfo0),
set_of_var.insert_list(NewArgs, CallNonlocals0, CallNonlocals),
goal_info_set_nonlocals(CallNonlocals, CallGoalInfo0, CallGoalInfo),
Goals = [hlds_goal(CallGoalExpr, CallGoalInfo) | Unifications],
% Create the new conjunction
GoalExpr = conj(plain_conj, Goals),
goal_info_init(!:GoalInfo),
goal_info_set_context(Context, !GoalInfo),
goal_info_set_nonlocals(CallNonlocals0, !GoalInfo).
%----------------------------------------------------------------------------%
module_info_pred_status_is_imported(ModuleInfo, PredId) :-
module_info_pred_info(ModuleInfo, PredId, PredInfo),
% The following used because pred_info_is_imported/2 is not
% as comprehensive as status_is_imported/2.
pred_info_get_status(PredInfo, Status),
pred_status_is_imported(Status) = yes.
%----------------------------------------------------------------------------%
% Print the constraints to the current output stream in human readable
% format. It titles each pred's constraints with a module qualification
% based on the default filename for the module followed by the
% predicate's name.
%
pretty_print_pred_constraints_map(ModuleInfo, ConstraintVarSet,
PredConstraintsMap, !IO) :-
ConstrainedPreds = map.keys(PredConstraintsMap),
list.foldl(
pretty_print_pred_constraints(ModuleInfo, ConstraintVarSet,
PredConstraintsMap),
ConstrainedPreds, !IO).
% Print the constraints for the specified predicate from the
% pred_constraints_map to the current output stream in a human
% readable format.
%
:- pred pretty_print_pred_constraints(module_info::in, mc_varset::in,
pred_constraints_map::in, pred_id::in, io::di, io::uo) is det.
pretty_print_pred_constraints(ModuleInfo, ConstraintVarSet,
PredConstraintsMap, PredId, !IO) :-
module_info_get_globals(ModuleInfo, Globals),
% Start with a blank line.
write_error_pieces_plain(Globals, [fixed("")], !IO),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
write_error_pieces_plain(Globals, [words("Constraints for")] ++
describe_one_pred_info_name(should_module_qualify, PredInfo) ++
[suffix(":")], !IO),
map.lookup(PredConstraintsMap, PredId, {_, PredConstraints}),
AllProcAnnConstraints = allproc_annotated_constraints(PredConstraints),
dump_constraints_and_annotations(Globals, ConstraintVarSet,
AllProcAnnConstraints, !IO),
list.foldl(
pretty_print_proc_constraints(ModuleInfo, ConstraintVarSet,
PredConstraints, PredId),
pred_info_all_procids(PredInfo), !IO).
% Puts the constraints specific to the procedure indicated from
% the pred_p_c_constraints to the current output stream in human
% readable format.
%
:- pred pretty_print_proc_constraints(module_info::in, mc_varset::in,
pred_p_c_constraints::in, pred_id::in, proc_id::in, io::di, io::uo) is det.
pretty_print_proc_constraints(ModuleInfo, ConstraintVarSet, PredConstraints,
PredId, ProcId, !IO) :-
module_info_get_globals(ModuleInfo, Globals),
% Start with a blank line.
write_error_pieces_plain(Globals, [fixed("")], !IO),
write_error_pieces_plain(Globals, describe_one_proc_name(ModuleInfo,
should_module_qualify, proc(PredId, ProcId)) ++ [suffix(":")], !IO),
ProcSpecAnnConstraints =
proc_specific_annotated_constraints(ProcId, PredConstraints),
dump_constraints_and_annotations(Globals, ConstraintVarSet,
ProcSpecAnnConstraints, !IO).
%----------------------------------------------------------------------------%
:- end_module check_hlds.prop_mode_constraints.
%----------------------------------------------------------------------------%