[m-rev.] for review: constraint propagation [1]

Simon Taylor stayl at cs.mu.OZ.AU
Thu Aug 2 22:50:47 AEST 2001


Hi,

This change was first reviewed early last year.
Below is a relative diff for constraint.m.
The full diff will be posted in another message.
The mailing list thread from last year can be found in
~stayl/constraint_mail.

Simon.


--- constraint.m.old	Thu Aug  2 22:13:26 2001
+++ constraint.m	Thu Aug  2 22:48:28 2001
@@ -1,5 +1,5 @@
 %-----------------------------------------------------------------------------%
-% Copyright (C) 2000 The University of Melbourne.
+% Copyright (C) 2001 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
 %-----------------------------------------------------------------------------%
@@ -18,17 +18,17 @@
 :- interface.
 
 :- import_module hlds_goal, hlds_module, instmap, prog_data.
-:- import_module bool, list, map, std_util.
+:- import_module bool, map.
 
-:- pred constraint__propagate_goal(hlds_goal, list(constraint),
-		hlds_goal, constraint_info, constraint_info).
-:- mode constraint__propagate_goal(in, in, out, 
-		in, out) is det.
+:- type constraint_info.
 
-:- pred constraint__propagate_conj(list(hlds_goal), list(constraint), 
-		list(hlds_goal), constraint_info, constraint_info).
-:- mode constraint__propagate_conj(in, in, out,
-		in, out) is det.
+	% constraint__propagate_constraints_in_goal pushes constraints
+	% left and inward within a single goal. Specialized versions of
+	% procedures which are called with constrained outputs are created
+	% by deforest.m.
+:- pred constraint__propagate_constraints_in_goal(hlds_goal, hlds_goal,
+		constraint_info, constraint_info).
+:- mode constraint__propagate_constraints_in_goal(in, out, in, out) is det.
 
 :- pred constraint_info_init(module_info, map(prog_var, type), prog_varset,
 		instmap, constraint_info).
@@ -38,14 +38,6 @@
 		map(prog_var, type), prog_varset, bool).
 :- mode constraint_info_deconstruct(in, out, out, out, out) is det.
 
