mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 22:03:26 +00:00
Estimated hours taken: 70
Branches: main
Implement the trace goal construct we discussed, for now for the LLDS backends
only.
Since the syntax of trace goals is non-trivial, useful feedback on syntax
errors inside trace goal attributes is essential. With the previous setup, this
wasn't possible, since the code that turned terms into parse tree goals turned
*all* terms into goals; it couldn't recognize any errors, sweeping them under
the rug as calls. This diff changes that. Now, if this code recognizes a
keyword that indicates a particular construct, it insists on the rest of the
code following the syntax required for that construct, and returns error
messages if it doesn't.
We handle the trace goal attributes that specify state variables to be threaded
through the trace goal (either the I/O state or a mutable variable) in
add_clause.m, at the point at which we transform the list of items to the HLDS.
We handle the compile-time condition on trace goals in the invocation of
simplify at the end of semantics analysis, by eliminating the goal if the
compile-time condition isn't met. We handle run-time conditions on trace goals
partially in the same invocation of simplify: we transform trace goals with
runtime conditions into an if-then-else with the trace goal as the then part
and `true' as the else part, the condition being a foreign_proc that is handled
specially by the code generator, that special handling being to replace
the actual code of the foreign_proc (which is a dummy) with the evaluation of
the runtime condition.
Since these changes require significant changes to some of our key data
structures, I took the liberty of doing some renaming of function symbols
at the same time to avoid using ambiguities with respect to language keywords.
library/ops.m:
Add "trace" as an operator.
compiler/prog_data.m:
Define data types to represent the various attributes of trace goals.
Rename some function symbols to avoid ambiguities.
compiler/prog_item.m:
Extend the parse tree representation of goals with a trace goal.
compiler/mercury_to_mercury.m:
Output the new kind of goal and its components.
compiler/hlds_goal.m:
Extend the HLDS representation of scopes with a scope_reason
representing trace goals.
Add a mechanism (an extra argument in foreign_procs) to allow
the representation of goals that evaluate runtime trace conditions.
Since this requires modifying all code that traverses the HLDS,
do some renames that were long overdue: rename not as negation,
rename call as plain_call, and rename foreign_proc as
call_foreign_proc. These renames all avoid using language keywords
as function symbols.
Change the way we record goals' purities. Instead of optional features
to indicate impure or semipure, which is error-prone, use a plain
field in the goal_info, accessed in the usual way.
Add a way to represent that a goal contains a trace goal, and should
therefore be treated as if it were impure when considering whether to
optimize it away.
Reformat some comments describing function symbols.
compiler/hlds_out.m:
Output the new construct in the HLDS.
compiler/prog_io_util.m:
Generalize the maybe[123] types to allow the representation of more
than one error message. Add functions to extract the error messages.
Add a maybe4 type. Rename the function symbols of these types to
avoid massive ambiguity.
Change the order of some predicates to bring related predicates
next to each other.
compiler/prog_io.m:
compiler/prog_io_dcg.m:
compiler/prog_io_goal.m:
compiler/prog_io_pragma.m:
Rework these modules almost completely to find and accumulate syntax
errors as terms are being parsed. In some cases, this allowed us to
replace "XXX this is a hack" markers with meaningful error-reporting
code.
In prog_io_goal.m, add code for parsing trace goals.
In a bunch of places, update obsolete coding practices, such as using
nested chains of closures instead of simple sequential code, and
using A0 and A to refer to values of different types (terms and goals
respectively). Use more meaningful variable names.
Break up some too-large predicates.
compiler/superhomogeneous.m:
Find and accumulate syntax errors as terms are being parsed.
compiler/add_clause.m:
Add code to transform trace goals from the parse tree to the HLDS.
This is where the IO state and mutable variable attributes of trace
goals are handled.
Eliminate the practice of using the naming scheme Body0 and Body
to refer to values of different types (prog_item.goal and hlds_goal
respectively).
Use error_util for some error messages.
library/private_builtin.m:
Add the predicates referred to by the transformation in add_clause.m.
compiler/goal_util.m:
Rename a predicate to avoid ambiguity.
compiler/typecheck.m:
Do not print error messages about missing clauses if some errors have
been detected previously.
compiler/purity.m:
Instead of just computing purity, compute (and record) also whether
a goal contains a trace goal. However, treat trace goals as pure.
compiler/mode_info.m:
Add trace goals as a reason for locking variables.
Rename some function symbols to avoid ambiguity.
compiler/modes.m:
When analyzing trace goal scopes, lock the scope's nonlocal variables
to prevent them from being further instantiated.
compiler/det_analysis.m:
Insist on the code in trace goal scopes being det or cc_multi.
compiler/det_report.m:
Generate the error message if the code in a trace goal scope isn't det
or cc_multi.
compiler/simplify.m:
At the end of the front end, eliminate trace goal scopes if their
compile-time condition is false. Transform trace goals with runtime
conditions as described at the top.
Treat goals that contain trace goals as if they were impure when
considering whether to optimize them away.
compiler/mercury_compile.m:
Tell simplify when it is being invoked at the end of the front end.
Rename a predicate to avoid ambiguity.
compiler/trace_params.m:
Provide the predicates simplify.m need to be able to evaluate the trace
goal conditions regarding trace levels.
compiler/trace.m:
compiler/trace_gen.m:
Rename the trace module as trace_gen, since "trace" is now an operator.
Rename some predicates exported by the module, now that it is no longer
possible to preface calls with "trace." as a module qualifier.
compiler/notes/compiler_design.html:
Document this name change.
compiler/options.m:
Rename the trace option as trace_level internally, since "trace"
is now an operator. The user-visible name remains the same.
Add the new --trace-flag option.
Delete an obsolete option.
compiler/handle_options.m:
Rename the function symbols of the grade_component type,
since "trace" is now an operator.
compiler/llds.m:
Extend the LLDS with a mechanism to refer to C global variables.
For now, these are used to refer to C globals that will be created
by mkinit to represent the initial values of the environment variables
referred to by trace goals.
compiler/commit_gen.m:
Check that no trace goal with a runtime condition survives to code
generation; they should have been transformed by simplify.m.
compiler/code_gen.m:
Tell commit_gen.m what kind of scope it is generating code for.
compiler/pragma_c_gen.m:
Generate code for runtime conditions when handling the foreign_procs
created by simplify.m.
compiler/code_info.m:
Allow pragma_c_gen.m to record what environment variables it has
generated references to.
compiler/proc_gen.m:
Record the set of environment variables a procedure refers to
in the LLDS procedure header, for efficient access by llds_out.m.
compiler/llds_out.m:
Handle the new LLDS construct, and tell mkinit which environment
variables need C globals created for them.
compiler/pd_util.m:
Rename some predicates to avoid ambiguity.
compiler/*.m:
Conform to the changes above, mainly the renames of function symbols
and predicates, the changed signatures of some predicates, and the new
handling of purity.
util/mkinit.c:
Generate the definitions and the initializations of any C globals
representing the initial status (set or not set) of environment
variables needed by trace goals.
library/assoc_list.m:
Add some predicates that are useful in prog_io*.m.
library/term_io.m:
Minor cleanup.
tests/hard_coded/trace_goal_{1,2}.{m,exp}:
New test cases to test the new construct, identical except for whether
the trace goal is enabled at compile time.
tests/hard_coded/trace_goal_env_{1,2}.{m,exp}:
New test cases to test the new construct, identical except for whether
the trace goal is enabled at run time.
tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
Enable the new test cases.
tests/invalid/*.err_exp:
Update the expected output for the new versions of the error messages
now being generated.
361 lines
14 KiB
Mathematica
361 lines
14 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2000-2006 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: add_heap_ops.m.
|
|
% Author: fjh.
|
|
|
|
% This module is an HLDS-to-HLDS transformation that inserts code to
|
|
% handle heap reclamation on backtracking, by saving and restoring
|
|
% the values of the heap pointer.
|
|
% The transformation involves adding calls to impure
|
|
% predicates defined in library/private_builtin.m, which in turn call
|
|
% the MR_mark_hp() and MR_restore_hp() macros defined in
|
|
% runtime/mercury_heap.h.
|
|
%
|
|
% This pass is currently only used for the MLDS back-end.
|
|
% For some reason (perhaps efficiency?? or more likely just historical?),
|
|
% the LLDS back-end inserts the heap operations as it is generating
|
|
% LLDS code, rather than via an HLDS to HLDS transformation.
|
|
%
|
|
% This module is very similar to add_trail_ops.m.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% XXX check goal_infos for correctness
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.add_heap_ops.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
|
|
:- pred add_heap_ops(module_info::in, proc_info::in, proc_info::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.goal_form.
|
|
:- import_module hlds.goal_util.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.instmap.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module hlds.quantification.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.modules.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% As we traverse the goal, we add new variables to hold the saved values
|
|
% of the heap pointer. So we need to thread a varset and a vartypes mapping
|
|
% through, to record the names and types of the new variables.
|
|
%
|
|
% We also keep the module_info around, so that we can use the predicate
|
|
% table that it contains to lookup the pred_ids for the builtin procedures
|
|
% that we insert calls to. We do not update the module_info as we're
|
|
% traversing the goal.
|
|
%
|
|
:- type heap_ops_info
|
|
---> heap_ops_info(
|
|
varset :: prog_varset,
|
|
var_types :: vartypes,
|
|
module_info :: module_info
|
|
).
|
|
|
|
add_heap_ops(ModuleInfo0, !Proc) :-
|
|
proc_info_get_goal(!.Proc, Goal0),
|
|
proc_info_get_varset(!.Proc, VarSet0),
|
|
proc_info_get_vartypes(!.Proc, VarTypes0),
|
|
TrailOpsInfo0 = heap_ops_info(VarSet0, VarTypes0, ModuleInfo0),
|
|
goal_add_heap_ops(Goal0, Goal, TrailOpsInfo0, TrailOpsInfo),
|
|
TrailOpsInfo = heap_ops_info(VarSet, VarTypes, _),
|
|
proc_info_set_goal(Goal, !Proc),
|
|
proc_info_set_varset(VarSet, !Proc),
|
|
proc_info_set_vartypes(VarTypes, !Proc),
|
|
% The code below does not maintain the non-local variables,
|
|
% so we need to requantify.
|
|
% XXX it would be more efficient to maintain them rather than recomputing
|
|
% them every time.
|
|
requantify_proc(!Proc).
|
|
|
|
:- pred goal_add_heap_ops(hlds_goal::in, hlds_goal::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
goal_add_heap_ops(GoalExpr0 - GoalInfo, Goal, !Info) :-
|
|
goal_expr_add_heap_ops(GoalExpr0, GoalInfo, Goal, !Info).
|
|
|
|
:- pred goal_expr_add_heap_ops(hlds_goal_expr::in, hlds_goal_info::in,
|
|
hlds_goal::out, heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
goal_expr_add_heap_ops(conj(ConjType, Goals0), GI, conj(ConjType, Goals) - GI,
|
|
!Info) :-
|
|
conj_add_heap_ops(Goals0, Goals, !Info).
|
|
|
|
goal_expr_add_heap_ops(disj([]), GI, disj([]) - GI, !Info).
|
|
goal_expr_add_heap_ops(disj(Goals0), GoalInfo, Goal - GoalInfo, !Info) :-
|
|
Goals0 = [FirstDisjunct | _],
|
|
|
|
goal_info_get_context(GoalInfo, Context),
|
|
goal_info_get_code_model(GoalInfo, CodeModel),
|
|
|
|
% If necessary, save the heap pointer so that we can restore it
|
|
% on back-tracking. We don't need to do this here if it is a model_det
|
|
% or model_semi disjunction and the first disjunct won't allocate any heap
|
|
% -- in that case, we delay saving the heap pointer until just before
|
|
% the first disjunct that might allocate heap.
|
|
(
|
|
( CodeModel = model_non
|
|
; goal_may_allocate_heap(FirstDisjunct)
|
|
)
|
|
->
|
|
new_saved_hp_var(SavedHeapPointerVar, !Info),
|
|
gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info),
|
|
disj_add_heap_ops(Goals0, yes, yes(SavedHeapPointerVar), GoalInfo,
|
|
Goals, !Info),
|
|
Goal = conj(plain_conj, [MarkHeapPointerGoal, disj(Goals) - GoalInfo])
|
|
;
|
|
disj_add_heap_ops(Goals0, yes, no, GoalInfo, Goals, !Info),
|
|
Goal = disj(Goals)
|
|
).
|
|
|
|
goal_expr_add_heap_ops(switch(Var, CanFail, Cases0), GI,
|
|
switch(Var, CanFail, Cases) - GI, !Info) :-
|
|
cases_add_heap_ops(Cases0, Cases, !Info).
|
|
|
|
goal_expr_add_heap_ops(negation(InnerGoal), OuterGoalInfo, Goal, !Info) :-
|
|
%
|
|
% We handle negations by converting them into if-then-elses:
|
|
% not(G) ===> (if G then fail else true)
|
|
%
|
|
goal_info_get_context(OuterGoalInfo, Context),
|
|
InnerGoal = _ - InnerGoalInfo,
|
|
goal_info_get_determinism(InnerGoalInfo, Determinism),
|
|
determinism_components(Determinism, _CanFail, NumSolns),
|
|
True = true_goal_with_context(Context),
|
|
Fail = fail_goal_with_context(Context),
|
|
ModuleInfo = !.Info ^ module_info,
|
|
( NumSolns = at_most_zero ->
|
|
% The "then" part of the if-then-else will be unreachable, but to
|
|
% preserve the invariants that the MLDS back-end relies on, we need to
|
|
% make sure that it can't fail. So we use a call to
|
|
% `private_builtin.unused' (which will call error/1) rather than
|
|
% `fail' for the "then" part.
|
|
generate_call("unused", detism_det, purity_pure, [], [],
|
|
ModuleInfo, Context, ThenGoal)
|
|
;
|
|
ThenGoal = Fail
|
|
),
|
|
NewOuterGoal = if_then_else([], InnerGoal, ThenGoal, True),
|
|
goal_expr_add_heap_ops(NewOuterGoal, OuterGoalInfo, Goal, !Info).
|
|
|
|
goal_expr_add_heap_ops(scope(Reason, Goal0), GoalInfo,
|
|
scope(Reason, Goal) - GoalInfo, !Info) :-
|
|
goal_add_heap_ops(Goal0, Goal, !Info).
|
|
|
|
goal_expr_add_heap_ops(if_then_else(A, Cond0, Then0, Else0), GoalInfo,
|
|
Goal - GoalInfo, !Info) :-
|
|
goal_add_heap_ops(Cond0, Cond, !Info),
|
|
goal_add_heap_ops(Then0, Then, !Info),
|
|
goal_add_heap_ops(Else0, Else1, !Info),
|
|
|
|
% If the condition can allocate heap space, save the heap pointer
|
|
% so that we can restore it if the condition fails.
|
|
( goal_may_allocate_heap(Cond0) ->
|
|
new_saved_hp_var(SavedHeapPointerVar, !Info),
|
|
goal_info_get_context(GoalInfo, Context),
|
|
gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info),
|
|
|
|
% Generate code to restore the heap pointer, and insert that code
|
|
% at the start of the Else branch.
|
|
gen_restore_hp(SavedHeapPointerVar, Context, RestoreHeapPointerGoal,
|
|
!Info),
|
|
Else1 = _ - Else1GoalInfo,
|
|
Else = conj(plain_conj, [RestoreHeapPointerGoal, Else1])
|
|
- Else1GoalInfo,
|
|
IfThenElse = if_then_else(A, Cond, Then, Else) - GoalInfo,
|
|
Goal = conj(plain_conj, [MarkHeapPointerGoal, IfThenElse])
|
|
;
|
|
Goal = if_then_else(A, Cond, Then, Else1)
|
|
).
|
|
|
|
goal_expr_add_heap_ops(Goal @ plain_call(_, _, _, _, _, _), GI, Goal - GI,
|
|
!Info).
|
|
goal_expr_add_heap_ops(Goal @ generic_call(_, _, _, _), GI, Goal - GI, !Info).
|
|
goal_expr_add_heap_ops(Goal @ unify(_, _, _, _, _), GI, Goal - GI, !Info).
|
|
|
|
goal_expr_add_heap_ops(PragmaForeign, GoalInfo, Goal, !Info) :-
|
|
PragmaForeign = call_foreign_proc(_, _, _, _, _, _, Impl),
|
|
( Impl = fc_impl_model_non(_, _, _, _, _, _, _, _, _) ->
|
|
% XXX Implementing heap reclamation for nondet pragma foreign_code
|
|
% via transformation is difficult, because there's nowhere in the HLDS
|
|
% pragma_foreign_code goal where we can insert the heap reclamation
|
|
% operations. For now, we don't support this. Instead, we just generate
|
|
% a call to a procedure which will at runtime call error/1 with an
|
|
% appropriate "Sorry, not implemented" error message.
|
|
ModuleInfo = !.Info ^ module_info,
|
|
goal_info_get_context(GoalInfo, Context),
|
|
generate_call("reclaim_heap_nondet_pragma_foreign_code",
|
|
detism_erroneous, purity_pure, [], [], ModuleInfo, Context,
|
|
SorryNotImplementedCode),
|
|
Goal = SorryNotImplementedCode
|
|
;
|
|
Goal = PragmaForeign - GoalInfo
|
|
).
|
|
|
|
goal_expr_add_heap_ops(shorthand(_), _, _, !Info) :-
|
|
% These should have been expanded out by now.
|
|
unexpected(this_file, "goal_expr_add_heap_ops: unexpected shorthand").
|
|
|
|
:- pred conj_add_heap_ops(hlds_goals::in, hlds_goals::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
conj_add_heap_ops(Goals0, Goals, !Info) :-
|
|
list.map_foldl(goal_add_heap_ops, Goals0, Goals, !Info).
|
|
|
|
:- pred disj_add_heap_ops(hlds_goals::in, bool::in, maybe(prog_var)::in,
|
|
hlds_goal_info::in, hlds_goals::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
disj_add_heap_ops([], _, _, _, [], !Info).
|
|
disj_add_heap_ops([Goal0 | Goals0], IsFirstBranch, MaybeSavedHeapPointerVar,
|
|
DisjGoalInfo, DisjGoals, !Info) :-
|
|
goal_add_heap_ops(Goal0, Goal1, !Info),
|
|
Goal1 = _ - GoalInfo,
|
|
goal_info_get_context(GoalInfo, Context),
|
|
|
|
% If needed, reset the heap pointer before executing the goal,
|
|
% to reclaim heap space allocated in earlier branches.
|
|
(
|
|
IsFirstBranch = no,
|
|
MaybeSavedHeapPointerVar = yes(SavedHeapPointerVar0)
|
|
->
|
|
gen_restore_hp(SavedHeapPointerVar0, Context, RestoreHeapPointerGoal,
|
|
!Info),
|
|
conj_list_to_goal([RestoreHeapPointerGoal, Goal1], GoalInfo, Goal)
|
|
;
|
|
Goal = Goal1
|
|
),
|
|
|
|
% Save the heap pointer, if we haven't already done so, and if this
|
|
% disjunct might allocate heap space.
|
|
(
|
|
MaybeSavedHeapPointerVar = no,
|
|
goal_may_allocate_heap(Goal)
|
|
->
|
|
% Generate code to save the heap pointer.
|
|
new_saved_hp_var(SavedHeapPointerVar, !Info),
|
|
gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info),
|
|
|
|
% Recursively handle the remaining disjuncts.
|
|
disj_add_heap_ops(Goals0, no, yes(SavedHeapPointerVar), DisjGoalInfo,
|
|
Goals1, !Info),
|
|
% Put this disjunct and the remaining disjuncts in a nested
|
|
% disjunction, so that the heap pointer variable can scope over
|
|
% these disjuncts.
|
|
Disj = disj([Goal | Goals1]) - DisjGoalInfo,
|
|
DisjGoals = [conj(plain_conj, [MarkHeapPointerGoal, Disj])
|
|
- DisjGoalInfo]
|
|
;
|
|
% Just recursively handle the remaining disjuncts.
|
|
disj_add_heap_ops(Goals0, no, MaybeSavedHeapPointerVar, DisjGoalInfo,
|
|
Goals, !Info),
|
|
DisjGoals = [Goal | Goals]
|
|
).
|
|
|
|
:- pred cases_add_heap_ops(list(case)::in, list(case)::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
cases_add_heap_ops([], [], !Info).
|
|
cases_add_heap_ops([Case0 | Cases0], [Case | Cases], !Info) :-
|
|
Case0 = case(ConsId, Goal0),
|
|
Case = case(ConsId, Goal),
|
|
goal_add_heap_ops(Goal0, Goal, !Info),
|
|
cases_add_heap_ops(Cases0, Cases, !Info).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred gen_mark_hp(prog_var::in, prog_context::in, hlds_goal::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info) :-
|
|
generate_call("mark_hp", detism_det, purity_impure, [SavedHeapPointerVar],
|
|
[SavedHeapPointerVar - ground_inst], !.Info ^ module_info, Context,
|
|
MarkHeapPointerGoal).
|
|
|
|
:- pred gen_restore_hp(prog_var::in, prog_context::in, hlds_goal::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
gen_restore_hp(SavedHeapPointerVar, Context, RestoreHeapPointerGoal, !Info) :-
|
|
generate_call("restore_hp", detism_det, purity_impure,
|
|
[SavedHeapPointerVar], [], !.Info ^ module_info, Context,
|
|
RestoreHeapPointerGoal).
|
|
|
|
:- func ground_inst = mer_inst.
|
|
|
|
ground_inst = ground(unique, none).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred new_saved_hp_var(prog_var::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
new_saved_hp_var(Var, !Info) :-
|
|
new_var("HeapPointer", heap_pointer_type, Var, !Info).
|
|
|
|
:- pred new_var(string::in, mer_type::in, prog_var::out,
|
|
heap_ops_info::in, heap_ops_info::out) is det.
|
|
|
|
new_var(Name, Type, Var, !Info) :-
|
|
VarSet0 = !.Info ^ varset,
|
|
VarTypes0 = !.Info ^ var_types,
|
|
varset.new_named_var(VarSet0, Name, Var, VarSet),
|
|
map.det_insert(VarTypes0, Var, Type, VarTypes),
|
|
!:Info = !.Info ^ varset := VarSet,
|
|
!:Info = !.Info ^ var_types := VarTypes.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred generate_call(string::in, determinism::in, purity::in,
|
|
list(prog_var)::in, assoc_list(prog_var, mer_inst)::in, module_info::in,
|
|
term.context::in, hlds_goal::out) is det.
|
|
|
|
generate_call(PredName, Detism, Purity, Args, InstMap, ModuleInfo, Context,
|
|
CallGoal) :-
|
|
mercury_private_builtin_module(BuiltinModule),
|
|
goal_util.generate_simple_call(BuiltinModule, PredName, predicate,
|
|
only_mode, Detism, Purity, Args, [], InstMap, ModuleInfo,
|
|
Context, CallGoal).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "add_heap_ops.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|