[m-rev.] for review: adding promise ex declarations to the hlds with error checking

Lars Yencken lljy at students.cs.mu.oz.au
Wed Feb 20 10:49:34 AEDT 2002


Here's the new full diff.

Lars

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


Index: assertion.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/assertion.m,v
retrieving revision 1.14
diff -u -r1.14 assertion.m
--- assertion.m	20 Jul 2001 14:13:19 -0000	1.14
+++ assertion.m	14 Feb 2002 01:59:54 -0000
@@ -127,6 +127,14 @@
 		module_info::in, module_info::out,
 		io__state::di, io__state::uo) is det.
 
+	%
+	% assertion__normalise_goal
+	%
+	% Place a hlds_goal into a standard form.  Currently all the
+	% code does is replace conj([G]) with G.
+	%
+:- pred assertion__normalise_goal(hlds_goal::in, hlds_goal::out) is det.
+
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -650,14 +658,6 @@
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
-
-	%
-	% assertion__normalise_goal
-	%
-	% Place a hlds_goal into a standard form.  Currently all the
-	% code does is replace conj([G]) with G.
-	%
-:- pred assertion__normalise_goal(hlds_goal::in, hlds_goal::out) is det.
 
 assertion__normalise_goal(call(A,B,C,D,E,F) - GI, call(A,B,C,D,E,F) - GI).
 assertion__normalise_goal(generic_call(A,B,C,D) - GI, generic_call(A,B,C,D)-GI).
Index: dead_proc_elim.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.67
diff -u -r1.67 dead_proc_elim.m
--- dead_proc_elim.m	25 Jan 2002 08:22:47 -0000	1.67
+++ dead_proc_elim.m	14 Feb 2002 01:55:57 -0000
@@ -808,8 +808,8 @@
 			string__remove_suffix(PredName, "_init_any", _),
 			PredArity = 1
 		;
