[m-dev.] for review: fix quantification of "<=>" [1/2]

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Oct 25 01:54:52 AEST 1999


Estimated hours taken: 10

Handle quantification analysis of bi-implication (`<=>') goals correctly.
Previously we used to expand bi-implications before doing quantification
analysis, which stuffed up the results of quantification analysis for
those goals.  We need to do quantification analysis first, and only
then can we expand bi-implications.  In addition, elimination of double
negation needs to come after expansion of bi-implication, so I moved
that from make_hlds.m to purity.m.

compiler/hlds_goal.m:
	Add a new alternative to the HLDS goal type for bi-implications.
	Also add a new predicate negate_goal, for use by purity.m.

compiler/make_hlds.m:
	Don't expand bi-implication here, instead just use the new
	bi_implication/2 HLDS goal type.
	Don't eliminated double negation here.
	
compiler/quantification.m:
	Handle quantification for bi-implications.
	Expand bi-implications.

compiler/purity.m:
	Eliminate double negation.

compiler/hlds_out.m:
	Add code to print out bi-implication goals.

compiler/*.m:
	Trivial changes to handle the new bi_implication/2
	alternative in the HLDS goal type.

compiler/notes/compiler_design.html:
	Document the above changes.

tests/hard_coded/Mmakefile:
tests/hard_coded/quantifier2.m:
tests/hard_coded/quantifier2.exp:
	A regression test for the above change.

Workspace: /d-drive/home/hg/fjh/mercury
Index: compiler/assertion.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/assertion.m,v
retrieving revision 1.2
diff -u -d -r1.2 assertion.m
--- compiler/assertion.m	1999/09/12 04:26:37	1.2
+++ compiler/assertion.m	1999/10/21 13:48:32
@@ -211,6 +211,10 @@
 	equal_vars(VarsA, VarsB, Subst0, Subst).
 equal_goals(par_conj(GoalAs, _) - _, par_conj(GoalBs, _) - _, Subst0, Subst) :-
 	equal_goals_list(GoalAs, GoalBs, Subst0, Subst).
+equal_goals(bi_implication(LeftGoalA, RightGoalA) - _,
+	    bi_implication(LeftGoalB, RightGoalB) - _, Subst0, Subst) :-
+	equal_goals(LeftGoalA, LeftGoalB, Subst0, Subst1),
+	equal_goals(RightGoalA, RightGoalB, Subst1, Subst).
 
 :- pred equal_vars(prog_vars::in, prog_vars::in, subst::in,
 		subst::out) is semidet.
@@ -324,6 +328,10 @@
 	assertion__normalise_goal(Else0, Else).
 assertion__normalise_goal(par_conj(Goal0s,B) - GI, par_conj(Goals,B) - GI) :-
 	assertion__normalise_goals(Goal0s, Goals).
+assertion__normalise_goal(bi_implication(LHS0, RHS0) - GI,
+		bi_implication(LHS, RHS) - GI) :-
+	assertion__normalise_goal(LHS0, LHS),
+	assertion__normalise_goal(RHS0, RHS).
 
 %-----------------------------------------------------------------------------%
 
@@ -409,6 +417,10 @@
 	assertion__in_interface_check(Else, PredInfo, ModuleInfo).
 assertion__in_interface_check(par_conj(Goals,_) - _, PredInfo, ModuleInfo) -->
 	assertion__in_interface_check_list(Goals, PredInfo, ModuleInfo).
+assertion__in_interface_check(bi_implication(LHS, RHS) - _, PredInfo,
+		ModuleInfo) -->
+	assertion__in_interface_check(LHS, PredInfo, ModuleInfo),
+	assertion__in_interface_check(RHS, PredInfo, ModuleInfo).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/dependency_graph.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dependency_graph.m,v
retrieving revision 1.43
diff -u -d -r1.43 dependency_graph.m
--- compiler/dependency_graph.m	1999/07/13 08:52:47	1.43
+++ compiler/dependency_graph.m	1999/10/21 11:08:20
@@ -275,6 +275,11 @@
 dependency_graph__add_arcs_in_goal_2(pragma_c_code(_, _, _, _, _, _, _), _,
 	DepGraph, DepGraph).
 
+dependency_graph__add_arcs_in_goal_2(bi_implication(LHS, RHS), Caller, 
+		DepGraph0, DepGraph) :-
+	dependency_graph__add_arcs_in_list([LHS, RHS], Caller,
+			DepGraph0, DepGraph).
+
 %-----------------------------------------------------------------------------%
 
 :- pred dependency_graph__add_arcs_in_list(list(hlds_goal), relation_key,
@@ -688,6 +693,9 @@
 		Map, Map) --> [].
 process_aditi_goal(_IsNeg, pragma_c_code(_, _, _, _, _, _, _) - _,
 		Map, Map) --> [].
+process_aditi_goal(_, bi_implication(_, _) - _, _, _) -->
+	% these should have been expanded out by now
+	{ error("process_aditi_goal: unexpected bi_implication") }.
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/dnf.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dnf.m,v
retrieving revision 1.37
diff -u -d -r1.37 dnf.m
--- compiler/dnf.m	1999/07/13 08:52:50	1.37
+++ compiler/dnf.m	1999/10/21 16:33:06
@@ -240,6 +240,10 @@
 		ModuleInfo = ModuleInfo0,
 		NewPredIds = NewPredIds0,
 		Goal = Goal0
+	;
+		GoalExpr0 = bi_implication(_, _),
+		% these should have been expanded out by now
+		error("dnf__transform_goal: unexpected bi_implication")
 	).
 
 %-----------------------------------------------------------------------------%
@@ -468,6 +472,7 @@
 	).
 dnf__is_atomic_expr(_, _, _, if_then_else(_, _, _, _, _), no).
 dnf__is_atomic_expr(_, _, _, pragma_c_code(_, _, _, _, _, _, _), yes).
+dnf__is_atomic_expr(_, _, _, bi_implication(_, _), no).
 
 :- pred dnf__free_of_nonatomic(hlds_goal::in,
 	set(pred_proc_id)::in) is semidet.
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.58
diff -u -d -r1.58 goal_util.m
--- compiler/goal_util.m	1999/10/15 03:44:44	1.58
+++ compiler/goal_util.m	1999/10/21 14:53:56
@@ -368,6 +368,11 @@
 		pragma_c_code(A,B,C,Vars,E,F,G)) :-
 	goal_util__rename_var_list(Vars0, Must, Subn, Vars).
 
+goal_util__name_apart_2(bi_implication(LHS0, RHS0), Must, Subn,
+		bi_implication(LHS, RHS)) :-
+	goal_util__rename_vars_in_goal(LHS0, Must, Subn, LHS),
+	goal_util__rename_vars_in_goal(RHS0, Must, Subn, RHS).
+
 %-----------------------------------------------------------------------------%
 
 :- pred goal_util__name_apart_list(list(hlds_goal), bool,
@@ -591,6 +596,10 @@
 		Set0, Set) :-
 	set__insert_list(Set0, ArgVars, Set).
 
+goal_util__goal_vars_2(bi_implication(LHS - _, RHS - _), Set0, Set) :-
+	goal_util__goal_vars_2(LHS, Set0, Set1),
+	goal_util__goal_vars_2(RHS, Set1, Set).
+
 goal_util__goals_goal_vars([], Set, Set).
 goal_util__goals_goal_vars([Goal - _ | Goals], Set0, Set) :-
 	goal_util__goal_vars_2(Goal, Set0, Set1),
@@ -728,6 +737,10 @@
 goal_expr_size(generic_call(_, _, _, _), 1).
 goal_expr_size(unify(_, _, _, _, _), 1).
 goal_expr_size(pragma_c_code(_, _, _, _, _, _, _), 1).
+goal_expr_size(bi_implication(LHS, RHS), Size) :-
+	goal_size(LHS, Size1),
+	goal_size(RHS, Size2),
+	Size is Size1 + Size2 + 1.
 
 %-----------------------------------------------------------------------------%
 %
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.63
diff -u -d -r1.63 hlds_goal.m
--- compiler/hlds_goal.m	1999/09/12 04:26:41	1.63
+++ compiler/hlds_goal.m	1999/10/21 14:55:52
@@ -29,7 +29,7 @@
 	--->	conj(hlds_goals)
 
 		% A predicate call.
-		% Initially only the sym_name and arguments
+		% Initially only the sym_name, arguments, and context
 		% are filled in. Type analysis fills in the
 		% pred_id. Mode analysis fills in the
 		% proc_id and the builtin_state field.
@@ -179,12 +179,28 @@
 					% pragma_c_codes; none for others.
 		)
 
+		% parallel conjunction
 	;	par_conj(hlds_goals, store_map)
-					% parallel conjunction
 					% The store_map specifies the locations
 					% in which live variables should be
 					% stored at the start of the parallel
 					% conjunction.
+
+		% bi-implication (A <=> B)
+		%
+		% These get eliminated by quantification.m,
+		% so most passes of the compiler will just call error/1
+		% if they occur.
+		%
+		% Note that ordinary implications (A => B)
+		% and reverse implications (A <= B) are expanded
+		% out before we construct the HLDS.  But we can't
+		% do that for bi-implications, because if expansion
+		% of bi-implications is done before implicit quantification,
+		% then the quantification would be wrong.
+
+	;	bi_implication(hlds_goal, hlds_goal)
+
 	.
 
 :- type generic_call
@@ -880,6 +896,11 @@
 :- pred conjoin_goals(hlds_goal, hlds_goal, hlds_goal).
 :- mode conjoin_goals(in, in, out) is det.
 
+	% Negate a goal, eliminating double negations as we go.
+	%
+:- pred negate_goal(hlds_goal, hlds_goal_info, hlds_goal).
+:- mode negate_goal(in, in, out) is det.
+
 	% A goal is atomic iff it doesn't contain any sub-goals
 	% (except possibly goals inside lambda expressions --
 	% but lambda expressions will get transformed into separate
@@ -1242,6 +1263,37 @@
 	),
 	conjoin_goal_and_goal_list(Goal1, GoalList, Goal).
 	
+	% Negate a goal, eliminating double negations as we go.
+
+negate_goal(Goal, GoalInfo, NegatedGoal) :-
+	(
+		% eliminate double negations
+		Goal = not(Goal1) - _
+	->
+		NegatedGoal = Goal1
+	;
+		% convert negated conjunctions of negations
+		% into disjunctions
+		Goal = conj(NegatedGoals) - _,
+		all_negated(NegatedGoals, UnnegatedGoals)
+	->
+		map__init(StoreMap),
+		NegatedGoal = disj(UnnegatedGoals, StoreMap) - GoalInfo
+	;
+		NegatedGoal = not(Goal) - GoalInfo
+	).
+
+:- pred all_negated(list(hlds_goal), list(hlds_goal)).
+:- mode all_negated(in, out) is semidet.
+
+all_negated([], []).
+all_negated([not(Goal) - _ | NegatedGoals], [Goal | Goals]) :-
+	all_negated(NegatedGoals, Goals).
+all_negated([conj(NegatedConj) - _GoalInfo | NegatedGoals], Goals) :-
+	all_negated(NegatedConj, Goals1),
+	all_negated(NegatedGoals, Goals2),
+	list__append(Goals1, Goals2, Goals).
+
 %-----------------------------------------------------------------------------%
 
 goal_is_atomic(conj([])).
@@ -1345,6 +1397,10 @@
 	Goal = unify(_, _, _, _, _).
 set_goal_contexts_2(_, Goal, Goal) :-
 	Goal = pragma_c_code(_, _, _, _, _, _, _).
+set_goal_contexts_2(Context, bi_implication(LHS0, RHS0),
+		bi_implication(LHS, RHS)) :-
+	set_goal_contexts(Context, LHS0, LHS),
+	set_goal_contexts(Context, RHS0, RHS).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.227
diff -u -d -r1.227 hlds_out.m
--- compiler/hlds_out.m	1999/10/15 03:44:46	1.227
+++ compiler/hlds_out.m	1999/10/21 11:25:52
@@ -1539,6 +1539,21 @@
 	io__write_string(")"),
 	io__write_string(Follow).
 
+hlds_out__write_goal_2(bi_implication(LHS, RHS), ModuleInfo, VarSet,
+		AppendVarnums, Indent, Follow, TypeQual) -->
+	hlds_out__write_indent(Indent),
+	io__write_string("( % bi-implication\n"),
+	{ Indent1 is Indent + 1 },
+	hlds_out__write_goal_a(LHS, ModuleInfo, VarSet, AppendVarnums,
+		Indent1, "\n", TypeQual),
+	hlds_out__write_indent(Indent),
+	io__write_string("<=>\n"),
+	hlds_out__write_goal_a(RHS, ModuleInfo, VarSet, AppendVarnums,
+		Indent1, "\n", TypeQual),
+	hlds_out__write_indent(Indent),
+	io__write_string(")"),
+	io__write_string(Follow).
+
 :- pred hlds_out__write_varnum_list(list(prog_var), io__state, io__state).
 :- mode hlds_out__write_varnum_list(in, di, uo) is det.
 
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.310
diff -u -d -r1.310 make_hlds.m
--- compiler/make_hlds.m	1999/10/14 04:27:52	1.310
+++ compiler/make_hlds.m	1999/10/21 16:47:36
@@ -4014,6 +4014,12 @@
 	warn_singletons_in_pragma_c_code(PragmaImpl, ArgInfo, Context, 
 		PredCallId, MI).
 
+warn_singletons_in_goal_2(bi_implication(LHS, RHS), _GoalInfo, QuantVars,
+		VarSet, PredCallId, MI) -->
+	warn_singletons_in_goal_list([LHS, RHS], QuantVars, VarSet,
+		PredCallId, MI).
+
+
 :- pred warn_singletons_in_goal_list(list(hlds_goal), set(prog_var),
 		prog_varset, simple_call_id, module_info,
 		io__state, io__state).
@@ -4661,24 +4667,8 @@
 
 transform_goal_2(not(A0), _, VarSet0, Subst, Goal, VarSet, Info0, Info) -->
 	transform_goal(A0, VarSet0, Subst, A, VarSet, Info0, Info),
-	{
-		% eliminate double negations
-		A = not(Goal1) - _
-	->
-		Goal = Goal1
-	;
-		% convert negated conjunctions of negations
-		% into disjunctions
-		A = conj(NegatedGoals) - _,
-		all_negated(NegatedGoals, UnnegatedGoals)
-	->
-		goal_info_init(GoalInfo),
-		map__init(StoreMap),
-		Goal = disj(UnnegatedGoals, StoreMap) - GoalInfo
-	;
-		goal_info_init(GoalInfo),
-		Goal = not(A) - GoalInfo
-	}.
+	{ goal_info_init(GoalInfo) },
+	{ Goal = not(A) - GoalInfo }.
 
 transform_goal_2((A0,B0), _, VarSet0, Subst, Goal, VarSet, Info0, Info) -->
 	get_conj(B0, Subst, [], VarSet0, L0, VarSet1, Info0, Info1),
@@ -4705,13 +4695,19 @@
 	transform_goal_2(TransformedGoal, Context, VarSet0, Subst,
 		Goal, VarSet, Info0, Info).
 
-transform_goal_2(equivalent(P, Q), Context, VarSet0, Subst, Goal, VarSet,
+transform_goal_2(equivalent(P0, Q0), _Context, VarSet0, Subst, Goal, VarSet,
 		Info0, Info) -->
-		% `P <=> Q' is defined as `(P => Q), (Q => P)'
-	{ TransformedGoal = (implies(P, Q) - Context,
-				implies(Q, P) - Context) },
-	transform_goal_2(TransformedGoal, Context, VarSet0, Subst,
-		Goal, VarSet, Info0, Info).
+	%
+	% `P <=> Q' is defined as `(P => Q), (Q => P)',
+	% but that transformation must not be done until
+	% after quantification analysis, lest the duplication of
+	% the goals concerned affect the implicit quantification
+	% of the variables inside them.
+	%
+	{ goal_info_init(GoalInfo) },
+	transform_goal(P0, VarSet0, Subst, P, VarSet1, Info0, Info1),
+	transform_goal(Q0, VarSet1, Subst, Q, VarSet, Info1, Info),
+	{ Goal = bi_implication(P, Q) - GoalInfo }.
 
 transform_goal_2(call(Name, Args0, Purity), Context, VarSet0, Subst, Goal,
 		VarSet, Info0, Info) -->
@@ -4801,18 +4797,6 @@
 	{ term__apply_substitution(B0, Subst, B) },
 	unravel_unification(A, B, Context, explicit, [],
 			VarSet0, Goal, VarSet, Info0, Info).
-
-:- pred all_negated(list(hlds_goal), list(hlds_goal)).
-:- mode all_negated(in, out) is semidet.
-
-all_negated([], []).
-all_negated([not(Goal) - _ | NegatedGoals], [Goal | Goals]) :-
-	all_negated(NegatedGoals, Goals).
-% nested conjunctions shouldn't occur here anyway, but just in case...
-all_negated([conj(NegatedConj) - _GoalInfo | NegatedGoals], Goals) :-
-	all_negated(NegatedConj, Goals1),
-	all_negated(NegatedGoals, Goals2),
-	list__append(Goals1, Goals2, Goals).
 
 :- inst aditi_update_str =
 	bound(	"aditi_insert"
Index: compiler/purity.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.19
diff -u -d -r1.19 purity.m
--- compiler/purity.m	1999/09/12 04:26:51	1.19
+++ compiler/purity.m	1999/10/21 17:12:08
@@ -25,7 +25,11 @@
 %  so they need to be a separate "post-typecheck pass"; they are done
 %  here in combination with the purity-analysis pass for efficiency reasons.
 %
+%  We also do elimination of double-negation in this pass.
+%  It needs to be done somewhere after quantification analysis and
+%  before mode analysis, and this is convenient place to do it.
 %
+%
 %  The aim of Mercury's purity system is to allow one to declare certain parts
 %  of one's program to be impure, thereby forbidding the compiler from making
 %  certain optimizations to that part of the code.  Since one can often
@@ -508,10 +512,21 @@
 		ModuleInfo, InClosure, Purity, NumErrors0, NumErrors) -->
 	compute_goals_purity(Goals0, Goals, PredInfo, ModuleInfo,
 			     InClosure, pure, Purity, NumErrors0, NumErrors).
-compute_expr_purity(not(Goal0), not(Goal), _, PredInfo, ModuleInfo,
+compute_expr_purity(not(Goal0), NotGoal, GoalInfo0, PredInfo, ModuleInfo,
 		InClosure, Purity, NumErrors0, NumErrors) -->
-	compute_goal_purity(Goal0, Goal, PredInfo, ModuleInfo, 
-			    InClosure, Purity, NumErrors0, NumErrors).
+	%
+	% eliminate double negation
+	%
+	{ negate_goal(Goal0, GoalInfo0, NotGoal0) },
+	( { NotGoal0 = not(Goal1) - _GoalInfo1 } ->
+		compute_goal_purity(Goal1, Goal, PredInfo, ModuleInfo, 
+				    InClosure, Purity, NumErrors0, NumErrors),
+		{ NotGoal = not(Goal) }
+	;
+		compute_goal_purity(NotGoal0, NotGoal1, PredInfo, ModuleInfo, 
+				    InClosure, Purity, NumErrors0, NumErrors),
+		{ NotGoal1 = NotGoal - _ }
+	).
 compute_expr_purity(some(Vars, CanRemove, Goal0), some(Vars, CanRemove, Goal),
 		_, PredInfo, ModuleInfo, InClosure, Purity,
 		NumErrors0, NumErrors) -->
@@ -534,6 +549,9 @@
 	{ module_info_preds(ModuleInfo, Preds) },
 	{ map__lookup(Preds, PredId, PredInfo) },
 	{ pred_info_get_purity(PredInfo, Purity) }.
+compute_expr_purity(bi_implication(_, _), _, _, _, _, _, _, _, _) -->
+	% these should have been expanded out by now
+	{ error("compute_expr_purity: unexpected bi_implication") }.
 
 :- pred compute_goal_purity(hlds_goal, hlds_goal, pred_info,
 	module_info, bool, purity, int, int, io__state, io__state).
Index: compiler/quantification.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/quantification.m,v
retrieving revision 1.68
diff -u -d -r1.68 quantification.m
--- compiler/quantification.m	1999/07/13 08:53:26	1.68
+++ compiler/quantification.m	1999/10/24 15:32:11
@@ -12,6 +12,10 @@
 	% For the rules on implicit quantification, see the
 	% Mercury language reference manual.
 	%
+	% This pass also expands out bi-implications (that has to be
+	% done after quantification, and preferably as soon as possible,
+	% so we do it here).
+	%
 	% Rather than making implicit quantification explicit by
 	% inserting additional existential quantifiers in the form of
 	% `some/2' goals, we instead record existential quantification
@@ -353,6 +357,82 @@
 		pragma_c_code(A,B,C,Vars,E,F,G)) --> 
 	implicitly_quantify_atomic_goal(Vars).
 
+implicitly_quantify_goal_2(bi_implication(LHS0, RHS0), Context, Goal) -->
+		% get the initial values of various settings
+	quantification__get_quant_vars(QuantVars0),
+	quantification__get_outside(OutsideVars0),
+	quantification__get_lambda_outside(LambdaOutsideVars0),
+
+		% quantified variables cannot be pushed inside a negation,
+		% so we insert the quantified vars into the outside vars set,
+		% and initialize the new quantified vars set to be empty
+		% (the lambda outside vars remain unchanged)
+	{ set__union(OutsideVars0, QuantVars0, OutsideVars1) },
+	{ set__init(QuantVars1) },
+	{ LambdaOutsideVars1 = LambdaOutsideVars0 },
+	quantification__set_quant_vars(QuantVars1),
+
+		% prepare for quantifying the LHS:
+		% add variables from the RHS to the outside vars
+		% and the outside lambda vars sets.
+	{ quantification__goal_vars(RHS0, RHS_Vars, RHS_LambdaVars) },
+	{ set__union(OutsideVars1, RHS_Vars, LHS_OutsideVars) },
+	{ set__union(LambdaOutsideVars1, RHS_LambdaVars,
+			LHS_LambdaOutsideVars) },
+
+		% quantify the LHS
+	quantification__set_outside(LHS_OutsideVars),
+	quantification__set_lambda_outside(LHS_LambdaOutsideVars),
+	implicitly_quantify_goal(LHS0, LHS),
+	quantification__get_nonlocals(LHS_NonLocalVars),
+
+		% prepare for quantifying the RHS:
+		% add nonlocals from the LHS to the outside vars.
+		% (We use the nonlocals rather than the more symmetric
+		% approach of calling quantification__goal_vars on the
+		% LHS goal because it is more efficient.)
+	{ set__union(OutsideVars1, LHS_NonLocalVars, RHS_OutsideVars) },
+	{ RHS_LambdaOutsideVars = LambdaOutsideVars1 },
+
+		% quantify the RHS
+	quantification__set_outside(RHS_OutsideVars),
+	quantification__set_lambda_outside(RHS_LambdaOutsideVars),
+	implicitly_quantify_goal(RHS0, RHS),
+	quantification__get_nonlocals(RHS_NonLocalVars),
+
+		% compute the nonlocals for this goal
+	{ set__union(LHS_NonLocalVars, RHS_NonLocalVars, AllNonLocalVars) },
+	{ set__intersect(AllNonLocalVars, OutsideVars0, NonLocalVarsO) },
+	{ set__intersect(AllNonLocalVars, LambdaOutsideVars0, NonLocalVarsL) },
+	{ set__union(NonLocalVarsO, NonLocalVarsL, NonLocalVars) },
+	quantification__set_nonlocals(NonLocalVars),
+
+		% restore the original values of various settings
+	quantification__set_outside(OutsideVars0),
+	quantification__set_lambda_outside(LambdaOutsideVars0),
+	quantification__set_quant_vars(QuantVars0),
+
+		%
+		% We've figured out the quantification.
+		% Now expand the bi-implication according to the usual
+		% rules:
+		%	LHS <=> RHS
+		% ===>
+		%	(LHS => RHS), (RHS => LHS)
+		% ===>
+		%	(not (LHS, not RHS)), (not (RHS, not LHS))
+		%
+	{ goal_info_init(GoalInfo0) },
+	{ goal_info_set_context(GoalInfo0, Context, GoalInfo1) },
+	{ goal_info_set_nonlocals(GoalInfo1, LHS_NonLocalVars, LHS_GI) },
+	{ goal_info_set_nonlocals(GoalInfo1, RHS_NonLocalVars, RHS_GI) },
+	{ goal_info_set_nonlocals(GoalInfo1, NonLocalVars, GI) },
+	{ NotLHS = not(LHS) - LHS_GI },
+	{ NotRHS = not(RHS) - RHS_GI },
+	{ ForwardsImplication = not(conj([LHS, NotRHS]) - GI) - GI },
+	{ ReverseImplication = not(conj([RHS, NotLHS]) - GI) - GI },
+	{ Goal = conj([ForwardsImplication, ReverseImplication]) }.
+
 :- pred implicitly_quantify_atomic_goal(list(prog_var), quant_info, quant_info).
 :- mode implicitly_quantify_atomic_goal(in, in, out) is det.
 
@@ -715,6 +795,10 @@
 quantification__goal_vars_2(pragma_c_code(_, _, _, ArgVars, _, _, _),
 		Set0, LambdaSet, Set, LambdaSet) :-
 	set__insert_list(Set0, ArgVars, Set).
+
+quantification__goal_vars_2(bi_implication(LHS, RHS), Set0, LambdaSet0, Set,
+		LambdaSet) :-
+	goal_list_vars_2([LHS, RHS], Set0, LambdaSet0, Set, LambdaSet).
 
 :- pred quantification__unify_rhs_vars(unify_rhs, set(prog_var), set(prog_var),
 					set(prog_var), set(prog_var)).
Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.265
diff -u -d -r1.265 typecheck.m
--- compiler/typecheck.m	1999/07/22 17:14:39	1.265
+++ compiler/typecheck.m	1999/10/21 16:22:40
@@ -978,6 +978,10 @@
 		OrigTypeAssignSet) },
 	typecheck_call_pred_id(PredId, Args),
 	perform_context_reduction(OrigTypeAssignSet).
+typecheck_goal_2(bi_implication(LHS0, RHS0), bi_implication(LHS, RHS)) -->
+	checkpoint("<=>"),
+	typecheck_goal(LHS0, LHS),
+	typecheck_goal(RHS0, RHS).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/notes/compiler_design.html
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.39
diff -u -d -r1.39 compiler_design.html
--- compiler/notes/compiler_design.html	1999/10/14 05:27:35	1.39
+++ compiler/notes/compiler_design.html	1999/10/21 16:01:22
@@ -206,6 +206,9 @@
 
 	make_hlds.m transforms the code into superhomogeneous form,
 	and at the same time converts the parse tree into the HLDS.
+	It expands away universal quantification
+	(using `all [Vs] G' ===> `not (some [Vs] (not G))')
+	and implication (using `A => B' ===> `not(A, not B)').
 	It converts `pragma import', `pragma c_code' and `pragma fact_table'
 	declarations into clauses with HLDS `pragma_c_code'
 	instructions for bodies.
@@ -258,7 +261,10 @@
 	<dd>
 	quantification.m handles implicit quantification and computes
 	the set of non-local variables for each sub-goal.
-    This is done in transform in make_hlds.m
+	It also expands away bi-implication (unlike the expansion
+	of implication and universal quantification, this expansion
+	cannot be done until after quantification).
+	This pass is called from the `transform' predicate in make_hlds.m.
 
 <dt> checking typeclass instances (check_typeclass.m)
 	<dd>
@@ -324,6 +330,8 @@
 	complete the handling of predicate
 	overloading for cases which typecheck.m is unable to handle,
 	and to check for unbound type variables.
+	Elimination of double negation is also done here; that needs to
+	be done after quantification analysis and before mode analysis.
 
 <dt> polymorphism transformation
 
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.67
diff -u -d -r1.67 Mmakefile
--- tests/hard_coded/Mmakefile	1999/10/19 04:11:43	1.67
+++ tests/hard_coded/Mmakefile	1999/10/24 15:30:26
@@ -80,6 +80,7 @@
 	qual_basic_test \
 	qual_is_test \
 	quantifier \
+	quantifier2 \
 	quoting_bug_test \
 	rational_test \
 	relation_test \
cvs diff: tests/hard_coded/quantifier2.exp is a new entry, no comparison available
cvs diff: tests/hard_coded/quantifier2.m is a new entry, no comparison available
====================
tests/hard_coded/quantifier2.exp
====================
yes
====================
tests/hard_coded/quantifier2.m
====================
:- module quantifier2.

:- interface.

:- import_module io.

:- pred main(io__state::di,io__state::uo) is det.

:- implementation.

:- import_module list, int.

:- pred testsum(list(int),int,int).
:- mode testsum(in,in,out) is semidet.

testsum([],I,0) :- I > 0.
testsum([X|L],I,X + N1) :- testsum(L,I,N1). 


:- pred foo(pred(int, int)).
:- mode foo(free->pred(in, out) is semidet) is det.

foo(testsum([1,2,3])).


main -->
	(
		{ P = lambda([I :: in, X :: out] is semidet, (I > 0, X = 6)),
		  foo(Q), 
		  J = 1,
		  (call(P,J,_X) <=> call(Q,J,_Y)) }
	->
		print("yes"), nl
	;
		print("no"), nl
	).

====================

[continued in part 2]

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list