-:- type constraint_info.
-
-	% A constraint is a goal with no outputs which can fail and
-	% always terminates, and a list of goals to construct static
-	% constants for the constraint. All the goals should have a
-	% `constraint' annotation.
-:- type constraint == pair(hlds_goal, list(hlds_goal)).
-
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -55,27 +47,31 @@
 :- import_module mode_util, passes_aux, code_aux, inst_match, purity.
 :- import_module options, globals.
 
-:- import_module assoc_list, require, set, string, term, varset.
+:- import_module assoc_list, list, require, set, std_util.
+:- import_module string, term, varset.
 
 %-----------------------------------------------------------------------------%
 
+constraint__propagate_constraints_in_goal(Goal0, Goal) -->
+	% We need to strip off any existing constraint markers first.
+	% Constraint markers are meant to indicate where a constraint
+	% is meant to be attached to a call, and that deforest.m should
+	% consider creating a specialized version for the call.
+	% If deforest.m rearranges the goal, the constraints may
+	% not remain next to the call.
+	{ Goal1 = strip_constraint_markers(Goal0) },
+	constraint__propagate_goal(Goal1, [], Goal).
+
+:- pred constraint__propagate_goal(hlds_goal, list(constraint),
+		hlds_goal, constraint_info, constraint_info).
+:- mode constraint__propagate_goal(in, in, out, in, out) is det.
+
 constraint__propagate_goal(Goal0, Constraints, Goal) -->
-	{ Goal0 = _ - GoalInfo0 },
-	
-	% 
-	% If the goal cannot succeed, prune away the constraints.
-	% This is necessary because the goal might not produce some
-	% of the inputs to the constraints, so reordering the constraints
-	% with the goal may cause compiler aborts later.
-	%
-	{ goal_info_get_determinism(GoalInfo0, Detism) },
-	( { determinism_components(Detism, _, at_most_zero) } ->
-		{ Goals = [Goal0] }
-	;
-		InstMap0 =^ instmap,
-		constraint__propagate_goal_2(Goal0, Constraints, Goals),
-		^ instmap := InstMap0
-	),
+	% We need to treat all single goals as conjunctions so that
+	% constraint__propagate_conj can move the constraints to the
+	% left of the goal if that is allowed.
+	{ goal_to_conj_list(Goal0, Goals0) },
+	constraint__propagate_conj(Goals0, Constraints, Goals),
 	{ Goals = [Goal1] ->
 		Goal = Goal1
 	;
@@ -86,77 +82,105 @@
 		conj_list_to_goal(Goals, GoalInfo, Goal)
 	}.
 
-:- pred constraint__propagate_goal_2(hlds_goal, list(constraint),
+:- pred constraint__propagate_conj_sub_goal(hlds_goal, list(constraint),
+		hlds_goals, constraint_info, constraint_info).
+:- mode constraint__propagate_conj_sub_goal(in, in, out, 
+		in, out) is det.
+
+constraint__propagate_conj_sub_goal(Goal0, Constraints, Goals) -->
+	{ Goal0 = GoalExpr0 - _ },
+	( { goal_is_atomic(GoalExpr0) } ->
+		[]
+	;
+		% If a non-empty list of constraints is pushed into a sub-goal,
+		% quantification, instmap_deltas and determinism need to be
+		% recomputed.
+		constraint_info_update_changed(Constraints)
+	),
+	InstMap0 =^ instmap,
+	constraint__propagate_conj_sub_goal_2(Goal0, Constraints, Goals),
+	^ instmap := InstMap0.
+
+:- pred constraint__propagate_conj_sub_goal_2(hlds_goal, list(constraint),
 		list(hlds_goal), constraint_info, constraint_info).
-:- mode constraint__propagate_goal_2(in, in, out, in, out) is det.
+:- mode constraint__propagate_conj_sub_goal_2(in, in, out, in, out) is det.
 
-constraint__propagate_goal_2(conj(Goals0) - Info, Constraints, 
+constraint__propagate_conj_sub_goal_2(conj(Goals0) - Info, Constraints, 
 		[conj(Goals) - Info]) -->
-	constraint_info_update_changed(Constraints),
 	constraint__propagate_conj(Goals0, Constraints, Goals).
 
-constraint__propagate_goal_2(disj(Goals0, SM) - Info, Constraints,
+constraint__propagate_conj_sub_goal_2(disj(Goals0, SM) - Info, Constraints,
 		[disj(Goals, SM) - Info]) -->
 	constraint__propagate_disj(Goals0, Constraints, Goals).
 
-constraint__propagate_goal_2(switch(Var, CanFail, Cases0, SM) - Info,
+constraint__propagate_conj_sub_goal_2(switch(Var, CanFail, Cases0, SM) - Info,
 		Constraints, [switch(Var, CanFail, Cases, SM) - Info]) -->
-	constraint_info_update_changed(Constraints),
 	constraint__propagate_cases(Var, Cases0, Constraints, Cases).
 	
-constraint__propagate_goal_2(
+constraint__propagate_conj_sub_goal_2(
 		if_then_else(Vars, Cond0, Then0, Else0, SM) - Info,
 		Constraints, 
 		[if_then_else(Vars, Cond, Then, Else, SM) - Info]) -->
 	InstMap0 =^ instmap,
-	constraint_info_update_changed(Constraints),
 
 	% We can't safely propagate constraints into 
-	% the condition of an if-then-else.
+	% the condition of an if-then-else, because that
+	% would change the answers generated by the procedure.
 	constraint__propagate_goal(Cond0, [], Cond),
 	constraint_info_update_goal(Cond),
 	constraint__propagate_goal(Then0, Constraints, Then),
 	^ instmap := InstMap0,
-	constraint__propagate_goal(Else0, Constraints, Else),
-	^ instmap := InstMap0.
+	constraint__propagate_goal(Else0, Constraints, Else).
 
-	% XXX propagate constraints into par_conjs - could be a little tricky.
-constraint__propagate_goal_2(par_conj(Goals0, SM) - GoalInfo, Constraints0,
+	% XXX propagate constraints into par_conjs -- this isn't
+	% possible at the moment because par_conj goals must have
+	% determinism det.
+constraint__propagate_conj_sub_goal_2(par_conj(Goals0, SM) - GoalInfo,
+		Constraints0,
 		[par_conj(Goals, SM) - GoalInfo | Constraints]) -->
+	% Propagate constraints within the goals of the conjunction.
 	% constraint__propagate_disj treats its list of goals as
 	% independent rather than specifically disjoint, so we can
 	% use it to process a list of independent parallel conjuncts.
 	constraint__propagate_disj(Goals0, [], Goals),
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
-constraint__propagate_goal_2(some(Vars, CanRemove, Goal0) - GoalInfo,
+constraint__propagate_conj_sub_goal_2(some(Vars, CanRemove, Goal0) - GoalInfo,
 		Constraints, [some(Vars, CanRemove, Goal) - GoalInfo]) -->
-	constraint_info_update_changed(Constraints),
 	constraint__propagate_goal(Goal0, Constraints, Goal).
 
-constraint__propagate_goal_2(not(NegGoal0) - GoalInfo, Constraints0,
+constraint__propagate_conj_sub_goal_2(not(NegGoal0) - GoalInfo, Constraints0,
 		[not(NegGoal) - GoalInfo | Constraints]) -->
-	% We can't safely propagate constraints into a negation.
+	% We can't safely propagate constraints into a negation,
+	% because that would change the answers computed by the
+	% procedure.
 	constraint__propagate_goal(NegGoal0, [], NegGoal),
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
-constraint__propagate_goal_2(Goal, Constraints0, [Goal | Constraints]) -->
+constraint__propagate_conj_sub_goal_2(Goal, Constraints0,
+		[Goal | Constraints]) -->
+	% constraint__propagate_conj will move the constraints
+	% to the left of the call if that is possible, so nothing
+	% needs to be done here.
 	{ Goal = call(_, _, _, _, _, _) - _ },
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
-constraint__propagate_goal_2(Goal, Constraints0, [Goal | Constraints]) -->
+constraint__propagate_conj_sub_goal_2(Goal, Constraints0,
+		[Goal | Constraints]) -->
 	{ Goal = generic_call(_, _, _, _) - _ },
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
-constraint__propagate_goal_2(Goal, Constraints0, [Goal | Constraints]) -->
-	{ Goal = pragma_c_code(_, _, _, _, _, _, _) - _ },
+constraint__propagate_conj_sub_goal_2(Goal, Constraints0,
+		[Goal | Constraints]) -->
+	{ Goal = foreign_proc(_, _, _, _, _, _, _) - _ },
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
-constraint__propagate_goal_2(Goal, _, _) -->
-	{ Goal = bi_implication(_, _) - _ },
-	{ error("constraint__propagate_goal_2: bi_implication") }.
+constraint__propagate_conj_sub_goal_2(Goal, _, _) -->
+	{ Goal = shorthand(_) - _ },
+	{ error("constraint__propagate_conj_sub_goal_2: shorthand") }.
 
-constraint__propagate_goal_2(Goal, Constraints0, [Goal | Constraints]) -->
+constraint__propagate_conj_sub_goal_2(Goal, Constraints0,
+		[Goal | Constraints]) -->
 	{ Goal = unify(_, _, _, _, _) - _ },
 	{ constraint__flatten_constraints(Constraints0, Constraints) }.
 
@@ -168,7 +192,7 @@
 
 constraint__flatten_constraints(Constraints0, Goals) :-
 	list__map(lambda([Constraint::in, Lists::out] is det, (
-			Constraint = Goal - Constructs,
+			Constraint = constraint(Goal, _, _, Constructs),
 			Lists = [Constructs, [Goal]]
 	)), Constraints0, GoalLists0),
 	list__condense(GoalLists0, GoalLists),
@@ -211,46 +235,115 @@
 	% in the list. Some effort is made to keep the constraints
 	% in the same order as they are encountered to increase
 	% the likelihood of folding recursive calls.
+:- pred constraint__propagate_conj(list(hlds_goal), list(constraint), 
+		list(hlds_goal), constraint_info, constraint_info).
+:- mode constraint__propagate_conj(in, in, out,
+		in, out) is det.
 
 constraint__propagate_conj(Goals0, Constraints, Goals) -->
-	InstMap0 =^ instmap,
-	ModuleInfo =^ module_info,
-	{ constraint__annotate_conj_output_vars(Goals0, ModuleInfo,
-		InstMap0, [], RevGoals1) },
-	constraint__annotate_conj_constraints(ModuleInfo, RevGoals1, 
-		Constraints, [], Goals2),
-	constraint__propagate_conj_constraints(Goals2, [], Goals).
+	( { Goals0 = [] } ->
+		{ constraint__flatten_constraints(Constraints, Goals) }
+	; { Goals0 = [Goal0], Constraints = [] } ->
+		constraint__propagate_conj_sub_goal(Goal0, [], Goals)
+	;
+		constraint_info_update_changed(Constraints),
+		InstMap0 =^ instmap,
+		ModuleInfo =^ module_info,
+		VarTypes =^ vartypes,
+		{ constraint__annotate_conj_output_vars(Goals0, ModuleInfo,
+			VarTypes, InstMap0, [], RevGoals1) },
+		constraint__annotate_conj_constraints(ModuleInfo, RevGoals1, 
+			Constraints, [], Goals2),
+		constraint__propagate_conj_constraints(Goals2, [], Goals)
+	).
 
 	% Annotate each conjunct with the variables it produces.
-:- pred constraint__annotate_conj_output_vars(list(hlds_goal), 
-		module_info, instmap, annotated_conj, annotated_conj).
-:- mode constraint__annotate_conj_output_vars(in, in, in, in, out) is det.
-
-constraint__annotate_conj_output_vars([], _, _, RevGoals, RevGoals).
-constraint__annotate_conj_output_vars([Goal | Goals], ModuleInfo, InstMap0, 
-		RevGoals0, RevGoals) :-
+:- pred constraint__annotate_conj_output_vars(list(hlds_goal), module_info,
+		vartypes, instmap, annotated_conj, annotated_conj).
+:- mode constraint__annotate_conj_output_vars(in, in, in, in, in, out) is det.
+
+constraint__annotate_conj_output_vars([], _, _, _, RevGoals, RevGoals).
+constraint__annotate_conj_output_vars([Goal | Goals], ModuleInfo, VarTypes,
+		InstMap0, RevGoals0, RevGoals) :-
 	Goal = _ - GoalInfo,
 	goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
 
-	% XXX this won't work on the alias branch.
-	instmap_delta_changed_vars(InstMapDelta, ChangedVars0),
-	Bound = lambda([Var::in] is semidet, (
-			instmap__lookup_var(InstMap0, Var, InstMapInst),
-			instmap_delta_search_var(InstMapDelta, Var, DeltaInst),
-			\+ inst_matches_binding(InstMapInst,
-				DeltaInst, ModuleInfo)
-		)),
-	set__to_sorted_list(ChangedVars0, ChangedVars1),
-	list__filter(Bound, ChangedVars1, ChangedVars2),
-	set__sorted_list_to_set(ChangedVars2, ChangedVars),
 	instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMap),
-	constraint__annotate_conj_output_vars(Goals, ModuleInfo, InstMap, 
-		[Goal - ChangedVars | RevGoals0], RevGoals).
+	instmap_changed_vars(InstMap0, InstMap, VarTypes,
+		ModuleInfo, ChangedVars),
+
+	% Restrict the set of changed variables down to the set
+	% for which the new inst is not an acceptable subsitute
+	% for the old. This is done to allow reordering of a goal which
+	% uses a variable with inst `ground(shared, no)' with
+	% a constraint which just adds information, changing the inst
+	% to `bound(shared, ...)'.
+	InCompatible = (pred(Var::in) is semidet :-
+			instmap__lookup_var(InstMap0, Var, InstBefore),
+			instmap_delta_search_var(InstMapDelta, Var, InstAfter),
+			\+ inst_matches_initial(InstAfter, InstBefore,
+				map__lookup(VarTypes, Var), ModuleInfo)
+		),
+	IncompatibleInstVars = set__filter(InCompatible, ChangedVars), 
+
+	Bound = (pred(Var::in) is semidet :-
+			instmap__lookup_var(InstMap0, Var, InstBefore),
+			instmap_delta_search_var(InstMapDelta, Var, InstAfter),
+			\+ inst_matches_binding(InstAfter, InstBefore,
+				map__lookup(VarTypes, Var), ModuleInfo)
+		),
+	BoundVars = set__filter(Bound, ChangedVars),
+
+	AnnotatedConjunct = annotated_conjunct(Goal, ChangedVars, BoundVars,
+				IncompatibleInstVars),
+	constraint__annotate_conj_output_vars(Goals, ModuleInfo, VarTypes,
+		InstMap, [AnnotatedConjunct | RevGoals0], RevGoals).
 
 %-----------------------------------------------------------------------------%
 
-	% Conjunction annotated with its output variables.
-:- type annotated_conj == assoc_list(hlds_goal, set(prog_var)).
+	% Conjunction annotated with the variables each conjunct
+	% changes the instantiatedness of.
+:- type annotated_conj == list(annotated_conjunct).
+
+:- type annotated_conjunct
+	---> annotated_conjunct(
+		hlds_goal,
+
+			% All variables returned by instmap_changed_vars.
+		set(prog_var),
+
+			% All variables returned by instmap_changed_vars for
+			% which inst_matches_binding(NewInst, OldInst) fails.
+		set(prog_var),
+
+			% Variables returned by instmap_changed_vars
+			% for which the new inst cannot be substituted
+			% for the old as an input to a goal
+			% (inst_matches_initial(NewInst, OldInst) fails).
+		set(prog_var)
+	).
+
+	% A constraint is a goal with no outputs which can fail and
+	% always terminates.
+:- type constraint
+	---> constraint(
+			% The constraint itself.
+		hlds_goal,
+
+			% All variables returned by instmap_changed_vars.
+		set(prog_var),
+
+			% Variables returned by instmap_changed_vars
+			% for which the new inst cannot be substituted
+			% for the old as an input to a goal
+			% (inst_matches_initial(NewInst, OldInst) fails).
+		set(prog_var),
+		
+			% Goals to construct constants used by the constraint.
+			% (as in X = 2, Y < X). These need to be propagated
+			% with the constraint.
+		list(hlds_goal)
+	).
 
 	% Conjunction annotated with constraining goals.
 :- type constrained_conj == assoc_list(hlds_goal, list(constraint)).
@@ -270,26 +363,37 @@
 		)), Constraints1, Constraints) },
 	{ list__append(Constraints, Goals0, Goals) }.
 constraint__annotate_conj_constraints(ModuleInfo, 
-		[Goal - OutputVars | RevGoals0], 
+		[Conjunct | RevConjuncts0],
 		Constraints0, Goals0, Goals) -->
 	{ Goal = GoalExpr - GoalInfo },
+	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
+	{ Conjunct = annotated_conjunct(Goal, ChangedVars,
+			OutputVars, IncompatibleInstVars) },
 	(
 		% Propagate goals with no output variables which can fail.
+		% Propagating cc_nondet goals would be tricky, because we
+		% would need to be careful about reordering the constraints
+		% (the cc_nondet goal can't be moved before any goals
+		% which can fail).
+		% 
 		{ goal_info_get_determinism(GoalInfo, Detism) },
 		{ Detism = semidet
 		; Detism = failure
-		% ; Detism = cc_nondet	% ??
 		},
 		{ set__empty(OutputVars) },
 
+		% Don't propagate impure goals.
+		{ goal_info_is_pure(GoalInfo) },
+
 		% Don't propagate goals that can loop. 
 		{ code_aux__goal_cannot_loop(ModuleInfo, Goal) }
 	->
+		% It's a constraint, add it to the list of constraints
+		% to be attached to goals earlier in the conjunction.
 		{ Goals1 = Goals0 },
-		% Put the `constraint' feature on the goal so deforest.m
-		% knows to attempt to propagate this goal through calls.
-		{ goal_info_add_feature(GoalInfo, constraint, GoalInfo1) },
-		{ Constraints1 = [(GoalExpr - GoalInfo1) - [] | Constraints0] }
+		{ Constraint = constraint(GoalExpr - GoalInfo,
+				ChangedVars, IncompatibleInstVars, []) },
+		{ Constraints1 = [Constraint | Constraints0] }
 	;
 		%
 		% Look for a simple goal which some constraint depends