-			% Don't eliminate the clauses for assertions.
-			pred_info_get_goal_type(PredInfo, assertion)
+			% Don't eliminate the clauses for promises.
+			pred_info_get_goal_type(PredInfo, promise(_))
 		)
 	->
 		set__insert(NeededNames0, qualified(PredModule, PredName), 
Index: error_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/error_util.m,v
retrieving revision 1.15
diff -u -r1.15 error_util.m
--- error_util.m	30 Jul 2001 03:55:49 -0000	1.15
+++ error_util.m	19 Feb 2002 01:41:29 -0000
@@ -416,9 +416,9 @@
 		OrigArity is Arity - 1
 	),
 	(
-		pred_info_get_goal_type(PredInfo, assertion)
+		pred_info_get_goal_type(PredInfo, promise(PromiseType))
 	->
-		Piece = "promise"
+		Piece = "`" ++ promise_to_string(PromiseType) ++ "' declaration"
 	;
 		string__int_to_string(OrigArity, ArityPart),
 		string__append_list([
Index: goal_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.71
diff -u -r1.71 goal_util.m
--- goal_util.m	26 Nov 2001 09:30:56 -0000	1.71
+++ goal_util.m	19 Feb 2002 04:48:40 -0000
@@ -149,6 +149,14 @@
 :- pred direct_subgoal(hlds_goal_expr, hlds_goal).
 :- mode direct_subgoal(in, out) is nondet.
 
+	% returns all the predids that are used within a goal
+:- pred predids_from_goal(hlds_goal, list(pred_id)).
+:- mode predids_from_goal(in, out) is det.
+	
+	% returns all the predids that are used in a list of goals
+:- pred predids_from_goals(list(hlds_goal), list(pred_id)).
+:- mode predids_from_goals(in, out) is det.
+
 %-----------------------------------------------------------------------------%
 
 	% Convert a switch back into a disjunction. This is needed 
@@ -1283,5 +1291,24 @@
 		CallGoalInfo = CallGoalInfo1
 	),
 	CallGoal = Call - CallGoalInfo.
+
+%-----------------------------------------------------------------------------%
+
+predids_from_goals(Goals, PredIds) :- 
+	(
+		Goals = [],
+		PredIds = []
+	;
+		Goals = [Goal | Rest],
+		predids_from_goal(Goal, PredIds0),
+		predids_from_goals(Rest, PredIds1),
+		PredIds = PredIds0 ++ PredIds1
+	).
+
+predids_from_goal(Goal, PredIds) :-
+                % Explicit lambda expression needed since
+		% goal_calls_pred_id has multiple modes.
+	P = (pred(PredId::out) is nondet :- goal_calls_pred_id(Goal, PredId)),
+	solutions(P, PredIds).
 
 %-----------------------------------------------------------------------------%
Index: hlds_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_data.m,v
retrieving revision 1.63
diff -u -r1.63 hlds_data.m
--- hlds_data.m	16 Jan 2002 01:13:18 -0000	1.63
+++ hlds_data.m	19 Feb 2002 05:22:10 -0000
@@ -1038,3 +1038,86 @@
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
+
+:- interface.
+
+	% 
+	% A table recording exclusivity declarations (i.e. promise_exclusive
+	% and promise_exclusive_exhaustive). 
+	%
+	% e.g. :- all [X]
+	% 		promise_exclusive
+	% 		some [Y] (
+	% 			p(X, Y)
+	% 		;
+	% 			q(X)
+	% 		).
+	% 
+	% promises that only one of p(X, Y) and q(X) can succeed at a time,
+	% although whichever one succeeds may have multiple solutions. See
+	% notes/promise_ex.html for details of the declarations.
+	%
+
+	% an exclusive_id is the pred_id of an exclusivity declaration,
+	% and is useful in distinguishing between the arguments of the
+	% operations below on the exclusive_table
+:- type exclusive_id	==	pred_id.
+:- type exclusive_ids	==	list(pred_id).
+
+:- type exclusive_table.
+
+	% initialise the exclusive_table
+:- pred exclusive_table_init(exclusive_table).
+:- mode exclusive_table_init(out) is det.
+
+	% search the exclusive table and return the list of exclusivity
+	% declarations that use the predicate given by pred_id
+:- pred exclusive_table_search(exclusive_table, pred_id, exclusive_ids).
+:- mode exclusive_table_search(in, in, out) is semidet.
+
+	% as for search, but aborts if no exclusivity declarations are
+	% found
+:- pred exclusive_table_lookup(exclusive_table, pred_id, exclusive_ids).
+:- mode exclusive_table_lookup(in, in, out) is det.
+
+	% optimises the exclusive_table
+:- pred exclusive_table_optimize(exclusive_table, exclusive_table).
+:- mode exclusive_table_optimize(in, out) is det.
+
+	% add to the exclusive table that pred_id is used in the
+	% exclusivity declaration exclusive_id
+:- pred exclusive_table_add(pred_id, exclusive_id, exclusive_table,
+		exclusive_table).
+:- mode exclusive_table_add(in, in, in, out) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module multi_map.
+
+:- type exclusive_table		==	multi_map(pred_id, exclusive_id).
+
+exclusive_table_init(ExclusiveTable) :-
+	multi_map__init(ExclusiveTable).
+
+exclusive_table_lookup(ExclusiveTable, PredId, ExclusiveIds) :-
+	multi_map__lookup(ExclusiveTable, PredId, ExclusiveIds).
+
+exclusive_table_search(ExclusiveTable, Id, ExclusiveIds) :-
+	multi_map__search(ExclusiveTable, Id, ExclusiveIds).
+
+exclusive_table_optimize(ExclusiveTable0, ExclusiveTable) :-
+	multi_map__optimize(ExclusiveTable0, ExclusiveTable).
+
+exclusive_table_add(ExclusiveId, PredId, ExclusiveTable0, ExclusiveTable) :-
+	(
+		multi_map__contains(ExclusiveTable0, PredId)
+	->
+		multi_map__det_update(ExclusiveTable0, PredId, ExclusiveId, 
+				ExclusiveTable)
+	;
+		multi_map__det_insert(ExclusiveTable0, PredId, ExclusiveId, 
+				ExclusiveTable)
+	).
+
Index: hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.70
diff -u -r1.70 hlds_module.m
--- hlds_module.m	25 Jan 2002 08:22:48 -0000	1.70
+++ hlds_module.m	14 Feb 2002 01:24:10 -0000
@@ -195,6 +195,13 @@
 	module_info).
 :- mode module_info_set_assertion_table(in, in, out) is det.
 
+:- pred module_info_exclusive_table(module_info, exclusive_table).
+:- mode module_info_exclusive_table(in, out) is det.
+
+:- pred module_info_set_exclusive_table(module_info, exclusive_table, 
+	module_info).
+:- mode module_info_set_exclusive_table(in, in, out) is det.
+
 :- pred module_info_ctor_field_table(module_info, ctor_field_table).
 :- mode module_info_ctor_field_table(in, out) is det.
 
@@ -503,6 +510,7 @@
 		instance_table ::		instance_table,
 		superclass_table ::		superclass_table,
 		assertion_table ::		assertion_table,
+		exclusive_table ::		exclusive_table,
 		ctor_field_table ::		ctor_field_table,
 		cell_counter ::			counter,
 					% cell count, passed into code_info
@@ -595,6 +603,7 @@
 	set__init(IndirectlyImportedModules),
 
 	assertion_table_init(AssertionTable),
+	exclusive_table_init(ExclusiveTable),
 	map__init(FieldNameTable),
 
 	map__init(NoTagTypes),
@@ -605,7 +614,7 @@
 	ModuleInfo = module(ModuleSubInfo, PredicateTable, Requests,
 		UnifyPredMap, QualifierInfo, Types, Insts, Modes, Ctors,
 		ClassTable, SuperClassTable, InstanceTable, AssertionTable,
-		FieldNameTable, counter__init(1), RecompInfo).
+		ExclusiveTable, FieldNameTable, counter__init(1), RecompInfo).
 
 %-----------------------------------------------------------------------------%
 
@@ -623,6 +632,7 @@
 module_info_instances(MI, MI ^ instance_table).
 module_info_superclasses(MI, MI ^ superclass_table).
 module_info_assertion_table(MI, MI ^ assertion_table).
+module_info_exclusive_table(MI, MI ^ exclusive_table).
 module_info_ctor_field_table(MI, MI ^ ctor_field_table).
 module_info_get_cell_counter(MI, MI ^ cell_counter).
 module_info_get_maybe_recompilation_info(MI, MI ^ maybe_recompilation_info).
@@ -644,6 +654,7 @@
 module_info_set_instances(MI, I, MI ^ instance_table := I).
 module_info_set_superclasses(MI, S, MI ^ superclass_table := S).
 module_info_set_assertion_table(MI, A, MI ^ assertion_table := A).
