[m-rev.] diff: break up big predicate
Zoltan Somogyi
zs at cs.mu.OZ.AU
Fri Feb 17 14:22:35 AEDT 2006
compiler/det_analysis.m:
Break up a predicate whose code used to be 441(!) lines long
into manageable pieces. There are no algorithmic changes.
Zoltan.
cvs diff: Diffing .
Index: det_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/det_analysis.m,v
retrieving revision 1.184
diff -u -b -r1.184 det_analysis.m
--- det_analysis.m 27 Jan 2006 05:52:03 -0000 1.184
+++ det_analysis.m 13 Feb 2006 08:02:05 -0000
@@ -502,7 +502,126 @@
GoalExpr = conj(Goals)
;
GoalExpr0 = par_conj(Goals0),
- det_infer_par_conj(Goals0, Goals, InstMap0, SolnContext,
+ det_infer_par_conj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
+ !:Msgs),
+ GoalExpr = par_conj(Goals)
+ ;
+ GoalExpr0 = disj(Goals0),
+ det_infer_disj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
+ !:Msgs),
+ GoalExpr = disj(Goals)
+ ;
+ GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
+ det_infer_switch(Var, SwitchCanFail, Cases0, Cases, GoalInfo, InstMap0,
+ SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs),
+ GoalExpr = switch(Var, SwitchCanFail, Cases)
+ ;
+ GoalExpr0 = call(PredId, ProcId0, Args, Builtin, UnifyContext, Name),
+ det_infer_call(PredId, ProcId0, ProcId, GoalInfo, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
+ !:Msgs),
+ GoalExpr = call(PredId, ProcId, Args, Builtin, UnifyContext, Name)
+ ;
+ GoalExpr0 = generic_call(GenericCall, _ArgVars, _Modes, CallDetism),
+ det_infer_generic_call(GenericCall, CallDetism, GoalInfo, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
+ !:Msgs),
+ GoalExpr = GoalExpr0
+ ;
+ GoalExpr0 = unify(LHS, RHS0, Mode, Unify, UnifyContext),
+ det_infer_unify(LHS, RHS0, Unify, UnifyContext, RHS, GoalInfo,
+ InstMap0, SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs),
+ GoalExpr = unify(LHS, RHS, Mode, Unify, UnifyContext)
+ ;
+ GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
+ det_infer_if_then_else(Cond0, Cond, Then0, Then, Else0, Else,
+ InstMap0, SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs),
+ GoalExpr = if_then_else(Vars, Cond, Then, Else)
+ ;
+ GoalExpr0 = not(Goal0),
+ det_infer_not(Goal0, Goal, GoalInfo, InstMap0, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs),
+ GoalExpr = not(Goal)
+ ;
+ GoalExpr0 = scope(Reason, Goal0),
+ det_infer_scope(Reason, Goal0, Goal, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
+ !:Msgs),
+ GoalExpr = scope(Reason, Goal)
+ ;
+ GoalExpr0 = foreign_proc(Attributes, PredId, ProcId, _Args, _ExtraArgs,
+ PragmaCode),
+ det_infer_foreign_proc(Attributes, PredId, ProcId, PragmaCode,
+ GoalInfo, SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs),
+ GoalExpr = GoalExpr0
+ ;
+ GoalExpr0 = shorthand(_),
+ % These should have been expanded out by now.
+ unexpected(this_file, "det_infer_goal_2: unexpected shorthand")
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred det_infer_conj(list(hlds_goal)::in, list(hlds_goal)::out, instmap::in,
+ soln_context::in, list(failing_context)::in, det_info::in,
+ determinism::out, list(failing_context)::in, list(failing_context)::out,
+ list(context_det_msg)::out) is det.
+
+det_infer_conj([], [], _InstMap0, _SolnContext, _RightFailingContexts,
+ _DetInfo, det, !ConjFailingContexts, []).
+det_infer_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, !ConjFailingContexts, Msgs) :-
+ % We should look to see when we get to a not_reached point
+ % and optimize away the remaining elements of the conjunction.
+ % But that optimization is done in the code generator anyway.
+
+ % We infer the determinisms right-to-left, so that we can propagate
+ % the SolnContext properly.
+
+ % First, process the second and subsequent conjuncts.
+ update_instmap(Goal0, InstMap0, InstMap1),
+ det_infer_conj(Goals0, Goals, InstMap1, SolnContext,
+ RightFailingContexts, DetInfo, TailDetism, !ConjFailingContexts,
+ TailMsgs),
+ determinism_components(TailDetism, TailCanFail, _TailMaxSolns),
+
+ % Next, work out whether the first conjunct is in a first_soln context
+ % or not. We obviously need all its solutions if we need all the solutions
+ % of the conjunction. However, even if we need only the first solution
+ % of the conjunction, we may need to generate more than one solution
+ % of the first conjunct if the later conjuncts may possibly fail.
+ (
+ TailCanFail = cannot_fail,
+ SolnContext = first_soln
+ ->
+ HeadSolnContext = first_soln
+ ;
+ HeadSolnContext = all_solns
+ ),
+ % Process the first conjunct.
+ det_infer_goal(Goal0, Goal, InstMap0, HeadSolnContext,
+ !.ConjFailingContexts ++ RightFailingContexts, DetInfo, HeadDetism,
+ GoalFailingContexts, HeadMsgs),
+
+ % Finally combine the results computed above.
+ det_conjunction_detism(HeadDetism, TailDetism, Detism),
+ !:ConjFailingContexts = GoalFailingContexts ++ !.ConjFailingContexts,
+ Msgs = HeadMsgs ++ TailMsgs.
+
+:- pred det_infer_par_conj(list(hlds_goal)::in, list(hlds_goal)::out,
+ hlds_goal_info::in, instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_par_conj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts, !:Msgs) :-
+ det_infer_par_conj_goals(Goals0, Goals, InstMap0, SolnContext,
RightFailingContexts, DetInfo, Detism, [], GoalFailingContexts,
!:Msgs),
(
@@ -518,11 +637,41 @@
Msg = par_conj_not_det(Detism, PredId, ProcId, GoalInfo, Goals),
ContextMsg = context_det_msg(Context, Msg),
!:Msgs = [ContextMsg | !.Msgs]
- ),
- GoalExpr = par_conj(Goals)
- ;
- GoalExpr0 = disj(Goals0),
- det_infer_disj(Goals0, Goals, InstMap0, SolnContext,
+ ).
+
+:- pred det_infer_par_conj_goals(list(hlds_goal)::in, list(hlds_goal)::out,
+ instmap::in, soln_context::in, list(failing_context)::in, det_info::in,
+ determinism::out, list(failing_context)::in, list(failing_context)::out,
+ list(context_det_msg)::out) is det.
+
+det_infer_par_conj_goals([], [], _InstMap0, _SolnContext, _RightFailingContexts,
+ _DetInfo, det, !ConjFailingContexts, []).
+det_infer_par_conj_goals([Goal0 | Goals0], [Goal | Goals], InstMap0,
+ SolnContext, RightFailingContexts, DetInfo, Detism,
+ !ConjFailingContexts, Msgs) :-
+ det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
+ DetInfo, HeadDetism, GoalFailingContexts, HeadMsgs),
+ determinism_components(HeadDetism, HeadCanFail, HeadMaxSolns),
+
+ det_infer_par_conj_goals(Goals0, Goals, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, TailDetism, !ConjFailingContexts,
+ TailMsgs),
+ determinism_components(TailDetism, TailCanFail, TailMaxSolns),
+
+ det_conjunction_maxsoln(HeadMaxSolns, TailMaxSolns, MaxSolns),
+ det_conjunction_canfail(HeadCanFail, TailCanFail, CanFail),
+ determinism_components(Detism, CanFail, MaxSolns),
+ !:ConjFailingContexts = GoalFailingContexts ++ !.ConjFailingContexts,
+ Msgs = HeadMsgs ++ TailMsgs.
+
+:- pred det_infer_disj(list(hlds_goal)::in, list(hlds_goal)::out,
+ hlds_goal_info::in, instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_disj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts, !:Msgs) :-
+ det_infer_disj_goals(Goals0, Goals, InstMap0, SolnContext,
RightFailingContexts, DetInfo, can_fail, at_most_zero, Detism,
[], GoalFailingContexts0, !:Msgs),
(
@@ -532,17 +681,78 @@
;
Goals = [_ | _],
GoalFailingContexts = GoalFailingContexts0
+ ).
+
+:- pred det_infer_disj_goals(list(hlds_goal)::in, list(hlds_goal)::out,
+ instmap::in, soln_context::in, list(failing_context)::in, det_info::in,
+ can_fail::in, soln_count::in, determinism::out,
+ list(failing_context)::in, list(failing_context)::out,
+ list(context_det_msg)::out) is det.
+
+det_infer_disj_goals([], [], _InstMap0, _SolnContext, _RightFailingContexts,
+ _DetInfo, CanFail, MaxSolns, Detism, !DisjFailingContexts, []) :-
+ determinism_components(Detism, CanFail, MaxSolns).
+det_infer_disj_goals([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
+ !DisjFailingContexts, Msgs) :-
+ det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
+ DetInfo, FirstDetism, GoalFailingContexts, FirstMsgs),
+ determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
+ Goal = _ - GoalInfo,
+ % If a disjunct cannot succeed but is marked with the
+ % preserve_backtrack_into feature, treat it as being able to succeed
+ % when computing the max number of solutions of the disjunction as a
+ % whole, *provided* that some earlier disjuct could succeed. The idea
+ % is that ( marked failure ; det ) should be treated as det, since all
+ % backtracking is local within it, while disjunctions of the form
+ % ( det ; marked failure ) should be treated as multi, since we want
+ % to be able to backtrack to the second disjunct from *outside*
+ % the disjunction. This is useful for program transformation that want
+ % to get control on exits to and redos into model_non procedures.
+ % Deep profiling is one such transformation.
+ (
+ !.MaxSolns \= at_most_zero,
+ FirstMaxSolns = at_most_zero,
+ goal_info_has_feature(GoalInfo, preserve_backtrack_into)
+ ->
+ AdjFirstMaxSolns = at_most_one
+ ;
+ AdjFirstMaxSolns = FirstMaxSolns
),
- GoalExpr = disj(Goals)
+ det_disjunction_canfail(!.CanFail, FirstCanFail, !:CanFail),
+ det_disjunction_maxsoln(!.MaxSolns, AdjFirstMaxSolns, !:MaxSolns),
+ % In single-solution contexts, convert at_most_many to at_most_many_cc.
+ (
+ SolnContext = first_soln,
+ !.MaxSolns = at_most_many
+ ->
+ !:MaxSolns = at_most_many_cc
;
- GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
+ true
+ ),
+ det_infer_disj_goals(Goals0, Goals, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
+ !DisjFailingContexts, LaterMsgs),
+ !:DisjFailingContexts = GoalFailingContexts ++ !.DisjFailingContexts,
+ Msgs = FirstMsgs ++ LaterMsgs.
+
+%-----------------------------------------------------------------------------%
+:- pred det_infer_switch(prog_var::in, can_fail::in,
+ list(case)::in, list(case)::out,
+ hlds_goal_info::in, instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_switch(Var, SwitchCanFail, Cases0, Cases, GoalInfo, InstMap0,
+ SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs) :-
% The determinism of a switch is the worst of the determinism of each
% of the cases. Also, if only a subset of the constructors are handled,
% then it is semideterministic or worse - this is determined
% in switch_detection.m and handled via the SwitchCanFail field.
- det_infer_switch(Cases0, Cases, InstMap0, SolnContext,
+ det_infer_switch_cases(Cases0, Cases, InstMap0, SolnContext,
RightFailingContexts, DetInfo, cannot_fail, at_most_zero,
CasesDetism, [], GoalFailingContexts0, !:Msgs),
determinism_components(CasesDetism, CasesCanFail, CasesSolns),
@@ -572,11 +782,46 @@
;
SwitchCanFail = cannot_fail,
GoalFailingContexts = GoalFailingContexts0
- ),
- GoalExpr = switch(Var, SwitchCanFail, Cases)
- ;
- GoalExpr0 = call(PredId, ProcId0, Args, Builtin, UnifyContext, Name),
+ ).
+
+:- pred det_infer_switch_cases(list(case)::in, list(case)::out, instmap::in,
+ soln_context::in, list(failing_context)::in, det_info::in, can_fail::in,
+ soln_count::in, determinism::out,
+ list(failing_context)::in, list(failing_context)::out,
+ list(context_det_msg)::out) is det.
+
+det_infer_switch_cases([], [], _InstMap0, _SolnContext, _RightFailingContexts,
+ _DetInfo, CanFail, MaxSolns, Detism, !SwitchFailingContexts, []) :-
+ determinism_components(Detism, CanFail, MaxSolns).
+det_infer_switch_cases([Case0 | Cases0], [Case | Cases], InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
+ !SwitchFailingContexts, Msgs) :-
+ % Technically, we should update the instmap to reflect the knowledge that
+ % the var is bound to this particular constructor, but we wouldn't use
+ % that information here anyway, so we don't bother.
+ Case0 = case(ConsId, Goal0),
+ det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
+ DetInfo, FirstDetism, GoalFailingContexts, FirstMsgs),
+ Case = case(ConsId, Goal),
+ determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
+ det_switch_canfail(!.CanFail, FirstCanFail, !:CanFail),
+ det_switch_maxsoln(!.MaxSolns, FirstMaxSolns, !:MaxSolns),
+ det_infer_switch_cases(Cases0, Cases, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
+ !SwitchFailingContexts, LaterMsgs),
+ !:SwitchFailingContexts = GoalFailingContexts ++ !.SwitchFailingContexts,
+ Msgs = FirstMsgs ++ LaterMsgs.
+
+%-----------------------------------------------------------------------------%
+:- pred det_infer_call(pred_id::in, proc_id::in, proc_id::out,
+ hlds_goal_info::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_call(PredId, ProcId0, ProcId, GoalInfo,
+ SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs) :-
% For calls, just look up the determinism entry associated with
% the called predicate.
% This is the point at which annotations start changing
@@ -623,10 +868,16 @@
;
CanFail = cannot_fail,
GoalFailingContexts = []
- ),
- GoalExpr = call(PredId, ProcId, Args, Builtin, UnifyContext, Name)
- ;
- GoalExpr0 = generic_call(GenericCall, _ArgVars, _Modes, CallDetism),
+ ).
+
+:- pred det_infer_generic_call(generic_call::in, determinism::in,
+ hlds_goal_info::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_generic_call(GenericCall, CallDetism,
+ GoalInfo, SolnContext, RightFailingContexts, DetInfo,
+ Detism, GoalFailingContexts, !:Msgs) :-
determinism_components(CallDetism, CanFail, NumSolns),
goal_info_get_context(GoalInfo, Context),
(
@@ -657,12 +908,91 @@
;
CanFail = cannot_fail,
GoalFailingContexts = []
+ ).
+
+:- pred det_infer_foreign_proc(pragma_foreign_proc_attributes::in,
+ pred_id::in, proc_id::in, pragma_foreign_code_impl::in,
+ hlds_goal_info::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_foreign_proc(Attributes, PredId, ProcId, PragmaCode,
+ GoalInfo, SolnContext, RightFailingContexts, DetInfo,
+ Detism, GoalFailingContexts, !:Msgs) :-
+ % Foreign_procs are handled in the same way as predicate calls.
+
+ det_info_get_module_info(DetInfo, ModuleInfo),
+ module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
+ proc_info_declared_determinism(ProcInfo, MaybeDetism),
+ (
+ MaybeDetism = yes(Detism0),
+ determinism_components(Detism0, CanFail, NumSolns0),
+ (
+ may_throw_exception(Attributes) = will_not_throw_exception,
+ Detism0 = erroneous
+ ->
+ proc_info_context(ProcInfo, ProcContext),
+ WillNotThrowMsg =
+ will_not_throw_with_erroneous(PredId, ProcId),
+ WillNotThrowContextMsg =
+ context_det_msg(ProcContext, WillNotThrowMsg),
+ !:Msgs = [WillNotThrowContextMsg]
+ ;
+ !:Msgs = []
),
- GoalExpr = GoalExpr0
+ ( PragmaCode = nondet(_, _, _, _, _, _, _, _, _) ->
+ % Foreign_procs codes of this form can have more than one
+ % solution.
+ NumSolns1 = at_most_many
;
- GoalExpr0 = unify(LHS, RHS0, Mode, Unify, UnifyContext),
+ NumSolns1 = NumSolns0
+ ),
+ (
+ NumSolns1 = at_most_many_cc,
+ SolnContext = all_solns
+ ->
+ goal_info_get_context(GoalInfo, GoalContext),
+ proc_info_varset(ProcInfo, VarSet),
+ WrongContextMsg = cc_pred_in_wrong_context(GoalInfo, Detism0,
+ PredId, ProcId, VarSet, RightFailingContexts),
+ WrongContextContextMsg = context_det_msg(GoalContext,
+ WrongContextMsg),
+ !:Msgs = [WrongContextContextMsg | !.Msgs],
+ NumSolns = at_most_many
+ ;
+ NumSolns = NumSolns1
+ ),
+ determinism_components(Detism, CanFail, NumSolns),
+ (
+ CanFail = can_fail,
+ goal_info_get_context(GoalInfo, Context),
+ GoalFailingContexts = [Context - call_goal(PredId, ProcId)]
+ ;
+ CanFail = cannot_fail,
+ GoalFailingContexts = []
+ )
+ ;
+ MaybeDetism = no,
+ proc_info_context(ProcInfo, Context),
+ Msg = pragma_c_code_without_det_decl(PredId, ProcId),
+ ContextMsg = context_det_msg(Context, Msg),
+ !:Msgs = [ContextMsg],
+ Detism = erroneous,
+ GoalFailingContexts = []
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred det_infer_unify(prog_var::in, unify_rhs::in,
+ unification::in, unify_context::in, unify_rhs::out,
+ hlds_goal_info::in, instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_unify(LHS, RHS0, Unify, UnifyContext, RHS,
+ GoalInfo, InstMap0, SolnContext, RightFailingContexts, DetInfo,
+ Detism, GoalFailingContexts, !:Msgs) :-
% Unifications are either deterministic or semideterministic.
- % (see det_infer_unify).
(
RHS0 = lambda_goal(Purity, PredOrFunc, EvalMethod, FixModes,
NonLocalVars, Vars, Modes, LambdaDeclaredDet, Goal0)
@@ -718,11 +1048,19 @@
;
UnifyCanFail = cannot_fail,
GoalFailingContexts = []
- ),
- GoalExpr = unify(LHS, RHS, Mode, Unify, UnifyContext)
- ;
- GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
+ ).
+
+%-----------------------------------------------------------------------------%
+:- pred det_infer_if_then_else(hlds_goal::in, hlds_goal::out,
+ hlds_goal::in, hlds_goal::out, hlds_goal::in, hlds_goal::out,
+ instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_if_then_else(Cond0, Cond, Then0, Then, Else0, Else,
+ InstMap0, SolnContext, RightFailingContexts, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs) :-
% We process the goal right-to-left, doing the `then' before the
% condition of the if-then-else, so that we can propagate the
% SolnContext correctly.
@@ -782,10 +1120,14 @@
% to failure of the if-then-else as a whole without one or more failing
% contexts in the then part or the else part.
GoalFailingContexts = ThenFailingContexts ++ ElseFailingContexts,
- !:Msgs = CondMsgs ++ ThenMsgs ++ ElseMsgs,
- GoalExpr = if_then_else(Vars, Cond, Then, Else)
- ;
- GoalExpr0 = not(Goal0),
+ !:Msgs = CondMsgs ++ ThenMsgs ++ ElseMsgs.
+
+:- pred det_infer_not(hlds_goal::in, hlds_goal::out, hlds_goal_info::in,
+ instmap::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_not(Goal0, Goal, GoalInfo, InstMap0, DetInfo, Detism,
+ GoalFailingContexts, !:Msgs) :-
% Negations are almost always semideterministic. It is an error for
% a negation to further instantiate any non-local variable. Such errors
% will be reported by the mode analysis.
@@ -811,10 +1153,17 @@
;
CanFail = cannot_fail,
GoalFailingContexts = []
- ),
- GoalExpr = not(Goal)
- ;
- GoalExpr0 = scope(Reason, Goal0),
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred det_infer_scope(scope_reason::in, hlds_goal::in, hlds_goal::out,
+ hlds_goal_info::in, instmap::in, soln_context::in,
+ list(failing_context)::in, det_info::in, determinism::out,
+ list(failing_context)::out, list(context_det_msg)::out) is det.
+
+det_infer_scope(Reason, Goal0, Goal, GoalInfo, InstMap0, SolnContext,
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts, !:Msgs) :-
% Existential quantification may require a cut to throw away solutions,
% but we cannot rely on explicit quantification to detect this.
% Therefore cuts are handled in det_infer_goal.
@@ -858,233 +1207,8 @@
ScopeMsgs = []
),
det_infer_goal(Goal0, Goal, InstMap0, SolnContextToUse,
- RightFailingContexts, DetInfo, Detism, GoalFailingContexts,
- SubMsgs),
- !:Msgs = SubMsgs ++ ScopeMsgs,
- GoalExpr = scope(Reason, Goal)
- ;
- GoalExpr0 = foreign_proc(Attributes, PredId, ProcId, _Args, _ExtraArgs,
- PragmaCode),
- % Foreign_procs are handled in the same way as predicate calls.
-
- det_info_get_module_info(DetInfo, ModuleInfo),
- module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
- proc_info_declared_determinism(ProcInfo, MaybeDetism),
- (
- MaybeDetism = yes(Detism0),
- determinism_components(Detism0, CanFail, NumSolns0),
- (
- may_throw_exception(Attributes) = will_not_throw_exception,
- Detism0 = erroneous
- ->
- proc_info_context(ProcInfo, ProcContext),
- WillNotThrowMsg =
- will_not_throw_with_erroneous(PredId, ProcId),
- WillNotThrowContextMsg =
- context_det_msg(ProcContext, WillNotThrowMsg),
- !:Msgs = [WillNotThrowContextMsg]
- ;
- !:Msgs = []
- ),
- ( PragmaCode = nondet(_, _, _, _, _, _, _, _, _) ->
- % Foreign_procs codes of this form can have more than one
- % solution.
- NumSolns1 = at_most_many
- ;
- NumSolns1 = NumSolns0
- ),
- (
- NumSolns1 = at_most_many_cc,
- SolnContext = all_solns
- ->
- goal_info_get_context(GoalInfo, GoalContext),
- proc_info_varset(ProcInfo, VarSet),
- WrongContextMsg = cc_pred_in_wrong_context(GoalInfo, Detism0,
- PredId, ProcId, VarSet, RightFailingContexts),
- WrongContextContextMsg = context_det_msg(GoalContext,
- WrongContextMsg),
- !:Msgs = [WrongContextContextMsg | !.Msgs],
- NumSolns = at_most_many
- ;
- NumSolns = NumSolns1
- ),
- determinism_components(Detism, CanFail, NumSolns),
- (
- CanFail = can_fail,
- goal_info_get_context(GoalInfo, Context),
- GoalFailingContexts = [Context - call_goal(PredId, ProcId)]
- ;
- CanFail = cannot_fail,
- GoalFailingContexts = []
- )
- ;
- MaybeDetism = no,
- proc_info_context(ProcInfo, Context),
- Msg = pragma_c_code_without_det_decl(PredId, ProcId),
- ContextMsg = context_det_msg(Context, Msg),
- !:Msgs = [ContextMsg],
- Detism = erroneous,
- GoalFailingContexts = []
- ),
- GoalExpr = GoalExpr0
- ;
- GoalExpr0 = shorthand(_),
- % These should have been expanded out by now.
- unexpected(this_file, "det_infer_goal_2: unexpected shorthand")
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- pred det_infer_conj(list(hlds_goal)::in, list(hlds_goal)::out, instmap::in,
- soln_context::in, list(failing_context)::in, det_info::in,
- determinism::out, list(failing_context)::in, list(failing_context)::out,
- list(context_det_msg)::out) is det.
-
-det_infer_conj([], [], _InstMap0, _SolnContext, _RightFailingContexts,
- _DetInfo, det, !ConjFailingContexts, []).
-det_infer_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
- RightFailingContexts, DetInfo, Detism, !ConjFailingContexts, Msgs) :-
- % We should look to see when we get to a not_reached point
- % and optimize away the remaining elements of the conjunction.
- % But that optimization is done in the code generator anyway.
-
- % We infer the determinisms right-to-left, so that we can propagate
- % the SolnContext properly.
-
- % First, process the second and subsequent conjuncts.
- update_instmap(Goal0, InstMap0, InstMap1),
- det_infer_conj(Goals0, Goals, InstMap1, SolnContext,
- RightFailingContexts, DetInfo, TailDetism, !ConjFailingContexts,
- TailMsgs),
- determinism_components(TailDetism, TailCanFail, _TailMaxSolns),
-
- % Next, work out whether the first conjunct is in a first_soln context
- % or not. We obviously need all its solutions if we need all the solutions
- % of the conjunction. However, even if we need only the first solution
- % of the conjunction, we may need to generate more than one solution
- % of the first conjunct if the later conjuncts may possibly fail.
- (
- TailCanFail = cannot_fail,
- SolnContext = first_soln
- ->
- HeadSolnContext = first_soln
- ;
- HeadSolnContext = all_solns
- ),
- % Process the first conjunct.
- det_infer_goal(Goal0, Goal, InstMap0, HeadSolnContext,
- !.ConjFailingContexts ++ RightFailingContexts, DetInfo, HeadDetism,
- GoalFailingContexts, HeadMsgs),
-
- % Finally combine the results computed above.
- det_conjunction_detism(HeadDetism, TailDetism, Detism),
- !:ConjFailingContexts = GoalFailingContexts ++ !.ConjFailingContexts,
- Msgs = HeadMsgs ++ TailMsgs.
-
-:- pred det_infer_par_conj(list(hlds_goal)::in, list(hlds_goal)::out,
- instmap::in, soln_context::in, list(failing_context)::in, det_info::in,
- determinism::out, list(failing_context)::in, list(failing_context)::out,
- list(context_det_msg)::out) is det.
-
-det_infer_par_conj([], [], _InstMap0, _SolnContext, _RightFailingContexts,
- _DetInfo, det, !ConjFailingContexts, []).
-det_infer_par_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
- RightFailingContexts, DetInfo, Detism, !ConjFailingContexts, Msgs) :-
- det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
- DetInfo, HeadDetism, GoalFailingContexts, HeadMsgs),
- determinism_components(HeadDetism, HeadCanFail, HeadMaxSolns),
-
- det_infer_par_conj(Goals0, Goals, InstMap0, SolnContext,
- RightFailingContexts, DetInfo, TailDetism, !ConjFailingContexts,
- TailMsgs),
- determinism_components(TailDetism, TailCanFail, TailMaxSolns),
-
- det_conjunction_maxsoln(HeadMaxSolns, TailMaxSolns, MaxSolns),
- det_conjunction_canfail(HeadCanFail, TailCanFail, CanFail),
- determinism_components(Detism, CanFail, MaxSolns),
- !:ConjFailingContexts = GoalFailingContexts ++ !.ConjFailingContexts,
- Msgs = HeadMsgs ++ TailMsgs.
-
-:- pred det_infer_disj(list(hlds_goal)::in, list(hlds_goal)::out, instmap::in,
- soln_context::in, list(failing_context)::in, det_info::in,
- can_fail::in, soln_count::in, determinism::out,
- list(failing_context)::in, list(failing_context)::out,
- list(context_det_msg)::out) is det.
-
-det_infer_disj([], [], _InstMap0, _SolnContext, _RightFailingContexts,
- _DetInfo, CanFail, MaxSolns, Detism, !DisjFailingContexts, []) :-
- determinism_components(Detism, CanFail, MaxSolns).
-det_infer_disj([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
- RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
- !DisjFailingContexts, Msgs) :-
- det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
- DetInfo, FirstDetism, GoalFailingContexts, FirstMsgs),
- determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
- Goal = _ - GoalInfo,
- % If a disjunct cannot succeed but is marked with the
- % preserve_backtrack_into feature, treat it as being able to succeed
- % when computing the max number of solutions of the disjunction as a
- % whole, *provided* that some earlier disjuct could succeed. The idea
- % is that ( marked failure ; det ) should be treated as det, since all
- % backtracking is local within it, while disjunctions of the form
- % ( det ; marked failure ) should be treated as multi, since we want
- % to be able to backtrack to the second disjunct from *outside*
- % the disjunction. This is useful for program transformation that want
- % to get control on exits to and redos into model_non procedures.
- % Deep profiling is one such transformation.
- (
- !.MaxSolns \= at_most_zero,
- FirstMaxSolns = at_most_zero,
- goal_info_has_feature(GoalInfo, preserve_backtrack_into)
- ->
- AdjFirstMaxSolns = at_most_one
- ;
- AdjFirstMaxSolns = FirstMaxSolns
- ),
- det_disjunction_canfail(!.CanFail, FirstCanFail, !:CanFail),
- det_disjunction_maxsoln(!.MaxSolns, AdjFirstMaxSolns, !:MaxSolns),
- % In single-solution contexts, convert at_most_many to at_most_many_cc.
- (
- SolnContext = first_soln,
- !.MaxSolns = at_most_many
- ->
- !:MaxSolns = at_most_many_cc
- ;
- true
- ),
- det_infer_disj(Goals0, Goals, InstMap0, SolnContext, RightFailingContexts,
- DetInfo, !.CanFail, !.MaxSolns, Detism, !DisjFailingContexts,
- LaterMsgs),
- !:DisjFailingContexts = GoalFailingContexts ++ !.DisjFailingContexts,
- Msgs = FirstMsgs ++ LaterMsgs.
-
-:- pred det_infer_switch(list(case)::in, list(case)::out, instmap::in,
- soln_context::in, list(failing_context)::in, det_info::in, can_fail::in,
- soln_count::in, determinism::out,
- list(failing_context)::in, list(failing_context)::out,
- list(context_det_msg)::out) is det.
-
-det_infer_switch([], [], _InstMap0, _SolnContext, _RightFailingContexts,
- _DetInfo, CanFail, MaxSolns, Detism, !SwitchFailingContexts, []) :-
- determinism_components(Detism, CanFail, MaxSolns).
-det_infer_switch([Case0 | Cases0], [Case | Cases], InstMap0, SolnContext,
- RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
- !SwitchFailingContexts, Msgs) :-
- % Technically, we should update the instmap to reflect the knowledge that
- % the var is bound to this particular constructor, but we wouldn't use
- % that information here anyway, so we don't bother.
- Case0 = case(ConsId, Goal0),
- det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
- DetInfo, FirstDetism, GoalFailingContexts, FirstMsgs),
- Case = case(ConsId, Goal),
- determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
- det_switch_canfail(!.CanFail, FirstCanFail, !:CanFail),
- det_switch_maxsoln(!.MaxSolns, FirstMaxSolns, !:MaxSolns),
- det_infer_switch(Cases0, Cases, InstMap0, SolnContext,
- RightFailingContexts, DetInfo, !.CanFail, !.MaxSolns, Detism,
- !SwitchFailingContexts, LaterMsgs),
- !:SwitchFailingContexts = GoalFailingContexts ++ !.SwitchFailingContexts,
- Msgs = FirstMsgs ++ LaterMsgs.
+ RightFailingContexts, DetInfo, Detism, GoalFailingContexts, SubMsgs),
+ !:Msgs = SubMsgs ++ ScopeMsgs.
%-----------------------------------------------------------------------------%
cvs diff: Diffing notes
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list