@@ -310,6 +414,15 @@
 		constraint__add_constant_construction(ConstructVar, Goal,
 			Constraints0, Constraints1)
 	;	
+		% Prune away the constraints after a goal
+		% which cannot succeed -- they can never be
+		% executed.
+		{ goal_info_get_determinism(GoalInfo, Detism) },
+		{ determinism_components(Detism, _, at_most_zero) }
+	->
+		{ Constraints1 = [] },
+		{ Goals1 = [Goal - [] | Goals0] }	
+	;
 		% Don't propagate constraints into or past impure goals.
 		{ Goal = _ - GoalInfo },
 		{ goal_info_is_impure(GoalInfo) }
@@ -319,42 +432,34 @@
 			ConstraintGoals) },
 		{ list__map(add_empty_constraints, [Goal | ConstraintGoals],
 			GoalsAndConstraints) },
-
 		{ list__append(GoalsAndConstraints, Goals0, Goals1) }
 	;
-		% Prune away the constraints after a goal
-		% which cannot succeed.
-		{ Goal = _ - GoalInfo },
-		{ goal_info_get_determinism(GoalInfo, Detism) },
-		{ determinism_components(Detism, _, at_most_zero) }
-	->
-		{ Constraints1 = [] },
-		{ Goals1 = [Goal - [] | Goals0] }	
-	;
 		% Don't move goals which can fail before a goal which
 		% can loop if `--fully-strict' is set.
-		{ module_info_globals(ModuleInfo, Globals) },
 		{ \+ code_aux__goal_cannot_loop(ModuleInfo, Goal) },
+		{ module_info_globals(ModuleInfo, Globals) },
 		{ globals__lookup_bool_option(Globals, fully_strict, yes) }
 	->
-		{ constraint__filter_dependent_constraints(OutputVars, 
-			Constraints0, [], ConstraintsToAttach,
+		{ constraint__filter_dependent_constraints(NonLocals,
+			ChangedVars, Constraints0, [], ConstraintsToAttach,
 			[], OtherConstraints) },
 		{ constraint__flatten_constraints(OtherConstraints,
 			ConstraintGoals) },
 		{ list__map(add_empty_constraints, ConstraintGoals,
 			GoalsAndConstraints) },
-		{ list__append(
-			[Goal - ConstraintsToAttach | GoalsAndConstraints],
-			Goals0, Goals1) },
+		{ Goals1 = 
+			[attach_constraints(Goal, ConstraintsToAttach)
+				| GoalsAndConstraints]
+			++ Goals0 },
 		{ Constraints1 = [] }
 	;
-		{ constraint__filter_dependent_constraints(OutputVars, 
-			Constraints0, [], ConstraintsToAttach,
+		{ constraint__filter_dependent_constraints(NonLocals,
+			OutputVars, Constraints0, [], ConstraintsToAttach,
 			[], Constraints1) },
-		{ Goals1 = [Goal - ConstraintsToAttach | Goals0] }
+		{ Goals1 = [attach_constraints(Goal, ConstraintsToAttach)
+				| Goals0] }
 	),
-	constraint__annotate_conj_constraints(ModuleInfo, RevGoals0, 
+	constraint__annotate_conj_constraints(ModuleInfo, RevConjuncts0, 
 		Constraints1, Goals1, Goals).
 
 :- pred add_empty_constraints(hlds_goal::in,
@@ -362,20 +467,43 @@
 
 add_empty_constraints(Goal, Goal - []).
 
+:- func attach_constraints(hlds_goal, list(constraint)) =
+		pair(hlds_goal, list(constraint)).
+
+attach_constraints(Goal, Constraints0) = Goal - Constraints :-
+        ( Goal = call(_, _, _, _, _, _) - _ ->
+                Constraints = list__map(
+                    (func(constraint(Goal0, B, C, Constructs0)) =
+                        constraint(add_constraint_feature(Goal0), B, C,
+                            list__map(add_constraint_feature, Constructs0))
+                    ), Constraints0)
+        ;
+                Constraints = Constraints0
+        ).
+
+:- func add_constraint_feature(hlds_goal) = hlds_goal.
+
+add_constraint_feature(Goal - GoalInfo0) = Goal - GoalInfo :-
+	goal_info_add_feature(GoalInfo0, constraint, GoalInfo).
+
+%-----------------------------------------------------------------------------%
+
+
 :- pred constraint__add_constant_construction(prog_var::in, hlds_goal::in,
 		list(constraint)::in, list(constraint)::out,
 		constraint_info::in, constraint_info::out) is det.
 
 constraint__add_constant_construction(_, _, [], []) --> [].
 constraint__add_constant_construction(ConstructVar, Construct0,
-		[Constraint0 - Constructs0 | Constraints0],
-		[Constraint - Constructs | Constraints]) -->
+		[Constraint0 | Constraints0],
+		[Constraint | Constraints]) -->
+	{ Constraint0 = constraint(ConstraintGoal0, ChangedVars,
+				IncompatibleInstVars, Constructs0) },
 	(
-		{
-		Constraint0 = _ - ConstraintInfo,
-		goal_info_get_nonlocals(ConstraintInfo, ConstraintNonLocals),
-		set__member(ConstructVar, ConstraintNonLocals)
-		}
+		{ ConstraintGoal0 = _ - ConstraintInfo },
+		{ goal_info_get_nonlocals(ConstraintInfo,
+			ConstraintNonLocals) },
+		{ set__member(ConstructVar, ConstraintNonLocals) }
 	->
 		VarSet0 =^ varset,
 		VarTypes0 =^ vartypes,
@@ -386,47 +514,70 @@
 		^ vartypes := VarTypes,
 		{ map__from_assoc_list([ConstructVar - NewVar], Subn) },
 		{ goal_util__rename_vars_in_goal(Construct0,
-			Subn, Construct1) },
-		{ Construct1 = ConstructExpr - ConstructInfo1 },
-		{ goal_info_add_feature(ConstructInfo1,
-			constraint, ConstructInfo) },
-		{ Constructs = [ConstructExpr - ConstructInfo | Constructs0] },
-		{ goal_util__rename_vars_in_goal(Constraint0,
-			Subn, Constraint) }
+			Subn, Construct) },
+		{ Constructs = [Construct | Constructs0] },
+		{ goal_util__rename_vars_in_goal(ConstraintGoal0,
+			Subn, ConstraintGoal) },
+		{ Constraint = constraint(ConstraintGoal, ChangedVars,
+				IncompatibleInstVars, Constructs) }
 	;
-		{ Constraint = Constraint0 },
-		{ Constructs = Constructs0 }
+		{ Constraint = Constraint0 }
 	),
 	constraint__add_constant_construction(ConstructVar, Construct0,
 		Constraints0, Constraints). 
 
+%-----------------------------------------------------------------------------%
+
 	% Find all constraints which depend on the
 	% output variables of the goal.
-:- pred constraint__filter_dependent_constraints(set(prog_var),
+:- pred constraint__filter_dependent_constraints(set(prog_var), set(prog_var),
 		list(constraint), list(constraint), list(constraint),
 		list(constraint), list(constraint)).
-:- mode constraint__filter_dependent_constraints(in, in, 
+:- mode constraint__filter_dependent_constraints(in, in, in,
 		in, out, in, out) is det.
 
-constraint__filter_dependent_constraints(_Vars, [], RevToAttach, ToAttach, 
-		RevOthers, Others) :-
+constraint__filter_dependent_constraints(_NonLocals, _Vars, [],
+		RevToAttach, ToAttach, RevOthers, Others) :-
 	list__reverse(RevToAttach, ToAttach),
 	list__reverse(RevOthers, Others).
-constraint__filter_dependent_constraints(GoalOutputVars, [Constraint | Goals],
-		ToAttach0, ToAttach, Others0, Others) :-
-	Constraint = Goal - _,
-	Goal = _ - GoalInfo,
-	goal_info_get_nonlocals(GoalInfo, NonLocals),
-	set__intersect(NonLocals, GoalOutputVars, Intersection),
-	( set__empty(Intersection) ->
+constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
+		[Constraint | Goals], ToAttach0, ToAttach, Others0, Others) :-
+	Constraint = constraint(ConstraintGoal, _, IncompatibleInstVars, _),
+	ConstraintGoal = _ - ConstraintGoalInfo,
+	goal_info_get_nonlocals(ConstraintGoalInfo, ConstraintNonLocals),
+	set__intersect(ConstraintNonLocals, GoalOutputVars,
+		OutputVarsUsedByConstraint),
+
+	% Don't reorder a constraint which changes the inst of
+	% a variable in such a way that the new inst is incompatible
+	% with the old inst (e.g. by losing uniqueness),
+	% with any goal which has that variable in its non-locals set.
+	%
+	% Don't reorder a constraint with another constraint which
+	% changes the instantiatedness of one of its input variables.
+	set__intersect(NonLocals, IncompatibleInstVars,
+		IncompatibleInstVarsUsedByGoal),
+	(
+		(
+			set__empty(OutputVarsUsedByConstraint),
+			set__empty(IncompatibleInstVarsUsedByGoal)
+		;
+			list__member(EarlierConstraint, ToAttach0),
+			EarlierConstraint = constraint(_,
+				EarlierChangedVars, _, _),
+			set__intersect(EarlierChangedVars, ConstraintNonLocals,
+				EarlierConstraintIntersection),
+			\+ set__empty(EarlierConstraintIntersection)
+		)
+	->
 		Others1 = [Constraint | Others0],
 		ToAttach1 = ToAttach0
 	;
 		Others1 = Others0,
 		ToAttach1 = [Constraint | ToAttach0]
 	),
-	constraint__filter_dependent_constraints(GoalOutputVars, Goals, 
-		ToAttach1, ToAttach, Others1, Others).
+	constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
+		Goals, ToAttach1, ToAttach, Others1, Others).
 	
 %-----------------------------------------------------------------------------%
 
@@ -440,7 +591,7 @@
 	{ list__reverse(RevGoals, Goals) }.
 constraint__propagate_conj_constraints([Goal0 - Constraints | Goals0],
 		RevGoals0, RevGoals) -->
-	constraint__propagate_goal_2(Goal0, Constraints, GoalList1),
+	constraint__propagate_conj_sub_goal(Goal0, Constraints, GoalList1),
 	{ list__reverse(GoalList1, RevGoalList1) },
 	{ list__append(RevGoalList1, RevGoals0, RevGoals1) },
 	constraint_info_update_goal(Goal0),
@@ -500,6 +651,53 @@
 	;
 		^ changed := yes
 	).
+
+%-----------------------------------------------------------------------------%
+
+	% Remove all `constraint' goal features from the goal_infos
+	% of all sub-goals of the given goal.
+:- func strip_constraint_markers(hlds_goal) = hlds_goal.
+
+strip_constraint_markers(Goal - GoalInfo0) =
+		strip_constraint_markers_expr(Goal) - GoalInfo :-
+	( goal_info_has_feature(GoalInfo0, constraint) ->
+		goal_info_remove_feature(GoalInfo0, constraint, GoalInfo)
+	;
+		GoalInfo = GoalInfo0
+	).
+
+:- func strip_constraint_markers_expr(hlds_goal_expr) = hlds_goal_expr.
+
+strip_constraint_markers_expr(conj(Goals)) =
+		conj(list__map(strip_constraint_markers, Goals)).
+strip_constraint_markers_expr(disj(Goals, SM)) =
+		disj(list__map(strip_constraint_markers, Goals), SM).
+strip_constraint_markers_expr(switch(Var, CanFail, Cases0, SM)) =
+		switch(Var, CanFail, Cases, SM) :-
+	Cases = list__map(
+		    (func(case(ConsId, Goal)) =
+			case(ConsId, strip_constraint_markers(Goal))
+		    ), Cases0).
+strip_constraint_markers_expr(not(Goal)) =
+		not(strip_constraint_markers(Goal)).
+strip_constraint_markers_expr(some(Vars, Remove, Goal)) =
+		some(Vars, Remove, strip_constraint_markers(Goal)).
+strip_constraint_markers_expr(if_then_else(Vars, If, Then, Else, SM)) =
+		if_then_else(Vars, strip_constraint_markers(If),
+			strip_constraint_markers(Then),
+			strip_constraint_markers(Else), SM).
+strip_constraint_markers_expr(par_conj(Goals, SM)) =
+		par_conj(list__map(strip_constraint_markers, Goals), SM).
+strip_constraint_markers_expr(Goal) = Goal :-
+	Goal = foreign_proc(_, _, _, _, _, _, _).
+strip_constraint_markers_expr(Goal) = Goal :-
+	Goal = generic_call(_, _, _, _).
+strip_constraint_markers_expr(Goal) = Goal :-
+	Goal = call(_, _, _, _, _, _).
+strip_constraint_markers_expr(Goal) = Goal :-
+	Goal = unify(_, _, _, _, _).
+strip_constraint_markers_expr(Goal) = Goal :-
+	Goal = shorthand(_).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
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