+module_info_set_exclusive_table(MI, PXT, MI ^ exclusive_table := PXT).
 module_info_set_ctor_field_table(MI, CF, MI ^ ctor_field_table := CF).
 module_info_set_cell_counter(MI, CC, MI ^ cell_counter := CC).
 module_info_set_maybe_recompilation_info(MI, I,
Index: hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.272
diff -u -r1.272 hlds_out.m
--- hlds_out.m	16 Jan 2002 01:13:19 -0000	1.272
+++ hlds_out.m	19 Feb 2002 23:36:53 -0000
@@ -164,10 +164,10 @@
 :- mode hlds_out__write_clause(in, in, in, in, in, in, in, in, in, in, di, uo)
 	is det.
 
-:- pred hlds_out__write_assertion(int, module_info, pred_id, prog_varset, bool,
-		list(prog_var), pred_or_func, clause, maybe_vartypes,
-		io__state, io__state).
-:- mode hlds_out__write_assertion(in, in, in, in, in, in, in, in, in, di, uo)
+:- pred hlds_out__write_promise(promise_type, int, module_info, pred_id,
+		prog_varset, bool, list(prog_var), pred_or_func, clause,
+		maybe_vartypes, io__state, io__state).
+:- mode hlds_out__write_promise(in, in, in, in, in, in, in, in, in, in, di, uo)
 	is det.
 
 	% Print out an HLDS goal. The module_info and prog_varset give
@@ -368,9 +368,10 @@
 	->
 		io__write_string("type class method implementation")
 	;
-		{ pred_info_get_goal_type(PredInfo, assertion) }
+		{ pred_info_get_goal_type(PredInfo, promise(PromiseType)) }
 	->
-		io__write_string("promise")
+		io__write_string("`" ++ prog_out__promise_to_string(PromiseType)
+					++ "' declaration")
 	;
 		hlds_out__write_simple_call_id(PredOrFunc,
 			qualified(Module, Name), Arity)
@@ -389,12 +390,43 @@
 	hlds_out__write_simple_call_id(PredOrFunc, Name, Arity).
 
 hlds_out__write_simple_call_id(PredOrFunc, Name, Arity) -->
-	hlds_out__write_pred_or_func(PredOrFunc),
-	io__write_string(" `"),
-	{ hlds_out__simple_call_id_to_sym_name_and_arity(
-		PredOrFunc - Name/Arity, SymArity) },
-	prog_out__write_sym_name_and_arity(SymArity),
-	io__write_string("'").
+		% XXX when printed, promises are differentiated from 
+		%     predicates or functions by module name, so the module 
+		%     names `promise', `promise_exclusive', etc. should be 
+		%     reserved, and their dummy predicates should have more
+		%     unusual module names
+	(
+		{ Name = unqualified(StrName) }
+	;
+		{ Name = qualified(_, StrName) }
+	),
+		% is it really a promise?
+	( { string__prefix(StrName, "promise__") } ->
+		{ Promise = promise(true) }
+	; { string__prefix(StrName, "promise_exclusive__") } ->
+		{ Promise = promise(exclusive) }
+	; { string__prefix(StrName, "promise_exhaustive__") } ->
+		{ Promise = promise(exhaustive) }
+	; { string__prefix(StrName, "promise_exclusive_exhaustive__") } ->
+		{ Promise = promise(exclusive_exhaustive) }
+	;
+		{ Promise = none }	% no, it is really a pred or func
+	),
+
+	(
+		{ Promise = promise(PromiseType) }
+	->
+		io__write_string("`"),
+		prog_out__write_promise_type(PromiseType),
+		io__write_string("' declaration")
+	;
+		hlds_out__write_pred_or_func(PredOrFunc),
+		io__write_string(" `"),
+		{ hlds_out__simple_call_id_to_sym_name_and_arity(
+			PredOrFunc - Name/Arity, SymArity) },
+		prog_out__write_sym_name_and_arity(SymArity),
+		io__write_string("'")
+	).
 
 :- pred hlds_out__simple_call_id_to_sym_name_and_arity(simple_call_id,
 		sym_name_and_arity).
@@ -913,8 +945,8 @@
 	{ hlds_out__marker_name(Marker, Name) },
 	io__write_string(Name).
 
-hlds_out__write_assertion(Indent, ModuleInfo, _PredId, VarSet, AppendVarnums,
-		HeadVars, _PredOrFunc, Clause, TypeQual) -->
+hlds_out__write_promise(PromiseType, Indent, ModuleInfo, _PredId, VarSet, 
+		AppendVarnums, HeadVars, _PredOrFunc, Clause, TypeQual) -->
 
 		% curry the varset for term_io__write_variable/4
 	{ PrintVar = lambda([VarName::in, IO0::di, IO::uo] is det,
@@ -922,14 +954,25 @@
 		) },
 
 	hlds_out__write_indent(Indent),
-	io__write_string(":- promise all["),
-	io__write_list(HeadVars, ", ", PrintVar),
-	io__write_string("] (\n"),
 
+		% print initial formatting differently for assertions
+	( { PromiseType = true } ->
+		io__write_string(":- promise all ["),
+		io__write_list(HeadVars, ", ", PrintVar),
+		io__write_string("] (\n")
+	;
+		io__write_string(":- all ["),
+		io__write_list(HeadVars, ", ", PrintVar),
+		io__write_string("]"),
+		mercury_output_newline(Indent),
+		prog_out__write_promise_type(PromiseType),
+		mercury_output_newline(Indent),
+		io__write_string("(\n")
+	),
+	
 	{ Clause = clause(_Modes, Goal, _Lang, _Context) },
 	hlds_out__write_goal_a(Goal, ModuleInfo, VarSet, AppendVarnums,
 			Indent+1, ").\n", TypeQual).
-
 
 
 hlds_out__write_clauses(Indent, ModuleInfo, PredId, VarSet, AppendVarnums,
Index: hlds_pred.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.101
diff -u -r1.101 hlds_pred.m
--- hlds_pred.m	24 Aug 2001 15:44:47 -0000	1.101
+++ hlds_pred.m	13 Feb 2002 05:11:52 -0000
@@ -239,7 +239,7 @@
 			;	clauses		
 			;	clauses_and_pragmas 
 						% both clauses and pragmas
-			;	(assertion)
+			;	promise(promise_type)
 			;	none.
 
 	% Note: `liveness' and `liveness_info' record liveness in the sense
Index: intermod.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/intermod.m,v
retrieving revision 1.111
diff -u -r1.111 intermod.m
--- intermod.m	16 Jan 2002 01:13:22 -0000	1.111
+++ intermod.m	14 Feb 2002 02:28:07 -0000
@@ -366,9 +366,9 @@
 			clause_list_is_deforestable(PredId, Clauses)
 		)
 	;
-		% assertions that are in the interface should always get
+		% promises that are in the interface should always get
 		% included in the .opt file.
-		pred_info_get_goal_type(PredInfo, assertion)
+		pred_info_get_goal_type(PredInfo, promise(_))
 	).
 
 :- pred intermod__traverse_clauses(list(clause)::in, list(clause)::out,
@@ -1371,7 +1371,7 @@
 		GoalType = clauses,
 		AppendVarNums = yes
 	;
-		GoalType = (assertion),
+		GoalType = promise(_),
 		AppendVarNums = yes
 	;
 		GoalType = none,
@@ -1458,14 +1458,14 @@
 	{ clauses_info_clauses(ClausesInfo, Clauses) },
 
 	(
-		{ pred_info_get_goal_type(PredInfo, assertion) }
+		{ pred_info_get_goal_type(PredInfo, promise(PromiseType)) }
 	->
 		(
 			{ Clauses = [Clause] }
 		->
-			hlds_out__write_assertion(0, ModuleInfo, PredId,
-					VarSet, no, HeadVars, PredOrFunc,
-					Clause, no)
+			hlds_out__write_promise(PromiseType, 0, ModuleInfo, 
+					PredId, VarSet, no, HeadVars, 
+					PredOrFunc, Clause, no)
 		;
 			{ error("intermod__write_preds: assertion not a single clause.") }
 		)
Index: make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.399
diff -u -r1.399 make_hlds.m
--- make_hlds.m	8 Feb 2002 02:26:45 -0000	1.399
+++ make_hlds.m	19 Feb 2002 04:52:05 -0000
@@ -692,9 +692,10 @@
 add_item_clause(clause(VarSet, PredOrFunc, PredName, Args, Body),
 		Status, Status, Context, Module0, Module, Info0, Info) -->
 	check_not_exported(Status, Context, "clause"),
-	{ IsAssertion = no },
+	{ GoalType = none }, 	% at this stage we only need know that it's not
+				% a promise declaration
 	module_add_clause(Module0, VarSet, PredOrFunc, PredName,
-		Args, Body, Status, Context, IsAssertion, Module, Info0, Info).
+		Args, Body, Status, Context, GoalType, Module, Info0, Info).
 add_item_clause(type_defn(_, _, _, _, _), Status, Status, _,
 				Module, Module, Info, Info) --> [].
 add_item_clause(inst_defn(_, _, _, _, _), Status, Status, _,
@@ -801,43 +802,54 @@
 	
 add_item_clause(promise(PromiseType, Goal, VarSet, UnivVars),
 		Status, Status, Context, Module0, Module, Info0, Info) -->
-	( { PromiseType = true } ->	% promise is an assertion
+	%
+	% If the outermost universally quantified variables
+	% are placed in the head of the dummy predicate, the
+	% typechecker will avoid warning about unbound
+	% type variables as this implicity adds a universal
+	% quantification of the typevariables needed.
+	%
+	{ term__var_list_to_term_list(UnivVars, HeadVars) },
+	
+	% extra error checking for promise ex declarations
+	( { PromiseType \= true } ->
+		check_promise_ex_decl(UnivVars, PromiseType, Goal, Context)
+	;
+		[]
+	),
 
-		%
-		% If the outermost existentially quantified variables
-		% are placed in the head of the assertion, the
-		% typechecker will avoid warning about unbound
-		% type variables as this implicity adds a universal
-		% quantification of the typevariables needed.
-		%
-		{ term__var_list_to_term_list(UnivVars, HeadVars) },
+	% add as dummy predicate
+	add_promise_clause(PromiseType, HeadVars, VarSet, Goal, Context, Status,
+			Module0, Module, Info0, Info).
+
+:- pred add_promise_clause(promise_type, list(term(prog_var_type)), prog_varset,
+		goal, prog_context, import_status, module_info, module_info, 
+		qual_info, qual_info, io__state, io__state). 
+:- mode add_promise_clause(in, in, in, in, in, in, in, out, in, out, 
+		di, uo) is det.
+add_promise_clause(PromiseType, HeadVars, VarSet, Goal, Context, Status,
+		Module0, Module, Info0, Info) -->
 	{ term__context_line(Context, Line) },
 	{ term__context_file(Context, File) },
-		{ string__format("assertion__%d__%s", [i(Line), s(File)],Name)},
-
+	{ string__format(prog_out__promise_to_string(PromiseType) ++
+			"__%d__%s", [i(Line), s(File)], Name) },
 		%
-		% The assertions are recorded as a predicate whose
-		% goal_type is set to assertion.  This allows us to
-		% leverage off all the other checks in the compiler that
-		% operate on predicates.
+		% Promise declarations are recorded as a predicate with a
+		% goal_type of promise(X), where X is of promise_type. This 
+		% allows us to leverage off all the other checks in the 
+		% compiler that operate on predicates.
 		%
 		% :- promise all [A,B,R] ( R = A + B <=> R = B + A ).
 		%
 		% becomes
 		%
-		% assertion__lineno_filename(A, B, R) :-
+		% promise__lineno_filename(A, B, R) :-
 		% 	( R = A + B <=> R = B + A ).
 		%
-	{ IsAssertion = yes },
+	{ GoalType = promise(PromiseType) },
 	module_add_clause(Module0, VarSet, predicate, unqualified(Name),
-				HeadVars, Goal, Status, Context, IsAssertion, 
-				Module, Info0, Info)
-	;
-			% promise is a promise ex declaration,
-			% not yet implemented
-		{ Module0 = Module },
-		{ Info0 = Info }
-	).
+			HeadVars, Goal, Status, Context, GoalType, 
+			Module, Info0, Info).
 
 add_item_clause(nothing(_), Status, Status, _,
 	Module, Module, Info, Info) --> [].
@@ -3583,13 +3595,13 @@
 %-----------------------------------------------------------------------------%
 
 :- pred module_add_clause(module_info, prog_varset, pred_or_func, sym_name,
-		list(prog_term), goal, import_status, prog_context, bool,
+		list(prog_term), goal, import_status, prog_context, goal_type,
 		module_info, qual_info, qual_info, io__state, io__state).
 :- mode module_add_clause(in, in, in, in, in, in, in, in, in,
 		out, in, out, di, uo) is det.
 
 module_add_clause(ModuleInfo0, ClauseVarSet, PredOrFunc, PredName, Args, Body,
-			Status, Context, IsAssertion, ModuleInfo,
+			Status, Context, GoalType, ModuleInfo,
 			Info0, Info) -->
 	globals__io_lookup_bool_option(very_verbose, VeryVerbose),
 	( { VeryVerbose = yes } ->
@@ -3617,7 +3629,7 @@
 		{ PredId = PredId0 },
 		{ ModuleInfo1 = ModuleInfo0 },
 		(
-			{ IsAssertion = yes }
+			{ GoalType = promise(_) }
 		->
 			{ prog_out__sym_name_to_string(PredName, NameString) },
 			{ string__format("%s %s %s (%s).\n",
@@ -3630,10 +3642,11 @@
 			[]
 		)
 	;
-		(
-				% An assertion will not have a
+				% A promise will not have a
 				% corresponding pred declaration.
-			{ IsAssertion = yes },
+		(
+			{ GoalType = promise(_) }
+		->
 			{ term__term_list_to_var_list(Args, HeadVars) },
 			{ preds_add_implicit_for_assertion(HeadVars,
 					ModuleInfo0, PredicateTable0,
@@ -3643,8 +3656,6 @@
 			{ module_info_set_predicate_table(ModuleInfo0,
 					PredicateTable1, ModuleInfo1) }
 		;
-			{ IsAssertion = no },
-
 			preds_add_implicit_report_error(ModuleName,
 				PredOrFunc, PredName, Arity, Status, no,
 				Context, "clause", PredId,
@@ -3745,15 +3756,16 @@
 			ArgTerms, ProcIdsForThisClause, ModuleInfo2, Info1),
 		clauses_info_add_clause(Clauses0, ProcIdsForThisClause,
 			ClauseVarSet, TVarSet0, ArgTerms, Body, Context,
-			Status, PredOrFunc, Arity, IsAssertion, Goal,
+			Status, PredOrFunc, Arity, GoalType, Goal,
 			VarSet, TVarSet, Clauses, Warnings,
 			ModuleInfo2, ModuleInfo3, Info1, Info),
 		{
 		pred_info_set_clauses_info(PredInfo2, Clauses, PredInfo3),
 		(
-			IsAssertion = yes
+			GoalType = promise(PromiseType)
 		->
-			pred_info_set_goal_type(PredInfo3, assertion, PredInfo4)
+			pred_info_set_goal_type(PredInfo3, promise(PromiseType),
+					PredInfo4)
 		;
 			pred_info_set_goal_type(PredInfo3, clauses, PredInfo4)
 		),
@@ -4004,10 +4016,10 @@
 
 		{ ProcIds = [] }, % means this clause applies to _every_
 				  % mode of the procedure
-		{ IsAssertion = no },
+		{ GoalType = none },	% goal is not a promise
 		clauses_info_add_clause(ClausesInfo0, ProcIds,
 			CVarSet, TVarSet0, HeadTerms, Body, Context, Status,
-			PredOrFunc, Arity, IsAssertion, Goal,
+			PredOrFunc, Arity, GoalType, Goal,
 			VarSet, _TVarSet, ClausesInfo, Warnings,
 			ModuleInfo0, ModuleInfo, QualInfo0, QualInfo),
 
@@ -5273,14 +5285,14 @@
 :- pred clauses_info_add_clause(clauses_info::in,
 		list(proc_id)::in, prog_varset::in, tvarset::in,
 		list(prog_term)::in, goal::in, prog_context::in,
-		import_status::in, pred_or_func::in, arity::in, bool::in,
+		import_status::in, pred_or_func::in, arity::in, goal_type::in,
 		hlds_goal::out, prog_varset::out, tvarset::out,
 		clauses_info::out, list(quant_warning)::out, 
 		module_info::in, module_info::out, qual_info::in,
 		qual_info::out, io__state::di, io__state::uo) is det.
 
 clauses_info_add_clause(ClausesInfo0, ModeIds0, CVarSet, TVarSet0,
-		Args, Body, Context, Status, PredOrFunc, Arity, IsAssertion,
+		Args, Body, Context, Status, PredOrFunc, Arity, GoalType,
 		Goal, VarSet, TVarSet, ClausesInfo, Warnings, Module0, Module,
 		Info0, Info) -->
 	{ ClausesInfo0 = clauses_info(VarSet0, ExplicitVarTypes0, TVarNameMap0,
@@ -5302,7 +5314,7 @@
 			ExplicitVarTypes0, Status, Info1) },
 	{ varset__merge_subst(VarSet0, CVarSet, VarSet1, Subst) },
 	transform(Subst, HeadVars, Args, Body, VarSet1, Context, PredOrFunc,
-			Arity, IsAssertion, Goal0, VarSet, Warnings,
+			Arity, GoalType, Goal0, VarSet, Warnings,
 			transform_info(Module0, Info1),
 			transform_info(Module, Info2)),
 	{ TVarSet = Info2 ^ tvarset },
@@ -5580,7 +5592,7 @@
 	).
 
 :- pred transform(prog_substitution, list(prog_var), list(prog_term), goal,
-		prog_varset, prog_context, pred_or_func, arity, bool,
+		prog_varset, prog_context, pred_or_func, arity, goal_type,
 		hlds_goal, prog_varset, list(quant_warning),
 		transform_info, transform_info,
 		io__state, io__state).
@@ -5588,14 +5600,14 @@
 		in, out, di, uo) is det.
 
 transform(Subst, HeadVars, Args0, Body, VarSet0, Context, PredOrFunc,
-		Arity, IsAssertion, Goal, VarSet, Warnings, Info0, Info) -->
+		Arity, GoalType, Goal, VarSet, Warnings, Info0, Info) -->
 	transform_goal(Body, VarSet0, Subst, Goal1, VarSet1, Info0, Info1),
 	{ term__apply_substitution_to_list(Args0, Subst, Args) },
 		
 		% The head variables of an assertion will always be
 		% variables, so it is unnecessary to insert unifications.
 	(
-		{ IsAssertion = yes }
+		{ GoalType = promise(_) }
 	->
 		{ VarSet2 = VarSet1 },
 		{ Goal2 = Goal1 },
@@ -8413,4 +8425,133 @@
 		PragmaVars0 = []
 	).
 
+
 %-----------------------------------------------------------------------------%
+%
+% promise ex error checking
+%
+% The following predicates are used to perform extra error checking specific
+% to promise ex declarations (see notes/promise_ex.html). Currently, the 
+% following checks are performed:
+% 	* check for universally quantified variables
+% 	* check if universal quantification is placed in the wrong
+% 	  position (i.e. after the `promise_exclusive' rather than 
+% 	  before it)
+% 	* check that its goal is a disjunction and that each arm of the 
+% 	  disjunction has at most one call, and otherwise has only unifications
+
+	% perform above checks on a promise ex declaration
+:- pred check_promise_ex_decl(prog_vars, promise_type, goal, prog_context, 
+		io__state, io__state).
+:- mode check_promise_ex_decl(in, in, in, in, di, uo) is det.
+check_promise_ex_decl(UnivVars, PromiseType, Goal, Context) -->
+		% are universally quantified variables present?
+	(
+		{ UnivVars = [] },
+		promise_ex_error(PromiseType, Context, "declaration has no universally quantified variables")
+	;
+		{ UnivVars = [_ | _] }
+	),
+	check_promise_ex_goal(PromiseType, Goal).
+
+	% check for misplaced universal quantification, otherwise find the
+	% disjunction, flatten it out into list form and perform further
+	% checks
+:- pred check_promise_ex_goal(promise_type, goal, io__state, io__state).
+:- mode check_promise_ex_goal(in, in, di, uo) is det.
+check_promise_ex_goal(PromiseType, GoalExpr - Context) -->
+	( { GoalExpr = some(_, Goal) } ->
+		check_promise_ex_goal(PromiseType, Goal)
+	; { GoalExpr =  ( _ ; _ ) } ->
+		{ flatten_to_disj_list(GoalExpr - Context, DisjList) },
+		{ list__map(flatten_to_conj_list, DisjList, DisjConsList) },
+		check_disjunction(PromiseType, DisjConsList)
+	; { GoalExpr = all(_UnivVars, Goal) } ->
+		promise_ex_error(PromiseType, Context, "universal quantification should come before the declaration name"),
+		check_promise_ex_goal(PromiseType, Goal)
+	;
+		promise_ex_error(PromiseType, Context, "goal in declaration is not a disjunction")
+	).
+
+	% turns the goal of a promise ex declaration into a list of goals,
+	% where each goal is an arm of the disjunction
+:- pred flatten_to_disj_list(goal, goals).
+:- mode flatten_to_disj_list(in, out) is det.
+flatten_to_disj_list(GoalExpr - Context, GoalList) :-
+	( GoalExpr = ( GoalA ; GoalB ) ->
+		flatten_to_disj_list(GoalA, GoalListA),
+		flatten_to_disj_list(GoalB, GoalListB),
+		GoalList = GoalListA ++ GoalListB
+	;
+		GoalList = [GoalExpr - Context]
+	).
+
+	% takes a goal representing an arm of a disjunction and turn it into
+	% a list of conjunct goals
+:- pred flatten_to_conj_list(goal, goals).
+:- mode flatten_to_conj_list(in, out) is det.
+flatten_to_conj_list(GoalExpr - Context, GoalList) :-
+	( GoalExpr = ( GoalA , GoalB ) ->
+		flatten_to_conj_list(GoalA, GoalListA),
+		flatten_to_conj_list(GoalB, GoalListB),
+		GoalList = GoalListA ++ GoalListB
+	;
+		GoalList = [GoalExpr - Context]
+	).
+
+	% taking a list of arms of the disjunction, check each arm
+	% individually
+:- pred check_disjunction(promise_type, list(goals), io__state, io__state).
+:- mode check_disjunction(in, in, di, uo) is det.
+check_disjunction(PromiseType, DisjConsList) -->
+	(
+		{ DisjConsList = [] }
+	;
+		{ DisjConsList = [ConsList | Rest] },
+		check_disj_arm(PromiseType, ConsList, no),
+		check_disjunction(PromiseType, Rest)
+	).
+
+	% only one goal in an arm is allowed to be a call, the rest must be 
+	% unifications
+:- pred check_disj_arm(promise_type, goals, bool, io__state, io__state).
+:- mode check_disj_arm(in, in, in, di, uo) is det.
+check_disj_arm(PromiseType, Goals, CallUsed) -->
+	(
+		{ Goals = [] }
+	;
+		{ Goals = [GoalExpr - Context | Rest] },
+		( { GoalExpr = unify(_, _, _) } ->
+			check_disj_arm(PromiseType, Rest, CallUsed)
+		; { GoalExpr = some(_, Goal) } ->
+			check_disj_arm(PromiseType, [Goal | Rest], CallUsed)
+		; { GoalExpr = call(_, _, _) } ->
+			(
+				{ CallUsed = no }
+			;
+				{ CallUsed = yes },
+				promise_ex_error(PromiseType, Context, "disjunct contains more than one call")
+			),
+			check_disj_arm(PromiseType, Rest, yes)
+		;
+			promise_ex_error(PromiseType, Context, "disjunct is not a call or unification"),
+			check_disj_arm(PromiseType, Rest, CallUsed)
+		)
+	).
+
+
+	% called for any error in the above checks
+:- pred promise_ex_error(promise_type, prog_context, string, 
+		io__state, io__state).
+:- mode promise_ex_error(in, in, in, di, uo) is det.
+promise_ex_error(PromiseType, Context, Message) -->
+	{ ErrorPieces = [
+		words("In"),
+		fixed("`" ++ prog_out__promise_to_string(PromiseType) ++ "' declaration:"),
+		nl,
+		words("error:"),
+		words(Message)
+		] },
+	error_util__write_error_pieces(Context, 0, ErrorPieces).
+
+%------------------------------------------------------------------------------%
Index: post_typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/post_typecheck.m,v
retrieving revision 1.34
diff -u -r1.34 post_typecheck.m
--- post_typecheck.m	2 Oct 2001 13:53:56 -0000	1.34
+++ post_typecheck.m	19 Feb 2002 01:29:11 -0000
@@ -124,9 +124,9 @@
 	% Now that the assertion has finished being typechecked,
 	% remove it from further processing and store it in the
 	% assertion_table.
-:- pred post_typecheck__finish_assertion(module_info, pred_id,
+:- pred post_typecheck__finish_promise(promise_type, module_info, pred_id,
 		module_info, io__state, io__state) is det.
-:- mode post_typecheck__finish_assertion(in, in, out, di, uo) is det.
+:- mode post_typecheck__finish_promise(in, in, in, out, di, uo) is det.
 
 %-----------------------------------------------------------------------------%
 
@@ -134,7 +134,7 @@
 
 :- import_module (assertion), code_util, typecheck, clause_to_proc.
 :- import_module mode_util, inst_match, (inst), prog_util, error_util.
-:- import_module mercury_to_mercury, prog_out, hlds_out, type_util.
+:- import_module mercury_to_mercury, prog_out, hlds_out, type_util, goal_util.
 :- import_module globals, options.
 
 :- import_module map, set, assoc_list, term, require, int.
@@ -691,42 +691,92 @@
 		Errors, PredInfo1, PredInfo).
 
 	%
-	% Now that the assertion has finished being typechecked,
+	% Now that the promise has finished being typechecked,
 	% and has had all of its pred_ids identified,
-	% remove the assertion from the list of pred ids to be processed
+	% remove the promise from the list of pred ids to be processed
 	% in the future and place the pred_id associated with the
-	% assertion into the assertion table.
+	% promise into the assertion or promise_ex table.
 	% For each assertion that is in the interface, you need to check
 	% that it doesn't refer to any symbols which are local to that
 	% module.
 	% Also record for each predicate that is used in an assertion
-	% which assertion it is used in.
-	% 
-post_typecheck__finish_assertion(Module0, PredId, Module) -->
-		% store into assertion table.
-	{ module_info_assertion_table(Module0, AssertTable0) },
-	{ assertion_table_add_assertion(PredId,
-			AssertTable0, AssertionId, AssertTable) },
-	{ module_info_set_assertion_table(Module0, AssertTable, Module1) },
-		
+	% which assertion it is used in, or for a promise ex declaration
+	% record in the promise ex table the predicates used by the
+	% declaration.
+	%
+post_typecheck__finish_promise(PromiseType, Module0, PromiseId, Module) -->
+		% Store the declaration in the appropriate table and get
+		% the goal for the promise
+	{ store_promise(PromiseType, Module0, PromiseId, Module1, Goal) },
+			
 		% Remove from further processing.
-	{ module_info_remove_predid(Module1, PredId, Module2) },
+	{ module_info_remove_predid(Module1, PromiseId, Module2) },
 
-		% If the assertion is in the interface, then ensure that
+		% If the promise is in the interface, then ensure that
 		% it doesn't refer to any local symbols.
-	{ module_info_pred_info(Module2, PredId, PredInfo) },
-	{ assertion__goal(AssertionId, Module2, Goal) },
-	(
-		{ pred_info_is_exported(PredInfo) }
+	{ module_info_pred_info(Module2, PromiseId, PredInfo) },
+	( { pred_info_is_exported(PredInfo) } ->
+		assertion__in_interface_check(Goal, PredInfo, 
+				Module2, Module)
+	;
+		{ Module2 = Module }
+	).
+
+	% store promise declaration, normalise goal and return new
+	% module_info and the goal for further processing
+:- pred store_promise(promise_type, module_info, pred_id, module_info, 
+		hlds_goal).
+:- mode store_promise(in, in, in, out, out) is det.
+store_promise(PromiseType, Module0, PromiseId, Module, Goal) :-
+	( 
+		% case for assertions
+		PromiseType = true
 	->
-		assertion__in_interface_check(Goal, PredInfo, Module2, Module3)
+		module_info_assertion_table(Module0, AssertTable0),
+		assertion_table_add_assertion(PromiseId, AssertTable0, 
+				AssertionId, AssertTable),
+		module_info_set_assertion_table(Module0, AssertTable, 
+				Module1),
+		assertion__goal(AssertionId, Module1, Goal),
+		assertion__record_preds_used_in(Goal, AssertionId, Module1,
+				Module)
 	;
-		{ Module3 = Module2 }
-	),
+		% case for exclusivity
+		(
+			PromiseType = exclusive
+		;
+			PromiseType = exclusive_exhaustive
+		)
+	->
+		promise_ex_goal(PromiseId, Module0, Goal),
+		predids_from_goal(Goal, PredIds),
+		module_info_exclusive_table(Module0, Table0),
+		list__foldl(exclusive_table_add(PromiseId), PredIds, Table0,
+				Table),
+		module_info_set_exclusive_table(Module0, Table, Module)
+
+	;
+		% case for exhaustiveness -- XXX not yet implemented
+		promise_ex_goal(PromiseId, Module0, Goal),
+		Module0 = Module
+	).
+
+	% get the goal from a promise_ex declaration
+:- pred promise_ex_goal(pred_id, module_info, hlds_goal).
+:- mode promise_ex_goal(in, in, out) is det.
+promise_ex_goal(ExclusiveDecl, Module, Goal) :-
+        module_info_pred_info(Module, ExclusiveDecl, PredInfo),
+        pred_info_clauses_info(PredInfo, ClausesInfo),
+        clauses_info_clauses(ClausesInfo, Clauses),
+        (
+		Clauses = [clause(_ProcIds, Goal0, _Lang, _Context)]
+	->
+		assertion__normalise_goal(Goal0, Goal)
+	;
+		error("promise_ex__goal: not an promise")
+	).
+
 
-		% record which predicates are used in assertions
-	{ assertion__record_preds_used_in(Goal, AssertionId, Module3, Module) }.
-	
 %-----------------------------------------------------------------------------%
 
 :- pred check_type_of_main(pred_info, io__state, io__state).
Index: purity.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.41
diff -u -r1.41 purity.m
--- purity.m	30 Jan 2002 01:40:30 -0000	1.41
+++ purity.m	14 Feb 2002 05:41:55 -0000
@@ -392,10 +392,10 @@
 	{ module_info_set_predicate_table(ModuleInfo0, PredTable,
 					  ModuleInfo1) },
 
-	(
-		{ pred_info_get_goal_type(PredInfo0, assertion) }
-	->
-		post_typecheck__finish_assertion(ModuleInfo1,
+		% finish processing of promise declarations
+	{ pred_info_get_goal_type(PredInfo0, GoalType) },
+	( { GoalType = promise(PromiseType) } ->
+		post_typecheck__finish_promise(PromiseType, ModuleInfo1,
 				PredId, ModuleInfo2)
 	;
 		{ ModuleInfo2 = ModuleInfo1 }
Index: typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.310
diff -u -r1.310 typecheck.m
--- typecheck.m	12 Feb 2002 05:14:07 -0000	1.310
+++ typecheck.m	13 Feb 2002 05:11:52 -0000
@@ -4565,7 +4565,7 @@
 		{ check_marker(Markers, infer_type) },
 		{ module_info_predids(ModuleInfo, ValidPredIds) },
 		{ list__member(PredId, ValidPredIds) },
-		{ \+ pred_info_get_goal_type(PredInfo, assertion) }
+		{ \+ pred_info_get_goal_type(PredInfo, promise(_)) }
 	->
 		write_inference_message(PredInfo)
 	;
--------------------------------------------------------------------------
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