[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