For review: declarative debugging back end (3/3)
Mark Anthony BROWN
dougl at cs.mu.OZ.AU
Tue Jul 14 20:11:42 AEST 1998
Note for reviewers: the following module contains large commented out
sections. These parts are not yet used, but show roughly how I intend the
module to work (in the near future).
%-----------------------------------------------------------------------------%
% Copyright (C) 1998 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%-----------------------------------------------------------------------------%
% File: evaluation_tree.m
% Author: dougl
% Stability: low
%
% Purpose:
% This module defines the interface to a Mercury Evaluation
% Dependence Tree (EDT), a data structure that holds the representation
% of a justification of program behaviour in terms of the declarative
% semantics of the language.
%
% An EDT for which the top node represents an incorrect result
% exhibits a "symptom" (eg: wrong answer, missing answer, etc); an
% EDT which exhibits a symptom, but which contains no direct
% children that exhibit symptoms, is an "error" (eg: incorrect
% clause instance, uncovered atom, etc).
%
% Rationale:
% An EDT can be used by a declarative debugger to search for
% errors in terms of symptoms. This is achieved with a two level
% architecture: a back end generates EDTs for a running program,
% and a front end searches them for errors.
%
% To support this, the interface to an EDT is decoupled from its
% implementation. The front end of a declarative debugger should
% use the interface provided for the type evaluation_tree/1 and the
% typeclass evaluation_atom/1, and their associated access procedures,
% to analyse the EDT. The back end should provide an instance
% of evaluation_atom (NB: this is the purpose of the compiler
% module evaluation_tree_gen.m).
%
% The chief advantage of this decoupling is that a debuggee module
% (back end) is free to vary the implementation of atoms without
% affecting the debugger (ie the compiled debugger does not depend
% on the debuggee's representation of atoms). In particular, this
% allows a debugger to be written, compiled and distributed _before_
% the debuggee is written, without resorting to the use of the
% ground representation.
%
% Design:
% The decoupling is achieved by parametrizing most of the types in
% this module with the type used to represent atoms, which must be
% an instance of the evaluation_atom typeclass. This module uses
% one of the type variables 'A' or 'E' whenever such a type is
% expected.
:- module evaluation_tree.
:- interface.
:- import_module io, std_util, list.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
%
% This section declares data common to the front and back ends.
%
%
% An evaluation_tree holds an EDT for Mercury.
%
% *_wrong An EDT that can be used for wrong answer
% analysis. For these EDTs, a goal
% behaviour is a computed answer (an
% evaluation_atom in its final state), and
% a goal justification is a proof_tree.
%
% *_miss An EDT that can be used for missing
% answer analysis. In this case, a goal
% behaviour is an evaluation_atom in its
% initial state and a set of computed
% answers, and a goal justification is
% a miss_tree.
%
% analyse_* A pair representing a goal behaviour
% and a goal justification.
%
% interface_* A node representing a goal behaviour.
% The justification is not explicitly
% represented, but we assume that all
% children were symptom-free.
%
% implicit_* A node representing a goal behaviour.
% The justification is not explicitly
% represented, and we make no assumptions
% about it.
%
% assumed The EDT is assumed to be symptom-free.
%
:- type evaluation_tree(A)
---> analyse_wrong(wrong_node(A), proof_tree(A))
; analyse_miss(miss_node(A), miss_tree(A))
; interface_wrong(wrong_node(A))
; interface_miss(miss_node(A))
; implicit_wrong(wrong_node(A))
; implicit_miss(miss_node(A))
; assumed.
%
% The elements of type *_node represent goal behaviours for the
% kinds of analysis that EDTs are used for.
%
% For wrong answer analysis, we store the computed answer.
%
:- type wrong_node(A) == A.
%
% For missing answer analysis, we store the atom in its initial
% instantiatedness, along with the set of its computed answers,
% represented as a list.
%
:- type miss_node(A) == pair(A, list(A)).
%
% The front end can request an analysis of a particular atom.
% The back end should generate an element of the following type
% (and inst).
%
:- type analysis(A)
---> nondet_wrong(pred(evaluation_tree(A)))
; multi_wrong(pred(evaluation_tree(A)))
; semidet_wrong(pred(evaluation_tree(A)))
; det_wrong(pred(evaluation_tree(A)))
; wrong_io(pred(evaluation_tree(A), io__state, io__state))
; miss(pred(evaluation_tree(A)))
; miss_io(pred(evaluation_tree(A), io__state, io__state))
; unavailable.
:- inst analysis =
bound( nondet_wrong(pred(out) is nondet)
; multi_wrong(pred(out) is multi)
; semidet_wrong(pred(out) is semidet)
; det_wrong(pred(out) is det)
; wrong_io(pred(out, di, uo) is det)
; miss(pred(out) is det)
; miss_io(pred(out, di, uo) is det)
; unavailable
).
%
% The back end must provide a way of converting terms in the ground
% representation to atoms. The following is the result type of
% such a conversion.
%
:- type atom_result(A)
---> ok(A)
; type_error
; mode_error
; undefined_atom
; not_an_atom.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
%
% This section contains the interface to the front end.
%
:- type evaluation_node(A)
---> wrong(wrong_node(A))
; miss(miss_node(A))
; interface_wrong(wrong_node(A))
; interface_miss(miss_node(A))
; assumed.
:- type evaluation_node_type
---> explicit
; implicit
; interface
; assumed.
/*
%
% These procedures are used for traversing an evaluation_tree.
%
:- pred root(evaluation_tree(A), evaluation_node(A), evaluation_node_type)
<= evaluation_atom(A).
:- mode root(in, out, out) is det.
:- pred local_child(evaluation_tree(A), evaluation_tree(A))
<= evaluation_atom(A).
:- mode local_child(in, out) is nondet.
%
% Each atom is in one of the following states.
%
:- type inst_state
---> initial % The atom represents the inputs to a call.
; final. % The atom represents a computed answer.
%
% These procedures convert terms using the ground representation
% into atoms. Note that the type variable 'A' is universally
% quantified. This means that the context of the caller
% determines the value of A; these procedures attempt to match
% the term against those atoms that can be represented by A.
%
:- pred find_matching_atom_and_mode(inst_state, int, term, atom_result(A))
<= evaluation_atom(A).
:- mode find_matching_atom_and_mode(in, in, in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
%
% This section contains the interface that the back end must
% conform to.
%
%
% A module that can act as a back end (ie, generate
% evaluation_trees) is free to choose any type to represent atoms.
% The module must provide an interface that makes the type an
% instance of the following typeclass.
%
:- typeclass evaluation_atom(A) where [
pred atom_to_wrong_analysis(A::in, analysis(A)::out(analysis)) is det,
pred atom_to_miss_analysis(A::in, analysis(A)::out(analysis)) is det,
pred term_to_atom(term::in, atom_result(A)::out) is det,
pred atom_to_term(A::in, term::out) is det
].
*/
%
% For wrong answer analysis, the goal justification is a
% proof_tree for a computed answer.
%
:- type proof_tree(A)
---> local_call(evaluation_tree(A))
% ; some [E] external_call(evaluation_tree(E))
% <= evaluation_atom(E)
; conj(list(proof_tree(A)))
; disj(int, proof_tree(A))
; switch(int, proof_tree(A))
; if_then(proof_tree(A), proof_tree(A))
; else(miss_tree(A), proof_tree(A))
; not(miss_tree(A))
; trivial.
%
% For missing answer analysis also, the goal justification is a
% tree that corresponds to the structure of the program. It is
% the dual of the above structure: it represents which atoms
% were _not_ computed answers.
%
:- type miss_tree(A)
---> local_call(evaluation_tree(A))
% ; some [E] external_call(evaluation_tree(E))
% <= evaluation_atom(E)
; conj(list(miss_tree(A)))
; disj(list(miss_tree(A)))
; switch(list(miss_tree(A)))
; if_then(miss_tree(A), miss_tree(A))
; else(proof_tree(A), miss_tree(A))
; not(proof_tree(A))
; trivial.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
/*
:- implementation.
:- import_module string, int.
root(analyse_wrong(Node, _), wrong(Node), explicit).
root(analyse_miss(Node, _), miss(Node), explicit).
root(interface_wrong(Node), interface_wrong(Node), interface).
root(interface_miss(Node), interface_miss(Node), interface).
root(implicit_wrong(Node), wrong(Node), implicit).
root(implicit_miss(Node), miss(Node), implicit).
root(assumed, assumed, assumed).
local_child(analyse_wrong(_, ProofTree), Child) :-
proof_tree_child(ProofTree, Child).
local_child(analyse_miss(_, MissTree), Child) :-
miss_tree_child(MissTree, Child).
%
% XXX Here we should implement the implicit representation
% of subtrees transparently. If the caller asks for the child
% of a implicit_{wrong, miss} node, then we should call
% atom_to_{wrong, miss}_analysis, then call the resulting
% closure to create the tree explicitly.
%
:- pred proof_tree_child(proof_tree(A), evaluation_tree(A)).
:- mode proof_tree_child(in, out) is nondet.
proof_tree_child(local_call(C), C).
proof_tree_child(conj(Ps), C) :-
list__member(P, Ps),
proof_tree_child(P, C).
proof_tree_child(disj(_, P), C) :-
proof_tree_child(P, C).
proof_tree_child(switch(_, P), C) :-
proof_tree_child(P, C).
proof_tree_child(if_then(P, _), C) :-
proof_tree_child(P, C).
proof_tree_child(if_then(_, P), C) :-
proof_tree_child(P, C).
proof_tree_child(else(M, _), C) :-
miss_tree_child(M, C).
proof_tree_child(else(_, P), C) :-
proof_tree_child(P, C).
proof_tree_child(not(M), C) :-
miss_tree_child(M, C).
:- pred miss_tree_child(miss_tree(A), evaluation_tree(A)).
:- mode miss_tree_child(in, out) is nondet.
miss_tree_child(local_call(C), C).
miss_tree_child(conj(Ms), C) :-
list__member(M, Ms),
miss_tree_child(M, C).
miss_tree_child(disj(Ms), C) :-
list__member(M, Ms),
miss_tree_child(M, C).
miss_tree_child(switch(Ms), C) :-
list__member(M, Ms),
miss_tree_child(M, C).
miss_tree_child(if_then(M, _), C) :-
miss_tree_child(M, C).
miss_tree_child(if_then(_, M), C) :-
miss_tree_child(M, C).
miss_tree_child(else(P, _), C) :-
proof_tree_child(P, C).
miss_tree_child(else(_, M), C) :-
miss_tree_child(M, C).
miss_tree_child(not(P), C) :-
proof_tree_child(P, C).
%-----------------------------------------------------------------------------%
find_matching_atom_and_mode(InstState, ModeNum, Term0, AtomResult) :-
( Term0 = term__functor(term__atom(Atom0), Args, Context) ->
add_mode_suffix(Atom0, ModeNum, Atom1),
add_inst_state_suffix(Atom1, InstState, Atom),
Term = term__functor(term__atom(Atom), Args, Context),
term_to_atom(Term, AtomResult)
;
AtomResult = not_an_atom
).
:- pred add_mode_suffix(string, int, string).
:- mode add_mode_suffix(in, in, out) is det.
add_mode_suffix(Name0, ModeNum, Name) :-
string__format("%s_%i", [s(Name0), i(ModeNum)], Name).
:- pred add_inst_state_suffix(string, inst_state, string).
:- mode add_inst_state_suffix(in, in, out) is det.
add_inst_state_suffix(Name0, InstState, Name) :-
(
InstState = initial,
Suffix = "_initial"
;
InstState = final,
Suffix = "_final"
),
string__append(Name0, Suffix, Name).
*/
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% Copyright (C) 1998 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: proof_tree.m
% Author: dougl
% Purpose:
%
% This module is an HLDS transformation that implements the proof tree
% generation required by evaluation_tree_gen.m for declarative
% debugging (of wrong answers).
%
% For each predicate that is to be debugged, a new predicate is created.
% This has one procedure for each procedure of the original. The new versions
% are the same except that they have an extra argument (with mode out)
% containing the proof tree, and that they call the debugging versions of
% subgoals whenever possible. In particular, the determinism does not
% change, and there is a one to one correspondence between the original
% modes and the new modes.
%
% The transformation can be described by the following relations.
%
% pw : Procedure -> Procedure
%
% pw[[ Proc ]] denotes the transformed version of Proc.
%
% gw : Procedure x Var -> Procedure
%
% gw[[ Goal, Proof ]] denotes Goal transformed so as to
% produce a proof tree in Proof.
%
% cw : Atom x Var -> Atom
%
% cw[[ Call, EDT ]] denotes a call to the version of Call
% which produces an evaluation tree in EDT.
%
% aw : Atom x Var -> Atom
%
% aw[[ Atom, EDT ]] is the same as Atom, but has EDT as
% an extra argument.
%
% The relations also refer to gm, which is the same as gw except that
% the structure produced is a miss tree rather than a proof tree.
%
% pw[[ Head :- Body ]] =
% aw[[ Head, EDT ]] :- (gw[[ Body, P ]], EDT = analyse_wrong(Head, P))
%
% gw[[ (G1, ..., Gn), P ]] =
% (gw[[ G1, P1 ]], ..., gw[[ Gn, Pn ]], P = conj([Pn, ..., P1]))
% gw[[ (G1; ...; Gn), P ]] =
% (((gw[[ G1, Pd ]], Arm = 1); ...; (gw[[ Gn, PD ]], Arm = n)),
% P = disj(Arm, PD))
% gw[[ (some Vs G), P ]] =
% (some Vs gw[[ G, P ]])
% gw[[ (not G), P) ]] =
% (not G, gm[[ G, M ]], P = not(M))
% gw[[ (Term1 = Term2), P ]] =
% (Term1 = Term2, P = trivial)
% gw[[ (Cond -> Then ; Else), P ]] =
% (gw[[ Cond, PC ]] -> (gw[[ Then, PT ]], P = if_then(PC, PT))
% ; (gm[[ Cond, MC ]], gw[[ Else, PE ]], P = else(MC, PE)))
% gw[[ call(Closure, ...), P ]] =
% (call(Closure, ...), P = trivial)
% gw[[ LocalCall, P ]] =
% (cw[[ Call, EDT ]], P = local_call(EDT))
% gw[[ ExternalCall, P ]] =
% (ExternalCall, EDT = assumed, P = external_call(EDT))
%
% cw[[ Call, EDT ]] =
% aw[[ Call, EDT ]] , if Call is a proc with
% a wrong answer version
% (Call, EDT = assumed) , otherwise
%
% aw[[ foo(A1, ..., An), EDT ]] =
% foo(A1, ..., An, EDT)
%
% XXXs:
%
% - The transformation as described does not do anything useful for
% higher order calls or calls to external predicates (it treats
% them as it will treat builtins in future). This means that any
% front end will act as if it assumes such calls are correct, and
% it will not search them for bug instances. This will change
% when more support for external calls (firstly) and higher order
% calls (secondly) is added.
%
% - According to the above transformation, proof trees will in
% general contain a large number of trivial subtrees which are
% usually not useful. As an optimisation, the actual
% transformation avoids building trivial subtrees where possible.
% The consequence of this is that proof trees built for
% conjunctions will _not_ always be of the form conj([Pn, ..., P1]).
% Some of the subtrees will not be included in the list, so it
% could be of the form (say) conj([P6, P5, P3, P1]). However, a
% front end can still use this effectively if we record which
% conjunct corresponds to each list member, or if we always decide
% in a consistent way which ones to exclude.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module proof_tree.
:- interface.
:- import_module hlds_module, hlds_pred, evaluation_tree_util.
%
% Perform the transformation on the proc referred to by the
% edt_proc_info.
%
:- pred proof_tree__create_proc(module_info, edt_info, edt_proc_info,
module_info).
:- mode proof_tree__create_proc(in, in, in, out) is det.
%
% Make a predicate with the required signature. Used by the
% first pass of the evaluation_tree compiler phase.
%
:- pred make_wrong_answer_pred_stub(edt_info, module_info, pred_id, pred_info).
:- mode make_wrong_answer_pred_stub(in, in, in, out) is det.
%
% Make the procedure which converts an atom to a closure with
% that atom as a goal.
%
:- pred proof_tree__make_wrong_analysis_pred(module_info, edt_info, pred_info).
:- mode proof_tree__make_wrong_analysis_pred(in, in, out) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, hlds_data, prog_data, (inst), globals, instmap.
:- import_module map, std_util, term, list, require, int, varset, set.
proof_tree__create_proc(Module0, EDTInfo, EDTProcInfo, Module) :-
edt_proc_info_get_wrong_proc(EDTProcInfo, WrongPredId, WrongProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, WrongPredId, WrongPredInfo0),
pred_info_procedures(WrongPredInfo0, WrongProcs0),
map__lookup(WrongProcs0, WrongProcId, ProcInfo0),
transform_proc(EDTInfo, EDTProcInfo, ProcInfo0, ProcInfo),
map__det_update(WrongProcs0, WrongProcId, ProcInfo, WrongProcs),
pred_info_set_procedures(WrongPredInfo0, WrongProcs, WrongPredInfo),
map__det_update(PredTable0, WrongPredId, WrongPredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module).
:- pred transform_proc(edt_info, edt_proc_info, proc_info, proc_info).
:- mode transform_proc(in, in, in, out) is det.
transform_proc(EDTInfo, EDTProcInfo, ProcInfo0, ProcInfo) :-
proc_info_goal(ProcInfo0, Goal0),
Goal0 = GoalExpr0 - GoalInfo0,
transform_goal(EDTInfo, ProcInfo0, ProcInfo1, GoalExpr0, GoalInfo0,
MaybeProofVar, GoalExpr1, GoalInfo1),
maybe_add_trivial_proof(EDTInfo, ProcInfo1, ProcInfo2, GoalExpr1,
GoalInfo1, GoalExpr2, GoalInfo2, MaybeProofVar,
ProofVar),
goal_to_conj_list(GoalExpr2 - GoalInfo2, GoalList0),
make_node_construction(EDTInfo, EDTProcInfo, ProcInfo2, ProcInfo3,
NodeVar, NodeConsGoals),
%
% We use the unmodified hlds_goal_info as input here
% because the proof_tree variable is not nonlocal in the
% outer conjunction.
%
create_evaluation_tree_head_var(EDTInfo, ProcInfo3, ProcInfo4,
GoalInfo0, GoalInfo, EDTVar),
evaluation_tree_ctor_analyse_wrong(EDTConsId),
make_simple_construction(EDTVar, EDTConsId, [NodeVar, ProofVar],
EDTConsGoal),
list__append(NodeConsGoals, [EDTConsGoal], GoalList1),
list__append(GoalList0, GoalList1, GoalList),
Goal = conj(GoalList) - GoalInfo,
proc_info_set_goal(ProcInfo4, Goal, ProcInfo).
:- pred make_node_construction(edt_info, edt_proc_info, proc_info, proc_info,
var, hlds_goals).
:- mode make_node_construction(in, in, in, out, out, out) is det.
make_node_construction(EDTInfo, EDTProcInfo, ProcInfo0, ProcInfo, Var,
Goals) :-
%
% For wrong answer analysis, a node is just an atom in
% its final instantiatedness state.
%
make_final_atom_construction(EDTInfo, EDTProcInfo, ProcInfo0, ProcInfo,
Var, Goals).
:- pred transform_goal(edt_info, proc_info, proc_info, hlds_goal_expr,
hlds_goal_info, maybe(var), hlds_goal_expr, hlds_goal_info).
:- mode transform_goal(in, in, out, in, in, out, out, out) is det.
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = conj(Goals0),
create_proof_tree_list_var(EDTInfo, ProcInfo0, ProcInfo1,
ProofListVar0),
library_ctor_list_nil(NilConsId),
make_simple_construction(ProofListVar0, NilConsId, [], InitGoal),
transform_conj_list(EDTInfo, ProcInfo1, ProcInfo2, ProofListVar0,
ProofListVar, Goals0, [InitGoal], Goals1),
create_proof_tree_var(EDTInfo, ProcInfo2, ProcInfo, GoalInfo0,
GoalInfo, ProofVar),
proof_tree_ctor_conj(ConjConsId),
make_simple_construction(ProofVar, ConjConsId, [ProofListVar],
NewGoal),
list__append(Goals1, [NewGoal], Goals),
GoalExpr = conj(Goals).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = call(PredId, ProcId, Args, BuiltinState, Context,
SymName),
transform_call(EDTInfo, ProcInfo0, ProcInfo, PredId, ProcId, Args,
BuiltinState, Context, SymName, GoalInfo0, ProofVar,
GoalExpr, GoalInfo).
transform_goal(_EDTInfo, ProcInfo, ProcInfo, GoalExpr, GoalInfo, no,
GoalExpr, GoalInfo) :-
GoalExpr = higher_order_call(_, _, _, _, _, _).
transform_goal(_EDTInfo, ProcInfo, ProcInfo, GoalExpr, GoalInfo, no,
GoalExpr, GoalInfo) :-
GoalExpr = class_method_call(_, _, _, _, _, _).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = switch(SwitchVar, CanFail, Cases0, StoreMap),
create_proof_tree_var(EDTInfo, ProcInfo0, ProcInfo1, GoalInfo0,
GoalInfo, ProofVar),
list__map_foldl(transform_switch_case(EDTInfo, ProofVar),
Cases0, Cases, ProcInfo1, ProcInfo),
GoalExpr = switch(SwitchVar, CanFail, Cases, StoreMap).
transform_goal(_EDTInfo, ProcInfo, ProcInfo, GoalExpr, GoalInfo, no,
GoalExpr, GoalInfo) :-
GoalExpr = unify(_, _, _, _, _).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = disj(Goals0, StoreMap),
create_proof_tree_var(EDTInfo, ProcInfo0, ProcInfo1, GoalInfo0,
GoalInfo, ProofVar),
list__map_foldl(transform_disjunct(EDTInfo, ProofVar),
Goals0, Goals, ProcInfo1, ProcInfo),
GoalExpr = disj(Goals, StoreMap).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = not(NegatedGoalExpr - NegatedGoalInfo),
transform_negated_context(EDTInfo, ProcInfo0, ProcInfo1,
NegatedGoalExpr, NegatedGoalInfo, MissTreeVar,
NewGoal1),
create_proof_tree_var(EDTInfo, ProcInfo1, ProcInfo, GoalInfo0,
GoalInfo, ProofVar),
proof_tree_ctor_not(NotConsId),
make_simple_construction(ProofVar, NotConsId, [MissTreeVar], NewGoal2),
GoalList = [GoalExpr0 - GoalInfo0, NewGoal1, NewGoal2],
GoalExpr = conj(GoalList).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
MaybeProofVar, GoalExpr, GoalInfo) :-
GoalExpr0 = some(Vars, GoalExpr1 - GoalInfo1),
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr1, GoalInfo1,
MaybeProofVar, GoalExpr2, GoalInfo2),
GoalExpr = some(Vars, GoalExpr2 - GoalInfo2),
(
MaybeProofVar = yes(ProofVar)
->
goal_info_set_nonlocal_grounded(GoalInfo0, ProofVar, GoalInfo)
;
GoalInfo = GoalInfo0
).
transform_goal(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
yes(ProofVar), GoalExpr, GoalInfo) :-
GoalExpr0 = if_then_else(Locals, CondGoal, ThenGoal, ElseGoal,
StoreMap),
transform_if_then_else(EDTInfo, ProcInfo0, ProcInfo, Locals,
CondGoal, ThenGoal, ElseGoal, StoreMap, GoalInfo0,
ProofVar, GoalExpr, GoalInfo).
transform_goal(_EDTInfo, ProcInfo, ProcInfo, GoalExpr, GoalInfo, no,
GoalExpr, GoalInfo) :-
GoalExpr = pragma_c_code(_, _, _, _, _, _, _).
transform_goal(_EDTInfo, ProcInfo, ProcInfo, GoalExpr, GoalInfo, no,
GoalExpr, GoalInfo) :-
GoalExpr = par_conj(_, _).
:- pred transform_conj_list(edt_info, proc_info, proc_info, var, var,
hlds_goals, hlds_goals, hlds_goals).
:- mode transform_conj_list(in, in, out, in, out, in, in, out) is det.
transform_conj_list(EDTInfo, ProcInfo0, ProcInfo, ProofListVar0, ProofListVar,
[InGoal | InGoals], OutGoals0, OutGoals) :-
InGoal = GoalExpr0 - GoalInfo0,
transform_goal(EDTInfo, ProcInfo0, ProcInfo1, GoalExpr0, GoalInfo0,
MaybeProofVar, GoalExpr1, GoalInfo1),
Goal1 = GoalExpr1 - GoalInfo1,
prepend_goal_to_rev_goal_list(Goal1, OutGoals0, OutGoals1),
(
MaybeProofVar = yes(ProofVar)
->
create_proof_tree_list_var(EDTInfo, ProcInfo1, ProcInfo2,
ProofListVar1),
library_ctor_list_cons(ListConsId),
make_simple_construction(ProofListVar1, ListConsId,
[ProofVar, ProofListVar0], NewGoal),
prepend_goal_to_rev_goal_list(NewGoal, OutGoals1, OutGoals2),
LastProof = ProofListVar1
;
ProcInfo2 = ProcInfo1,
OutGoals2 = OutGoals1,
LastProof = ProofListVar0
),
transform_conj_list(EDTInfo, ProcInfo2, ProcInfo, LastProof,
ProofListVar, InGoals, OutGoals2, OutGoals).
transform_conj_list(_EDTInfo, ProcInfo, ProcInfo, ProofVar, ProofVar,
[], OutGoals0, OutGoals) :-
%
% OutGoals0 has accumulated the goals in reverse order, so
% at the end we reverse again before returning.
%
list__reverse(OutGoals0, OutGoals).
:- pred transform_call(edt_info, proc_info, proc_info, pred_id, proc_id,
list(var), builtin_state, maybe(call_unify_context), sym_name,
hlds_goal_info, var, hlds_goal_expr, hlds_goal_info).
:- mode transform_call(in, in, out, in, in, in, in, in, in, in, out, out, out)
is det.
transform_call(EDTInfo, ProcInfo0, ProcInfo, PredId0, ProcId0, Args0,
BuiltinState, Context, SymName0, GoalInfo0, ProofVar,
GoalExpr, GoalInfo) :-
create_evaluation_tree_var(EDTInfo, ProcInfo0, ProcInfo1, GoalInfo0,
GoalInfo1, EDTVar),
create_proof_tree_var(EDTInfo, ProcInfo1, ProcInfo, GoalInfo1,
GoalInfo, ProofVar),
%
% Here we assume that the call is local. If the call is
% actually external, then at the moment we treat it as
% if it is assumed correct.
%
proof_tree_ctor_local_call(CallConsId),
make_simple_construction(ProofVar, CallConsId, [EDTVar], NewGoal0),
GoalList0 = [NewGoal0],
edt_info_proc_analysis(EDTInfo, PredId0, ProcId0, Analysis),
((
Analysis = wrong_answer_analysis(PredId, ProcId)
;
Analysis = full_analysis(PredId, ProcId, _, _)
) ->
list__append(Args0, [EDTVar], Args),
wrong_answer_sym_name_mangle(SymName0, SymName),
NewGoalExpr = call(PredId, ProcId, Args, BuiltinState,
Context, SymName),
%
% GoalInfo1 has EDTVar added to the nonlocals,
% and going to ground in the instmap_delta.
%
GoalList = [NewGoalExpr - GoalInfo1 | GoalList0]
;
evaluation_tree_ctor_assumed(AssumedConsId),
make_simple_construction(EDTVar, AssumedConsId, [],
NewGoal1),
GoalList1 = [NewGoal1 | GoalList0],
GoalExpr0 = call(PredId0, ProcId0, Args0, BuiltinState,
Context, SymName0),
GoalList = [GoalExpr0 - GoalInfo0 | GoalList1]
),
GoalExpr = conj(GoalList).
:- pred transform_switch_case(edt_info, var, case, case, proc_info, proc_info).
:- mode transform_switch_case(in, in, in, out, in, out) is det.
transform_switch_case(EDTInfo, ProofVar, Case0, Case, ProcInfo0, ProcInfo) :-
Case0 = case(ConsId, GoalExpr0 - GoalInfo0),
transform_goal(EDTInfo, ProcInfo0, ProcInfo1, GoalExpr0, GoalInfo0,
MaybeCaseProofVar, GoalExpr1, GoalInfo1),
maybe_add_trivial_proof(EDTInfo, ProcInfo1, ProcInfo2, GoalExpr1,
GoalInfo1, GoalExpr2, GoalInfo2, MaybeCaseProofVar,
CaseProofVar),
goal_to_conj_list(GoalExpr2 - GoalInfo2, GoalList0),
make_arm_id_construction(GoalInfo0, ProcInfo2, ProcInfo, ArmIdVar,
NewGoal1),
proof_tree_ctor_switch(SwitchConsId),
make_simple_construction(ProofVar, SwitchConsId,
[ArmIdVar, CaseProofVar], NewGoal2),
list__append(GoalList0, [NewGoal1, NewGoal2], GoalList),
%
% We must update the nonlocals and instmap_delta for
% this switch arm.
%
goal_info_set_nonlocal_grounded(GoalInfo0, ProofVar, GoalInfo),
Case = case(ConsId, conj(GoalList) - GoalInfo).
:- pred transform_disjunct(edt_info, var, hlds_goal, hlds_goal, proc_info,
proc_info).
:- mode transform_disjunct(in, in, in, out, in, out) is det.
transform_disjunct(EDTInfo, ProofVar, Goal0, Goal, ProcInfo0, ProcInfo) :-
Goal0 = GoalExpr0 - GoalInfo0,
transform_goal(EDTInfo, ProcInfo0, ProcInfo1, GoalExpr0, GoalInfo0,
MaybeDisjProofVar, GoalExpr1, GoalInfo1),
maybe_add_trivial_proof(EDTInfo, ProcInfo1, ProcInfo2, GoalExpr1,
GoalInfo1, GoalExpr2, GoalInfo2, MaybeDisjProofVar,
DisjProofVar),
goal_to_conj_list(GoalExpr2 - GoalInfo2, GoalList0),
make_arm_id_construction(GoalInfo0, ProcInfo2, ProcInfo, ArmIdVar,
NewGoal1),
proof_tree_ctor_disj(DisjConsId),
make_simple_construction(ProofVar, DisjConsId,
[ArmIdVar, DisjProofVar], NewGoal2),
list__append(GoalList0, [NewGoal1, NewGoal2], GoalList),
%
% We must update the nonlocals and instmap_delta for
% this disjunct.
%
goal_info_set_nonlocal_grounded(GoalInfo0, ProofVar, GoalInfo),
Goal = conj(GoalList) - GoalInfo.
:- pred make_arm_id_construction(hlds_goal_info, proc_info, proc_info, var,
hlds_goal).
:- mode make_arm_id_construction(in, in, out, out, out) is det.
make_arm_id_construction(GoalInfo, ProcInfo0, ProcInfo, ArmIdVar, NewGoal) :-
create_int_var(ProcInfo0, ArmIdVar, ProcInfo),
get_arm_identifier(GoalInfo, ArmId),
make_simple_construction(ArmIdVar, int_const(ArmId), [], NewGoal).
:- pred get_arm_identifier(hlds_goal_info, int).
:- mode get_arm_identifier(in, out) is det.
get_arm_identifier(GoalInfo, ArmId) :-
goal_info_get_goal_path(GoalInfo, GoalPath),
(
(
GoalPath = [switch(ArmId0) | _]
;
GoalPath = [disj(ArmId0) | _]
)
->
ArmId = ArmId0
;
error("get_arm_identifier: not a switch or disj")
).
:- pred transform_if_then_else(edt_info, proc_info, proc_info, list(var),
hlds_goal, hlds_goal, hlds_goal, store_map, hlds_goal_info,
var, hlds_goal_expr, hlds_goal_info).
:- mode transform_if_then_else(in, in, out, in, in, in, in, in, in, out, out,
out) is det.
transform_if_then_else(EDTInfo, ProcInfo0, ProcInfo, Locals0, CondGoal0,
ThenGoal0, ElseGoal0, StoreMap, GoalInfo0, ProofVar,
GoalExpr, GoalInfo) :-
create_proof_tree_var(EDTInfo, ProcInfo0, ProcInfo1, GoalInfo0,
GoalInfo, ProofVar),
CondGoal0 = CondGoalExpr0 - CondGoalInfo0,
transform_goal(EDTInfo, ProcInfo1, ProcInfo2, CondGoalExpr0,
CondGoalInfo0, MaybeCondProofVar, CondGoalExpr1,
CondGoalInfo1),
maybe_add_trivial_proof(EDTInfo, ProcInfo2, ProcInfo3, CondGoalExpr1,
CondGoalInfo1, CondGoalExpr, CondGoalInfo,
MaybeCondProofVar, CondProofVar),
Locals = [CondProofVar | Locals0],
CondGoal = CondGoalExpr - CondGoalInfo,
ThenGoal0 = ThenGoalExpr0 - ThenGoalInfo0,
%
% We can throw out the hlds_goal_info because the
% proof_tree for the `then' branch is not nonlocal -- it
% is used immediately to construct the proof_tree for
% the entire goal.
%
transform_goal(EDTInfo, ProcInfo3, ProcInfo4, ThenGoalExpr0,
ThenGoalInfo0, MaybeThenProofVar, ThenGoalExpr1, _),
maybe_add_trivial_proof(EDTInfo, ProcInfo4, ProcInfo5, ThenGoalExpr1,
ThenGoalInfo0, ThenGoalExpr2, _, MaybeThenProofVar,
ThenProofVar),
%
% The proof_tree variables for the condition and for the
% entire if_then_else are nonlocal to the `then' branch.
%
goal_info_add_nonlocal(ThenGoalInfo0, CondProofVar, ThenGoalInfo1),
goal_info_set_nonlocal_grounded(ThenGoalInfo1, ProofVar,
ThenGoalInfo2),
ThenGoal2 = ThenGoalExpr2 - ThenGoalInfo2,
proof_tree_ctor_if_then(IfThenConsId),
make_simple_construction(ProofVar, IfThenConsId,
[CondProofVar, ThenProofVar], ExtraThenGoal),
conjoin_goals(ThenGoal2, ExtraThenGoal, ThenGoal),
ElseGoal0 = ElseGoalExpr0 - ElseGoalInfo0,
%
% We can throw out the hlds_goal_info because the
% proof_tree for the `else' branch is not nonlocal -- it
% is used immediately to construct the proof_tree for
% the entire goal.
%
transform_goal(EDTInfo, ProcInfo5, ProcInfo6, ElseGoalExpr0,
ElseGoalInfo0, MaybeElseProofVar, ElseGoalExpr1, _),
maybe_add_trivial_proof(EDTInfo, ProcInfo6, ProcInfo7, ElseGoalExpr1,
ElseGoalInfo0, ElseGoalExpr2, _, MaybeElseProofVar,
ElseProofVar),
%
% This variable is nonlocal to the `else' goal as well
% as the entire if_then_else.
%
goal_info_set_nonlocal_grounded(ElseGoalInfo0, ProofVar,
ElseGoalInfo2),
ElseGoal2 = ElseGoalExpr2 - ElseGoalInfo2,
transform_negated_context(EDTInfo, ProcInfo7, ProcInfo, ElseGoalExpr2,
ElseGoalInfo2, MissTreeVar, ExtraElseGoal1),
conjoin_goals(ElseGoal2, ExtraElseGoal1, ElseGoal3),
proof_tree_ctor_else(ElseConsId),
make_simple_construction(ProofVar, ElseConsId,
[MissTreeVar, ElseProofVar], ExtraElseGoal2),
conjoin_goals(ElseGoal3, ExtraElseGoal2, ElseGoal),
GoalExpr = if_then_else(Locals, CondGoal, ThenGoal, ElseGoal,
StoreMap).
:- pred transform_negated_context(edt_info, proc_info, proc_info,
hlds_goal_expr, hlds_goal_info, var, hlds_goal).
:- mode transform_negated_context(in, in, out, in, in, out, out) is det.
transform_negated_context(EDTInfo, ProcInfo0, ProcInfo, _NegatedGoalExpr,
NegatedGoalInfo, MissTreeVar, Goal) :-
create_miss_tree_var(EDTInfo, ProcInfo0, ProcInfo, NegatedGoalInfo, _,
MissTreeVar),
%
% XXX For the moment, miss_trees are always trivial.
%
miss_tree_ctor_trivial(TrivialConsId),
make_simple_construction(MissTreeVar, TrivialConsId, [], Goal).
:- pred maybe_add_trivial_proof(edt_info, proc_info, proc_info, hlds_goal_expr,
hlds_goal_info, hlds_goal_expr, hlds_goal_info, maybe(var),
var).
:- mode maybe_add_trivial_proof(in, in, out, in, in, out, out, in, out) is det.
maybe_add_trivial_proof(EDTInfo, ProcInfo0, ProcInfo, GoalExpr0, GoalInfo0,
GoalExpr, GoalInfo, MaybeProofVar, ProofVar) :-
(
MaybeProofVar = yes(ProofVar0)
->
ProcInfo = ProcInfo0,
GoalExpr = GoalExpr0,
GoalInfo = GoalInfo0,
ProofVar = ProofVar0
;
create_proof_tree_var(EDTInfo, ProcInfo0, ProcInfo,
GoalInfo0, _, ProofVar),
proof_tree_ctor_trivial(TrivialConsId),
make_simple_construction(ProofVar, TrivialConsId, [],
ExtraGoal),
conjoin_goals(GoalExpr0 - GoalInfo0, ExtraGoal,
GoalExpr - GoalInfo)
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
make_wrong_answer_pred_stub(EDTInfo, Module, PredId, NewPredInfo) :-
module_info_pred_info(Module, PredId, PredInfo),
pred_info_arg_types(PredInfo, ArgTypeVarSet, ExistQTVars, ArgTypes0),
pred_info_clauses_info(PredInfo, ClausesInfo),
pred_info_context(PredInfo, Context),
pred_info_module(PredInfo, ModuleName),
pred_info_name(PredInfo, PredName0),
pred_info_arity(PredInfo, Arity0),
pred_info_import_status(PredInfo, ImportStatus),
pred_info_get_goal_type(PredInfo, GoalType),
pred_info_get_markers(PredInfo, Markers),
pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
pred_info_get_class_context(PredInfo, ClassContext),
pred_info_get_constraint_proofs(PredInfo, ClassProofs),
%
% The new predicate has an extra argument.
%
Arity = Arity0 + 1,
edt_info_evaluation_tree_type(EDTInfo, EDTType),
list__append(ArgTypes0, [EDTType], ArgTypes),
wrong_answer_name_mangle(PredName0, PredName),
%
% This creates a predicate with no procedures. We will
% add them later.
%
pred_info_init(ModuleName, unqualified(PredName), Arity, ArgTypeVarSet,
ExistQTVars, ArgTypes, true, Context, ClausesInfo,
ImportStatus, Markers, GoalType, PredOrFunc, ClassContext,
ClassProofs, NewPredInfo).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
proof_tree__make_wrong_analysis_pred(Module, EDTInfo, PredInfo) :-
edt_info_get_module_name(EDTInfo, ModuleName),
wrong_analysis_pred_sym_name(ModuleName, SymName),
make_wrong_analysis_proc(EDTInfo, ProcInfo0, AtomType, AnalysisType),
make_wrong_analysis_proc_body(Module, EDTInfo, ProcInfo0, ProcInfo),
varset__init(TVarSet),
generated_code_context(Context),
init_markers(PredMarkers),
ClassConstraints = constraints([], []),
pred_info_create(ModuleName, SymName, TVarSet, [],
[AtomType, AnalysisType], true, Context, exported,
PredMarkers, predicate, ClassConstraints, ProcInfo, _,
PredInfo).
:- pred make_wrong_analysis_proc(edt_info, proc_info, (type), (type)).
:- mode make_wrong_analysis_proc(in, out, out, out) is det.
make_wrong_analysis_proc(EDTInfo, ProcInfo, AtomType, AnalysisType) :-
ground_inst(Ground),
Arity = 2,
edt_info_evaluation_atom_type(EDTInfo, AtomType),
edt_info_analysis_type(EDTInfo, AnalysisType),
generated_code_context(Context),
local_analysis_inst(AnalysisInst),
HeadModes = [(Ground -> Ground), (free -> AnalysisInst)],
edt_info_get_globals(EDTInfo, Globals),
globals__get_args_method(Globals, ArgsMethod),
proc_info_init(Arity, HeadModes, no, no, no, Context, ArgsMethod,
ProcInfo0),
proc_info_set_inferred_determinism(ProcInfo0, semidet, ProcInfo1),
proc_info_headvars(ProcInfo1, HeadVars),
(
HeadVars = [H1, H2]
->
map__from_assoc_list([H1 - AtomType, H2 - AnalysisType],
VarTypes),
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo)
;
error("make_wrong_analysis_proc: wrong arity")
).
:- pred make_wrong_analysis_proc_body(module_info, edt_info, proc_info,
proc_info).
:- mode make_wrong_analysis_proc_body(in, in, in, out) is det.
make_wrong_analysis_proc_body(Module, EDTInfo, ProcInfo0, ProcInfo) :-
proc_info_headvars(ProcInfo0, HeadVars),
(
HeadVars = [H1, H2]
->
HeadVar1 = H1,
HeadVar2 = H2
;
error("make_wrong_analysis_proc_body: wrong arity")
),
edt_info_get_proc_map(EDTInfo, ProcMap),
map__values(ProcMap, EDTProcInfos),
list__map_foldl(make_wrong_analysis_case(Module, EDTInfo, HeadVar1,
HeadVar2), EDTProcInfos, AtomCases, ProcInfo0,
ProcInfo1),
map__init(StoreMap),
GoalExpr = switch(HeadVar1, can_fail, AtomCases, StoreMap),
set__list_to_set(HeadVars, NonLocals),
ground_inst(Ground),
instmap_delta_from_assoc_list([HeadVar2 - Ground], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, semidet, GoalInfo),
proc_info_set_goal(ProcInfo1, GoalExpr - GoalInfo, ProcInfo).
:- pred make_wrong_analysis_case(module_info, edt_info, var, var,
edt_proc_info, case, proc_info, proc_info).
:- mode make_wrong_analysis_case(in, in, in, in, in, out, in, out) is det.
make_wrong_analysis_case(Module, EDTInfo, HeadVar1, HeadVar2, EDTProcInfo,
Case, ProcInfo0, ProcInfo) :-
(
wrong_analysis_is_available(EDTProcInfo)
->
make_wrong_analysis_case_1(Module, EDTInfo, HeadVar1, HeadVar2,
EDTProcInfo, Case, ProcInfo0, ProcInfo)
;
analysis_ctor_unavailable(AnalysisConsId),
make_simple_construction(HeadVar2, AnalysisConsId, [], Goal),
edt_proc_info_initial_cons_id(EDTProcInfo, AtomConsId),
Case = case(AtomConsId, Goal),
ProcInfo = ProcInfo0
).
%
% This predicate temporarily exists to allow us to restrict
% what can be attempted while functionality is still being
% added. This predicate will ultimately be of no purpose and
% will be removed.
%
:- pred wrong_analysis_is_available(edt_proc_info).
:- mode wrong_analysis_is_available(in) is semidet.
wrong_analysis_is_available(EDTProcInfo) :-
edt_proc_info_get_atom_descriptor(EDTProcInfo, AtomDesc),
not (some [Arg] (
list__member(Arg, AtomDesc),
Arg \= direct_var(_, _, _)
)).
:- pred make_wrong_analysis_case_1(module_info, edt_info, var, var,
edt_proc_info, case, proc_info, proc_info).
:- mode make_wrong_analysis_case_1(in, in, in, in, in, out, in, out) is det.
make_wrong_analysis_case_1(Module, EDTInfo, HeadVar1, HeadVar2, EDTProcInfo,
Case, ProcInfo0, ProcInfo) :-
set__list_to_set([HeadVar1, HeadVar2], NonLocals),
ground_inst(Ground),
instmap_delta_from_assoc_list([HeadVar2 - Ground], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, semidet, GoalInfo),
make_atom_deconstruction(EDTInfo, EDTProcInfo, HeadVar1, ArgVars,
ProcInfo0, ProcInfo1, ArgGoals),
%
% XXX We should be more accurate with the determinism
% here, rather than just treating everything as nondet.
%
make_wrong_closure_construction(Module, EDTInfo, EDTProcInfo, ArgVars,
nondet, ProcInfo1, ProcInfo, ClosureVar, ClosureGoal),
analysis_ctor_nondet_wrong(AnalysisConsId),
make_simple_construction(HeadVar2, AnalysisConsId, [ClosureVar],
AnalysisGoal),
edt_proc_info_initial_cons_id(EDTProcInfo, InitialConsId),
list__append(ArgGoals, [ClosureGoal, AnalysisGoal], GoalList),
CaseGoal = conj(GoalList) - GoalInfo,
Case = case(InitialConsId, CaseGoal).
:- pred make_wrong_closure_construction(module_info, edt_info, edt_proc_info,
list(var), determinism, proc_info, proc_info, var, hlds_goal).
:- mode make_wrong_closure_construction(in, in, in, in, in, in, out, out, out)
is det.
make_wrong_closure_construction(Module, EDTInfo, EDTProcInfo, ArgVars, Detism,
ProcInfo0, ProcInfo, ClosureVar, Goal) :-
create_closure_var(EDTInfo, ProcInfo0, ProcInfo1, ClosureVar),
set__list_to_set([ClosureVar | ArgVars], NonLocals),
ground_inst(Ground),
instmap_delta_from_assoc_list([ClosureVar - Ground], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
%
% We can throw out the modified hlds_goal_info because this
% proof_tree variable is lambda quantified, not nonlocal.
%
create_evaluation_tree_var(EDTInfo, ProcInfo1, ProcInfo, GoalInfo, _,
LambdaVar),
edt_proc_info_get_wrong_proc(EDTProcInfo, PredId, ProcId),
%
% SymName is only used for hlds dumps.
%
module_info_pred_info(Module, PredId, PredInfo),
pred_info_name(PredInfo, PredName),
SymName = unqualified(PredName),
make_closure_construction(ClosureVar, SymName, PredId, ProcId,
LambdaVar, ArgVars, Detism, GoalExpr),
Goal = GoalExpr - GoalInfo.
:- pred make_atom_deconstruction(edt_info, edt_proc_info, var, list(var),
proc_info, proc_info, hlds_goals).
:- mode make_atom_deconstruction(in, in, in, out, in, out, out) is det.
make_atom_deconstruction(EDTInfo, EDTProcInfo, AtomVar, ArgVars, ProcInfo0,
ProcInfo, Goals) :-
edt_proc_info_get_atom_descriptor(EDTProcInfo, AtomDesc),
make_call_arguments(EDTInfo, AtomDesc, ArgVars, ConsVars, ProcInfo0,
ProcInfo, ArgGoals),
edt_proc_info_initial_cons_id(EDTProcInfo, ConsId),
make_simple_deconstruction(AtomVar, ConsId, ConsVars, Goal1),
Goals = [Goal1 | ArgGoals].
:- pred make_call_arguments(edt_info, atom_descriptor, list(var), list(var),
proc_info, proc_info, hlds_goals).
:- mode make_call_arguments(in, in, out, out, in, out, out) is det.
make_call_arguments(_, [], [], [], ProcInfo, ProcInfo, []).
make_call_arguments(EDTInfo, [AtomArg | AtomArgs], [ArgVar | ArgVars],
[ConsVar | ConsVars], ProcInfo0, ProcInfo, Goals) :-
AtomArg = direct_var(_, _, ArgType),
proc_info_create_var_from_type(ProcInfo0, ArgType, ArgVar, ProcInfo1),
ConsVar = ArgVar,
make_call_arguments(EDTInfo, AtomArgs, ArgVars, ConsVars, ProcInfo1,
ProcInfo, Goals).
make_call_arguments(EDTInfo, [AtomArg | AtomArgs], [ArgVar | ArgVars],
[ConsVar | ConsVars], ProcInfo0, ProcInfo, Goals) :-
AtomArg = univ_var(_, _, ArgType),
proc_info_create_var_from_type(ProcInfo0, ArgType, ArgVar, ProcInfo1),
create_univ_var(ProcInfo1, ConsVar, ProcInfo2),
%
% XXX this actually needs to call univ_value
%
make_from_univ_call(EDTInfo, ArgVar, ConsVar, Goal0),
make_call_arguments(EDTInfo, AtomArgs, ArgVars, ConsVars, ProcInfo2,
ProcInfo, Goals0),
Goals = [Goal0 | Goals0].
make_call_arguments(EDTInfo, [AtomArg | AtomArgs], ArgVars, ConsVars,
ProcInfo0, ProcInfo, Goals) :-
AtomArg = io_state_di(_, _),
make_call_arguments(EDTInfo, AtomArgs, ArgVars, ConsVars, ProcInfo0,
ProcInfo, Goals).
make_call_arguments(EDTInfo, [AtomArg | AtomArgs], ArgVars, ConsVars,
ProcInfo0, ProcInfo, Goals) :-
AtomArg = io_state_uo(_, _),
make_call_arguments(EDTInfo, AtomArgs, ArgVars, ConsVars, ProcInfo0,
ProcInfo, Goals).
More information about the developers
mailing list