[m-rev.] for review: fix bug 311
Julien Fischer
jfischer at opturion.com
Tue Jul 29 17:36:14 AEST 2014
On Sun, 27 Jul 2014, Zoltan Somogyi wrote:
> Fix mantis bug 311.
>
> compiler/simplify_goal_disj.m:
> Look for the conditions that lead to the bug (a disjunction that
> further instantiates an already partially instantiated variable).
> Generate an error message when found, PROVIDED that this happens
> in a context in which the surrounding procedure can succeed
> more than once. (If it cannot, then you cannot invoke an all-solutions
> predicate on it, and the bug cannot happen.)
>
> This condition (a model_non surrounding procedure) was motivated
> by mdbcomp/feedback.m, which does not compile without it.
>
> compiler/simplify_info.m:
> The simplify_info type used to contain four different kinds of fields:
>
> 1 static fields; set and then never changed, such as the id of the
> containing procedure
> 2 global information, such as the varset and vartypes, which are updated
> as new variable are added, and whose updates need to be kept regardless
> of what part of the procedure is analyzed next
> 3 information about the context surrounding the goal currently being
> analyzed, such as the number of lambda expressions we are inside
> 4 information about the point in the code before the goal currently being
> analyzed, such as the set of equivalences that currently hold between
> variables (part of common_info).
>
> The code of the simplify_goal*.m modules used to have jump through hoops
> to handle 3 and 4 properly, given that the simplify_info was being
> threaded through code in a way that was suitable only for 1 and 2.
>
> This change takes categories 3 and 4 out of the simplify_info.
> It creates a new type, simplify_nested_context, for category 3,
> and adds information about the ability of the procedure surrounding
> the current point to succeed more than once (needed for the bug311 fix)
> to this new type.
>
> compiler/simplify_tasks.m:
> Rename the do_once task to mark_code_model_changes, since this
> expresses what the task is much less ambiguously.
>
> compiler/simplify_goal*.m:
> compiler/simplify_proc.m:
> compiler/common.m:
> compiler/mercury_compile_front_end.m:
> compiler/mercury_compile_llds_back_end.m:
> Conform to the changes to simplify_info (and simplify_tasks).
> Pass the current instmap and common_info (the two category 4 fields)
> separately.
>
> Mark some places that could be improved.
>
> compiler/hlds_out_mode.m:
> Generate easier-to-understand debugging output. I needed this to track
> down a bug in my initial fix.
>
> compiler/inst_match.m:
> Remove a redundant unification that couldn't fail (since it was invoked
> only if the exact same unification succeeded a few lines earlier).
> Apply another minor optimizations.
>
> compiler/instmap.m:
> Remove references to the alias branch. It won't be coming back.
>
> compiler/error_util.m:
> Fix some documentation.
>
> mdbcomp/feedback.m:
> Put related stuff together.
>
> tests/invalid/bug311.{m,err_exp}:
> New test case for the bug.
>
> tests/invalid/Mmakefile:
> Enable the new test case.
Please also add an entry to the NEWS file mentioning the bug-fix.
> diff --git a/compiler/common.m b/compiler/common.m
> index c5ef900..e5fa621 100644
> --- a/compiler/common.m
> +++ b/compiler/common.m
...
> @@ -238,10 +241,10 @@
> % A struct_map maps a principal type constructor and a cons_id of that
> % type to information about cells involving that cons_id.
> %
> - % The reason why we need the principal type constructors is that two
> - % syntactically identical structures have compatible representations if and
> - % only if their principal type constructors are the same. For example, if
> - % we have:
> + % The reason why we need the principal type constructors is that
> + % two syntactically identical structures are guaranteed to have
> + % compatible representations if and ONLy if their principal type
s/ONLy/ONLY/
> + % constructors are the same. For example, if we have:
> %
> % :- type maybe_err(T) ---> ok(T) ; err(string).
> %
...
> @@ -621,7 +619,9 @@ common_optimise_call_2(SeenCall, InputArgs, OutputArgs, Modes, GoalInfo,
> simplify_info_get_module_info(!.Info, ModuleInfo),
> modes_to_uni_modes(ModuleInfo, Modes, Modes, UniModes),
> create_output_unifications(GoalInfo, OutputArgs, OutputArgs2,
> - UniModes, Goals, !Info),
> + UniModes, Goals, Common0, _Common1, !Info),
> + % XXX should be Common = Common1
> + Common = Common0,
If that must be left as an XXX, make the comment say why it is not currently
Common1.
...
> index 441908b..7803f36 100644
> --- a/compiler/simplify_goal.m
> +++ b/compiler/simplify_goal.m
> @@ -16,9 +16,11 @@
> :- module check_hlds.simplify.simplify_goal.
> :- interface.
>
> +:- import_module check_hlds.simplify.common.
> :- import_module check_hlds.simplify.simplify_info.
> :- import_module hlds.
> :- import_module hlds.hlds_goal.
> +:- import_module hlds.instmap.
>
> % Handle simplification of all goals.
> %
> @@ -26,13 +28,33 @@
> % and its surrounding goals before invoking the goal-type-specific
> % simplification code on it.
> %
> + % simplify_goal and its goal-type-specific subcontractor predicates
> + % pass around information about the context surrounding the goal
> + % currently being analyzed in the simplify_nested_context argument.
> + % They pass around information about the program point just before
> + % the current goal in the instmap and common_info arguments.
> + % They pass around information that is global to the simplification
> + % process as a whole in the simplify_info arguments..
Doubled-up full stop there.
> + %
> + % These predicates return the common_info appropriate to the program
> + % point after the goal that was just analyzed in the common_info output
> + % argumen. They do not return the new instmap, because it is not necessary.
s/argumen/argument/
> + % The two predicates that need to know the instmap after the goal
> + % that was just analyzed (simplify_goal_conj, after a conjunct, and
> + % simplify_goal_ite, after the condition) apply the goal's instmap delta
> + % themselves.
> + %
> :- pred simplify_goal(hlds_goal::in, hlds_goal::out,
> + simplify_nested_context::in, instmap::in,
> + common_info::in, common_info::out,
> simplify_info::in, simplify_info::out) is det.
...
> diff --git a/compiler/simplify_goal_conj.m b/compiler/simplify_goal_conj.m
> index 77d9034..4d095cd 100644
> --- a/compiler/simplify_goal_conj.m
> +++ b/compiler/simplify_goal_conj.m
...
> @@ -110,30 +115,58 @@ contains_multisoln_goal(Goals) :-
...
> % Delete unreachable goals.
> (
> - simplify_info_get_instmap(!.Info, InstMap1),
> - instmap_is_unreachable(InstMap1)
> + % XXX InstMap1 after
> + % update_instmap(Goal1, InstMap0, InstMap1),
> + instmap_is_unreachable(InstMap0)
Is that XXX something you plan to commit or just a note to yourself?
(If the former, then more detail is required).
...
> diff --git a/compiler/simplify_goal_disj.m b/compiler/simplify_goal_disj.m
> index ac3ec0b..7aba6c2 100644
> --- a/compiler/simplify_goal_disj.m
> +++ b/compiler/simplify_goal_disj.m
...
> @@ -78,12 +91,33 @@ simplify_goal_disj(GoalExpr0, GoalExpr, GoalInfo0, GoalInfo, !Info) :-
> simplify_info_get_module_info(!.Info, ModuleInfo1),
> NonLocals = goal_info_get_nonlocals(GoalInfo0),
> simplify_info_get_var_types(!.Info, VarTypes),
> - merge_instmap_deltas(InstMap0, NonLocals, VarTypes, InstMaps,
> + merge_instmap_deltas(InstMap0, NonLocals, VarTypes, InstMapDeltas,
> NewDelta, ModuleInfo1, ModuleInfo2),
> simplify_info_set_module_info(ModuleInfo2, !Info),
> - goal_info_set_instmap_delta(NewDelta, GoalInfo0, GoalInfo)
> + goal_info_set_instmap_delta(NewDelta, GoalInfo0, GoalInfo),
> +
> + (
> + simplify_do_after_front_end(!.Info),
> + % If the surround procedure cannot have more than one solution,
s/surround/surrounding/
> + % then any warning about not being able to compute the set of
> + % all solutions would be meaningless and confusing.
> + NestedContext0 ^ snc_proc_is_model_non = yes(Innermost)
> + ->
> + warn_about_any_problem_partial_vars(Innermost, GoalInfo0,
> + InstMap0, NewDelta, !Info)
> + ;
> + true
> + )
...
> @@ -101,18 +135,121 @@ simplify_goal_disj(GoalExpr0, GoalExpr, GoalInfo0, GoalInfo, !Info) :-
> true
> ).
>
> + % Look for the kind of bug represented by tests/invalid/bug311.m.
> + % For a detailed description of the problem, see that test case.
> + %
> +:- pred warn_about_any_problem_partial_vars(innermost_proc::in,
> + hlds_goal_info::in, instmap::in, instmap_delta::in,
> + simplify_info::in, simplify_info::out) is det.
> +
> +warn_about_any_problem_partial_vars(Innermost, GoalInfo, InstMap0,
> + InstMapDelta, !Info) :-
> + instmap_delta_to_assoc_list(InstMapDelta, InstMapDeltaChanges),
> + simplify_info_get_module_info(!.Info, ModuleInfo),
> + list.filter_map(is_var_a_problem_partial_var(ModuleInfo, InstMap0),
> + InstMapDeltaChanges, ProblemPartialVars),
> + (
> + ProblemPartialVars = []
> + ;
> + ProblemPartialVars = [_ | _],
> + (
> + Innermost = imp_whole_proc,
> + ProcStr = "the procedure"
> + ;
> + Innermost = imp_lambda(LambdaContext),
> + % If the lambda expression does not leave the scope of its
> + % defining procedure and does not have an all-solutions predicate
> + % invoked on it, the warning we generate could be a bit misleading.
> + % Unfortunately, without an escape analysis, I (zs) see no way
> + % to avoid this while still generating the warning in cases
> + % where the program *does* invoke an all-solutions predicate
> + % on the closure generated by the ambda expression.
s/ambda/lambda/
...
The rest looks okay.
Cheers,
Julien
More information about the reviews
mailing list