For review: Make Mercury cope with impure code (part 1/2)

Peter Schachte pets at cs.mu.oz.au
Fri Nov 14 19:32:47 AEDT 1997


================ begin part 1/2 ================
Make Mercury cope with impure code

The purpose of this diff is to allow Mercury programs to contain
impure Mercury code without the compiler changing its behavior
inappropriately, while still allowing the compiler to aggressively
optimize pure code.  To do this, we require impure predicates to be so
declared, and calls to impure predicates to be flagged as such.  We
also allow predicates implemented in terms of impure predicates to be
promised to be pure; lacking such a promise, any predicate that calls
an impure predicate is assumed to be impure.

At the moment, we don't allow impure functions (only predicates),
though some of the work necessary to support them has been done.

Note that to make the operators work properly, the precedence of the
`pred' and `func' operators has been changed from 1199 to 800.

Estimated hours taken: 120

compiler/purity.m
	New compiler pass for purity checking.
compiler/hlds_goal.m:
	Add `impure' and `semipure' to the goal_feature enum
compiler/hlds_out.m:
compiler/typecheck.m:
compiler/special_pred.m:
	Fixed code that prints predicate name to write something more
	helpful for special (compiler-generated) predicates.  Added
	code to print new markers.  Added purity argument to
	mercury_output_pred_type.  New public predicate
	special_pred_description/2 provides an english description for
	each compiler-generated predicate.
compiler/hlds_pred.m:
	Add `impure' and `semipure' to marker enum.  Added new
	public predicates to get predicate purity and whether or not
	it's promised to be pure.
compiler/prog_data.m:
compiler/mercury_to_mercury.m:
compiler/prog_io.m:
compiler/prog_io_goal.m:
compiler/prog_io_pragma.m:
compiler/prog_io_dcg.m:
compiler/prog_util.m:
compiler/equiv_type.m:
compiler/intermod.m:
compiler/mercury_to_c.m:
compiler/module_qual.m:
	Add purity argument to pred and func items.  Add new `impure'
	and `semipure' operators.  Add promise_pure pragma.  Add
	purity/2 wrapper to goal_expr type.
compiler/make_hlds.m:
compiler/mercury_to_goedel.m:
	Added purity argument to module_add_{pred,func},
	clauses_info_add_pragma_c_code, and to pred and func items.
	Handle promise_pure pragma.  Handle purity/2 wrapper used to
	handle user-written impurity annotations on goals.
compiler/mercury_compile.m:
	Add purity checking pass between type and mode checking.
compiler/mode_errors.m:
	Distinguish mode errors caused by impure goals preventing
	goals being delayed.
compiler/modes.m:
	Don't delay impure goals, and ensure before scheduling an
	impure goal that no goals are delayed.  Actually, we go ahead
	and try to schedule goals even if impurity causes a problem,
	and then if it still doesn't mode check, then we report an
	ordinary mode error.  Only if the clause would be mode correct
	except for an impure goal do we report it as an impurity problem.
compiler/simplify.m:
	Don't optimize away non-pure duplicate calls.  We could do
	better and still optimize duplicate semipure goals without an
	intervening impure goal, but it's probably not worth the
	trouble.  Also don't eliminate impure goals on a failing branch.
compiler/notes/compiler_design.html:
	Documented purity checking pass.
doc/reference_manual.texi:
	Document purity system.
doc/transition_guide.texi:
library/nc_builtin.nl:
library/ops.m:
library/sp_builtin.nl:
	New operators and new precdence for `pred' and `func'
	operators.
compiler/.cvsignore
profiler/.cvsignore
tests/hard_coded/.cvsignore
library/.cvsignore:
tests/valid/.cvsignore
	Ignore *.opt *.optdate *.date3 *.int3
tests/hard_coded/purity.m
tests/hard_coded/purity.exp
tests/hard_coded/Mmakefile:
tests/invalid/purity.m
tests/invalid/purity_nonsense.m
tests/invalid/purity.err_exp
tests/invalid/purity_nonsense.err_exp
tests/invalid/Mmakefile:
	Test cases for purity.



Index: compiler/.cvsignore
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/.cvsignore,v
retrieving revision 1.4
diff -u -r1.4 .cvsignore
--- .cvsignore	1996/03/26 16:44:43	1.4
+++ .cvsignore	1997/11/14 01:26:00
@@ -2,6 +2,10 @@
 *.ql
 *.pl
 *.prof
+*.date3
+*.int3
+*.opt
+*.optdate
 mercury_compile.m optimize.m code_gen.m
 conf.m
 mercury_compile.stats
Index: compiler/equiv_type.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/equiv_type.m,v
retrieving revision 1.9
diff -u -r1.9 equiv_type.m
--- equiv_type.m	1997/08/22 13:54:55	1.9
+++ equiv_type.m	1997/09/02 04:36:22
@@ -112,17 +112,20 @@
 	equiv_type__replace_in_type_defn(TypeDefn0, VarSet0, EqvMap,
 				TypeDefn, VarSet, ContainsCirc).
 
-equiv_type__replace_in_item(pred(VarSet0, PredName, TypesAndModes0, Det, Cond),
-		EqvMap, pred(VarSet, PredName, TypesAndModes, Det, Cond), no) :-
+equiv_type__replace_in_item(
+		pred(VarSet0, PredName, TypesAndModes0, Det, Cond, Purity),
+		EqvMap,
+		pred(VarSet, PredName, TypesAndModes, Det, Cond, Purity),
+		no) :-
 	equiv_type__replace_in_tms(TypesAndModes0, VarSet0, EqvMap, 
 					TypesAndModes, VarSet).
 
 equiv_type__replace_in_item(
 			func(VarSet0, PredName, TypesAndModes0, 
-				RetTypeAndMode0, Det, Cond),
+				RetTypeAndMode0, Det, Cond, Purity),
 			EqvMap,
 			func(VarSet, PredName, TypesAndModes, RetTypeAndMode,
-				Det, Cond),
+				Det, Cond, Purity),
 			no) :-
 	equiv_type__replace_in_tms(TypesAndModes0, VarSet0, EqvMap,
 				TypesAndModes, VarSet1),
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_goal.m,v
retrieving revision 1.42
diff -u -r1.42 hlds_goal.m
--- hlds_goal.m	1997/10/13 08:09:41	1.42
+++ hlds_goal.m	1997/11/14 00:32:04
@@ -365,9 +365,11 @@
 :- type hlds_goal_info.
 
 :- type goal_feature
-	--->	constraint.	% This is included if the goal is
+	--->	constraint	% This is included if the goal is
 				% a constraint.  See constraint.m
 				% for the definition of this.
+	    ;	(impure)	% This goal is impure.  See hlds_pred.m.
+	    ;	(semipure).	% This goal is semipure.  See hlds_pred.m.
 
 	% see notes/ALLOCATION for what these alternatives mean
 :- type resume_point	--->	resume_point(set(var), resume_locs)
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_out.m,v
retrieving revision 1.174
diff -u -r1.174 hlds_out.m
--- hlds_out.m	1997/10/13 08:09:43	1.174
+++ hlds_out.m	1997/11/14 08:22:42
@@ -174,7 +174,7 @@
 
 :- implementation.
 
-:- import_module mercury_to_mercury, globals, options.
+:- import_module mercury_to_mercury, globals, options, purity, special_pred.
 :- import_module llds_out, prog_out, prog_util, (inst), instmap, trace.
 
 :- import_module bool, int, string, list, set, map, std_util, assoc_list.
@@ -238,16 +238,21 @@
 	{ pred_info_name(PredInfo, Name) },
 	{ pred_info_arity(PredInfo, Arity) },
 	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
-	hlds_out__write_pred_or_func(PredOrFunc),
-	io__write_string(" `"),
-	io__write_string(Module),
-	io__write_string(":"),
-	( { string__append("__", _, Name) } ->
+	(   { special_pred_name_arity(Kind, _, Name, Arity) } ->	
+		{ special_pred_description(Kind, Descr) },
+		io__write_string(Descr),
+		io__write_string(" for type "),
 		{ pred_info_arg_types(PredInfo, TVarSet, ArgTypes) },
-		{ term__context_init(Context) },
-		mercury_output_term(term__functor(term__atom(Name),
-				ArgTypes, Context), TVarSet, no)
+		(   { special_pred_get_type(Name, ArgTypes, Type) } ->
+			mercury_output_term(Type, TVarSet, no)
+		;
+			{ error("special_pred_get_type failed!") }
+		)
 	;
+		hlds_out__write_pred_or_func(PredOrFunc),
+		io__write_string(" `"),
+		io__write_string(Module),
+		io__write_string(":"),
 		{ PredOrFunc = function ->
 			OrigArity is Arity - 1
 		;
@@ -255,9 +260,9 @@
 		},
 		io__write_string(Name),
 		io__write_string("/"),
-		io__write_int(OrigArity)
-	),
-	io__write_string("'").
+		io__write_int(OrigArity),
+		io__write_string("'")
+	).
 
 hlds_out__write_pred_proc_id(ModuleInfo, PredId, ProcId) -->
 	hlds_out__write_pred_id(ModuleInfo, PredId),
@@ -447,8 +452,8 @@
 	{ pred_info_import_status(PredInfo, ImportStatus) },
 	{ pred_info_get_marker_list(PredInfo, Markers) },
 	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
-	mercury_output_pred_type(TVarSet, qualified(Module, PredName), ArgTypes,
-		no, Context),
+	mercury_output_pred_type(TVarSet, qualified(Module, PredName),
+				 ArgTypes, no, pure, Context),
 	{ ClausesInfo = clauses_info(VarSet, _, VarTypes, HeadVars, Clauses) },
 	hlds_out__write_indent(Indent),
 	io__write_string("% pred id: "),
@@ -515,6 +520,9 @@
 hlds_out__marker_name(magic, "magic").
 hlds_out__marker_name(obsolete, "obsolete").
 hlds_out__marker_name(memo, "memo").
+hlds_out__marker_name((impure), "impure").
+hlds_out__marker_name((semipure), "semipure").
+hlds_out__marker_name(promised_pure, "promised_pure").
 hlds_out__marker_name(terminates, "terminates").
 hlds_out__marker_name(check_termination, "check_termination").
 hlds_out__marker_name(does_not_terminate, "does_not_terminate").
@@ -824,6 +832,21 @@
 			Indent)
 	;
 		[]
+	),
+	( { string__contains_char(Verbose, 'g') }
+	->	
+		{ goal_info_get_features(GoalInfo, Features) },
+		{ set__to_sorted_list(Features, Flist) },
+		(   { Flist = [] } ->
+			[]
+		;   
+			hlds_out__write_indent(Indent),
+			io__write_string("% Goal features:  "),
+			io__write(Flist),
+			io__write_string("\n")
+		)
+	;
+		[]
 	).
 
 :- pred hlds_out__write_goal_2(hlds_goal_expr, module_info, varset, bool,
@@ -833,7 +856,7 @@
 hlds_out__write_goal_2(switch(Var, CanFail, CasesList, _), ModuleInfo, VarSet,
 		AppendVarnums, Indent, Follow, TypeQual) -->
 	hlds_out__write_indent(Indent),
-	io__write_string("( % "),
+	io__write_string("(			% "),
 	hlds_out__write_can_fail(CanFail),
 	io__write_string(" switch on `"),
 	mercury_output_var(Var, VarSet, AppendVarnums),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_pred.m,v
retrieving revision 1.37
diff -u -r1.37 hlds_pred.m
--- hlds_pred.m	1997/10/31 00:14:25	1.37
+++ hlds_pred.m	1997/11/14 00:56:53
@@ -13,7 +13,8 @@
 
 :- interface.
 
-:- import_module hlds_data, hlds_goal, hlds_module, llds, prog_data, instmap.
+:- import_module hlds_data, hlds_goal, hlds_module, llds, prog_data, instmap,
+	purity.
 :- import_module bool, list, map, std_util, term, varset.
 :- import_module term_util.
 
@@ -171,8 +172,8 @@
 	;	function.
 
 	% Predicates can be marked, to request that transformations be
-	% performed on them and to record that these transformations have been
-	% done and are still valid.
+	% performed (or not be performed) on them and to record that these
+	% transformations have been done and are still valid.
 	%
 	% The code that performs the transformation should remove the request
 	% marker status and substitute the done marker status.
@@ -213,6 +214,21 @@
 	;	memo		% Requests that this predicate be evaluated
 				% using memoing.
 				% Used for pragma(memo).
+	;	(impure)	% Requests that no transformation that would
+				% be inappropriate for impure code be
+				% performed on calls to this predicate.  This
+				% includes reordering calls to it relative to
+				% other goals (in both conjunctions and
+				% disjunctions), and removing redundant calls
+				% to it.
+	;	(semipure)	% Requests that no transformation that would
+				% be inappropriate for semipure code be
+				% performed on calls to this predicate.  This
+				% includes removing redundant calls to it on
+				% different sides of an impure goal.
+	;	promised_pure	% Requests that calls to this predicate be
+				% transformed as usual, despite any impure
+				% or semipure markers present.
 
 				% The terminates and does_not_terminate
 				% pragmas are kept as markers to ensure
@@ -371,6 +387,12 @@
 :- pred pred_info_requested_no_inlining(pred_info).
 :- mode pred_info_requested_no_inlining(in) is semidet.
 
+:- pred pred_info_get_purity(pred_info, purity).
+:- mode pred_info_get_purity(in, out) is det.
+
+:- pred pred_info_get_promised_pure(pred_info, bool).
+:- mode pred_info_get_promised_pure(in, out) is det.
+
 :- pred pred_info_get_marker_list(pred_info, list(marker_status)).
 :- mode pred_info_get_marker_list(in, out) is det.
 
@@ -592,6 +614,30 @@
 pred_info_requested_no_inlining(PredInfo0) :-
 	pred_info_get_marker_list(PredInfo0, Markers),
 	list__member(request(no_inline), Markers).
+
+pred_info_get_purity(PredInfo0, Purity) :-
+	pred_info_get_marker_list(PredInfo0, Markers),
+	(
+		list__member(request((impure)), Markers)
+	->	    
+		Purity = (impure)
+	;
+		list__member(request((semipure)), Markers)
+	->	    
+		Purity = (semipure)
+	;
+		Purity = pure
+	).
+
+pred_info_get_promised_pure(PredInfo0, Promised) :-
+	pred_info_get_marker_list(PredInfo0, Markers),
+	(
+		list__member(request((promised_pure)), Markers)
+	->	    
+		Promised = yes
+	;
+		Promised = no
+	).
 
 pred_info_get_marker_list(PredInfo, Markers) :-
 	PredInfo = predicate(_, _, _, _, _, _, _, _, _, _, _, _, Markers, _).
Index: compiler/intermod.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/intermod.m,v
retrieving revision 1.34
diff -u -r1.34 intermod.m
--- intermod.m	1997/10/26 23:05:36	1.34
+++ intermod.m	1997/11/14 00:32:10
@@ -850,17 +850,18 @@
 	{ pred_info_name(PredInfo, Name) },
 	{ pred_info_arg_types(PredInfo, TVarSet, ArgTypes) },
 	{ pred_info_context(PredInfo, Context) },
+	{ pred_info_get_purity(PredInfo, Purity) },
 	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
 	(
 		{ PredOrFunc = predicate },
 		mercury_output_pred_type(TVarSet, qualified(Module, Name),
-					ArgTypes, no, Context)
+					ArgTypes, no, Purity, Context)
 	;
 		{ PredOrFunc = function },
 		{ pred_args_to_func_args(ArgTypes, FuncArgTypes, FuncRetType) },
 		mercury_output_func_type(TVarSet,
 			qualified(Module, Name), FuncArgTypes,
-			FuncRetType, no, Context)
+			FuncRetType, no, Purity, Context)
 	),
 	{ pred_info_procedures(PredInfo, Procs) },
 	{ pred_info_procids(PredInfo, ProcIds) },
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/make_hlds.m,v
retrieving revision 1.243
diff -u -r1.243 make_hlds.m
--- make_hlds.m	1997/11/02 12:28:53	1.243
+++ make_hlds.m	1997/11/14 00:59:06
@@ -61,7 +61,7 @@
 :- import_module make_tags, quantification, (inst).
 :- import_module code_util, unify_proc, special_pred, type_util, mode_util.
 :- import_module mercury_to_mercury, passes_aux, clause_to_proc, inst_match.
-:- import_module fact_table, term_util.
+:- import_module fact_table, purity, term_util.
 
 :- import_module string, char, int, set, bintree, list, map, require.
 :- import_module bool, getopt, assoc_list, term, term_io, varset.
@@ -188,15 +188,17 @@
 	module_add_mode_defn(Module0, VarSet, ModeDefn, Cond, Context,
 			Status, Module).
 
-add_item_decl_pass_1(pred(VarSet, PredName, TypesAndModes, MaybeDet, Cond),
-		Context, Status, Module0, Status, Module) -->
+add_item_decl_pass_1(pred(VarSet, PredName, TypesAndModes, MaybeDet, Cond,
+		Purity), Context, Status, Module0, Status, Module) -->
 	module_add_pred(Module0, VarSet, PredName, TypesAndModes, MaybeDet,
-		Cond, Context, Status, Module).
+		Cond, Purity, Context, Status, Module).
 
 add_item_decl_pass_1(func(VarSet, FuncName, TypesAndModes, RetTypeAndMode,
-		MaybeDet, Cond), Context, Status, Module0, Status, Module) -->
+		MaybeDet, Cond, Purity), Context, Status, Module0, Status,
+		Module) -->
 	module_add_func(Module0, VarSet, FuncName, TypesAndModes,
-		RetTypeAndMode, MaybeDet, Cond, Context, Status, Module).
+		RetTypeAndMode, MaybeDet, Cond, Purity, Context, Status,
+			Module).
 
 add_item_decl_pass_1(pred_mode(VarSet, PredName, Modes, MaybeDet, Cond),
 		Context, Status, Module0, Status, Module) -->
@@ -382,6 +384,10 @@
 		{ Pragma = fact_table(_, _, _) },
 		{ Module = Module0 }
 	;
+		{ Pragma = promise_pure(Name, Arity) },
+		add_pred_marker(Module0, "promise_pure", Name, Arity, Context,
+				[request(promised_pure)], [], Module)
+	;
 		{ Pragma = termination_info(PredOrFunc, SymName, ModeList, 
 			Termination) },
 		{ module_info_get_predicate_table(Module0, Preds) },
@@ -463,8 +469,8 @@
 	).
 
 add_item_decl_pass_2(func(_VarSet, FuncName, TypesAndModes, _RetTypeAndMode,
-		_MaybeDet, _Cond), _Context, Status, Module0, Status, Module)
-		-->
+		_MaybeDet, _Cond, _Purity), _Context, Status, Module0, Status,
+		Module) -->
 	%
 	% add default modes for function declarations, if necessary
 	%
@@ -490,7 +496,7 @@
 		--> [].
 add_item_decl_pass_2(mode_defn(_, _, _), _, Status, Module, Status, Module)
 		--> [].
-add_item_decl_pass_2(pred(_, _, _, _, _), _, Status, Module, Status, Module)
+add_item_decl_pass_2(pred(_, _, _, _, _, _), _, Status, Module, Status, Module)
 		--> [].
 add_item_decl_pass_2(pred_mode(_, _, _, _, _), _, Status, Module, Status,
 		Module) --> [].
@@ -539,9 +545,9 @@
 				Module, Module, Info, Info) --> [].
 add_item_clause(mode_defn(_, _, _), Status, Status, _,
 				Module, Module, Info, Info) --> [].
-add_item_clause(pred(_, _, _, _, _), Status, Status, _,
+add_item_clause(pred(_, _, _, _, _, _), Status, Status, _,
 				Module, Module, Info, Info) --> [].
-add_item_clause(func(_, _, _, _, _, _), Status, Status, _,
+add_item_clause(func(_, _, _, _, _, _, _), Status, Status, _,
 				Module, Module, Info, Info) --> [].
 add_item_clause(pred_mode(_, _, _, _, _), Status, Status, _,
 				Module, Module, Info, Info) --> [].
@@ -659,6 +665,9 @@
 		)
 	;
 		{ string__append_list(
+			% XXX It would be terser (and so less likely to
+			%     overrun the line), if this were instead:
+			%	  ["`", PragmaName, "' pragma"],
 			["`:- pragma ", PragmaName, "' declaration"],
 			Description) },
 		undefined_pred_or_func_error(Name, Arity, Context,
@@ -1060,12 +1069,13 @@
 %---------------------------------------------------------------------------%
 
 :- pred module_add_pred(module_info, varset, sym_name, list(type_and_mode),
-		maybe(determinism), condition, term__context, 
+		maybe(determinism), condition, purity, term__context, 
 		item_status, module_info, io__state, io__state).
-:- mode module_add_pred(in, in, in, in, in, in, in, in, out, di, uo) is det.
+:- mode module_add_pred(in, in, in, in, in, in, in, in, in, out, di, uo)
+		is det.
 
 module_add_pred(Module0, VarSet, PredName, TypesAndModes, MaybeDet, Cond,
-		Context, item_status(Status, NeedQual), Module) -->
+		Purity, Context, item_status(Status, NeedQual), Module) -->
 	% Only preds with opt_imported clauses are tagged as opt_imported, so
 	% that the compiler doesn't look for clauses for other preds read in
 	% from optimization interfaces.
@@ -1075,7 +1085,7 @@
 		DeclStatus = Status
 	},
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
-	add_new_pred(Module0, VarSet, PredName, Types, Cond, Context,
+	add_new_pred(Module0, VarSet, PredName, Types, Cond, Purity, Context,
 		DeclStatus, NeedQual, predicate, Module1),
 	(
 		{ MaybeModes = yes(Modes) }
@@ -1087,12 +1097,13 @@
 	).
 
 :- pred module_add_func(module_info, varset, sym_name, list(type_and_mode),
-		type_and_mode, maybe(determinism), condition, term__context,
-		item_status, module_info, io__state, io__state).
-:- mode module_add_func(in, in, in, in, in, in, in, in, in, out, di, uo) is det.
+		type_and_mode, maybe(determinism), condition, purity,
+		term__context, item_status, module_info, io__state, io__state).
+:- mode module_add_func(in, in, in, in, in, in, in, in, in, in, out, di, uo)
+		is det.
 
 module_add_func(Module0, VarSet, FuncName, TypesAndModes, RetTypeAndMode,
-		MaybeDet, Cond, Context,
+		MaybeDet, Cond, Purity, Context,
 		item_status(Status, NeedQual), Module) -->
 	% Only funcs with opt_imported clauses are tagged as opt_imported, so
 	% that the compiler doesn't look for clauses for other preds.
@@ -1104,7 +1115,7 @@
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
 	{ split_type_and_mode(RetTypeAndMode, RetType, MaybeRetMode) },
 	{ list__append(Types, [RetType], Types1) },
-	add_new_pred(Module0, VarSet, FuncName, Types1, Cond, Context,
+	add_new_pred(Module0, VarSet, FuncName, Types1, Cond, Purity, Context,
 		DeclStatus, NeedQual, function, Module1),
 	(
 		{ MaybeModes = yes(Modes) },
@@ -1118,15 +1129,16 @@
 	).
 
 :- pred add_new_pred(module_info, tvarset, sym_name, list(type), condition, 
-		term__context, import_status, need_qualifier, pred_or_func,
-		module_info, io__state, io__state).
-:- mode add_new_pred(in, in, in, in, in, in, in, in, in, out, di, uo) is det.
+		purity, term__context, import_status, need_qualifier,
+		pred_or_func, module_info, io__state, io__state).
+:- mode add_new_pred(in, in, in, in, in, in, in, in, in, in, out, di, uo)
+		is det.
 
 % NB.  Predicates are also added in polymorphism.m, which converts
 % lambda expressions into separate predicates, so any changes may need
 % to be reflected there too.
 
-add_new_pred(Module0, TVarSet, PredName, Types, Cond, Context, 
+add_new_pred(Module0, TVarSet, PredName, Types, Cond, Purity, Context, 
 		Status, NeedQual, PredOrFunc, Module) -->
 	{ module_info_name(Module0, ModuleName) },
 	{ list__length(Types, Arity) },
@@ -1141,9 +1153,10 @@
 		{ Module1 = Module0 },
 		{ module_info_get_predicate_table(Module1, PredicateTable0) },
 		{ clauses_info_init(Arity, ClausesInfo) },
+		{ purity_to_marker_list(Purity, MarkerList) },
 		{ pred_info_init(ModuleName, PredName, Arity, TVarSet, Types,
-				Cond, Context, ClausesInfo, Status, [], none,	
-				PredOrFunc, PredInfo0) },
+				Cond, Context, ClausesInfo, Status,
+				MarkerList, none, PredOrFunc, PredInfo0) },
 		(
 			{ predicate_table_search_pf_m_n_a(PredicateTable0,
 				PredOrFunc, MNameOfPred, PName, Arity,
@@ -1789,7 +1802,8 @@
 		->
 			{ pred_info_clauses_info(PredInfo1, Clauses0) },
 			{ pred_info_arg_types(PredInfo1, _TVarSet, ArgTypes) },
-			clauses_info_add_pragma_c_code(Clauses0,
+			{ pred_info_get_purity(PredInfo1, Purity) },
+			clauses_info_add_pragma_c_code(Clauses0, Purity,
 				MayCallMercury, PredId, ProcId, VarSet,
 				PVars, ArgTypes, C_Code, Context, ExtraInfo,
 				Clauses, Info0, Info),
@@ -2424,17 +2438,17 @@
 % pragma c_code declaration and the head vars of the pred. Also return the
 % hlds_goal.
 
-:- pred clauses_info_add_pragma_c_code(clauses_info, may_call_mercury,
+:- pred clauses_info_add_pragma_c_code(clauses_info, purity, may_call_mercury,
 	pred_id, proc_id, varset, list(pragma_var), list(type),
 	string, term__context,
 	maybe(pair(list(string))), clauses_info,
 	qual_info, qual_info, io__state, io__state) is det.
 :- mode clauses_info_add_pragma_c_code(in, in, in, in, in, in, in, in, in, in,
-	out, in, out, di, uo) is det.
+	in, out, in, out, di, uo) is det.
 
-clauses_info_add_pragma_c_code(ClausesInfo0, MayCallMercury, PredId, ModeId,
-		PVarSet, PVars, OrigArgTypes, C_Code, Context, ExtraInfo,
-		ClausesInfo, Info0, Info) -->
+clauses_info_add_pragma_c_code(ClausesInfo0, Purity, MayCallMercury, PredId,
+		ModeId, PVarSet, PVars, OrigArgTypes, C_Code, Context,
+		ExtraInfo, ClausesInfo, Info0, Info) -->
 	{
 	ClausesInfo0 = clauses_info(VarSet0, VarTypes, VarTypes1,
 				 HeadVars, ClauseList),
@@ -2459,7 +2473,9 @@
 
 		% build the pragma_c_code
 	goal_info_init(GoalInfo0),
-	goal_info_set_context(GoalInfo0, Context, GoalInfo),
+	goal_info_set_context(GoalInfo0, Context, GoalInfo1),
+	% Put the purity in the goal_info in case this c code is inlined
+	add_goal_info_purity_feature(GoalInfo1, Purity, GoalInfo),
 	HldsGoal0 = pragma_c_code(C_Code, MayCallMercury, PredId, ModeId, Args,
 			Names, OrigArgTypes, ExtraPragmaInfo) - GoalInfo
 	}, 
@@ -2652,6 +2668,46 @@
 	{ term__apply_substitution(B0, Subst, B) },
 	unravel_unification(A, B, Context, explicit, [],
 			VarSet0, Goal, VarSet, Info0, Info).
+transform_goal_2(purity(Goal0, Purity), _, VarSet0, Subst, Goal,
+		VarSet, Info0, Info) -->
+	transform_goal(Goal0, VarSet0, Subst, Goal1, VarSet,
+			 Info0, Info),
+	{ mark_goal_with_purity(Goal1, Purity, Goal) }.
+
+
+:- pred mark_goal_with_purity(hlds_goal, purity, hlds_goal).
+:- mode mark_goal_with_purity(in, in, out) is det.
+
+mark_goal_with_purity(Goal0-GoalInfo0, Purity, Goal-GoalInfo) :-
+	(   Goal0 = conj(Goals0) ->
+		Goal = conj(Goals),
+		GoalInfo = GoalInfo0,
+		mark_calls_with_purity(Goals0, Purity, Goals)
+	;
+		Goal = Goal0,
+		add_goal_info_purity_feature(GoalInfo0, Purity, GoalInfo)
+	).
+
+
+:- pred mark_calls_with_purity(list(hlds_goal), purity, list(hlds_goal)).
+:- mode mark_calls_with_purity(in, in, out) is det.
+
+mark_calls_with_purity([], _, []).
+mark_calls_with_purity([Goal0-GoalInfo0|Goals0], Purity,
+		[Goal-GoalInfo|Goals]) :-
+	(   Goal0 = call(_,_,_,_,_,_) ->
+		Goal = Goal0,
+		add_goal_info_purity_feature(GoalInfo0, Purity, GoalInfo)
+	;   Goal0 = conj(Goals1) ->
+		GoalInfo = GoalInfo0,
+		Goal = conj(Goals2),
+		mark_calls_with_purity(Goals1, Purity, Goals2)
+	;
+		Goal = Goal0,
+		GoalInfo = GoalInfo0
+	),
+	mark_calls_with_purity(Goals0, Purity, Goals).
+
 
 %-----------------------------------------------------------------------------
 
@@ -3332,6 +3388,8 @@
 	hlds_out__write_pred_call_id(Name/Arity),
 	io__write_string("\n"),
 	prog_out__write_context(Context),
+	% XXX is `preceding' the right word here?  Can't the pred or func decl
+	%     appear afterward?  Would `corresponding' be a better word?
 	io__write_string("  without preceding `pred' or `func' declaration\n").
 
 :- pred undefined_mode_error(sym_name, int, term__context, string,
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_compile.m,v
retrieving revision 1.60
diff -u -r1.60 mercury_compile.m
--- mercury_compile.m	1997/11/08 13:11:34	1.60
+++ mercury_compile.m	1997/11/14 00:32:20
@@ -30,7 +30,7 @@
 
 	% the main compiler passes (in order of execution)
 :- import_module handle_options, prog_io, modules, module_qual, equiv_type.
-:- import_module make_hlds, typecheck, modes.
+:- import_module make_hlds, typecheck, purity, modes.
 :- import_module switch_detection, cse_detection, det_analysis, unique_modes.
 :- import_module simplify, intermod, trans_opt, bytecode_gen, bytecode.
 :- import_module (lambda), polymorphism, termination, higher_order, inlining.
@@ -550,10 +550,13 @@
 % is det.
 :- mode mercury_compile__frontend_pass_2_by_phases(in, out, out, di, uo) is det.
 
-mercury_compile__frontend_pass_2_by_phases(HLDS4, HLDS20, FoundError) -->
+mercury_compile__frontend_pass_2_by_phases(HLDS3, HLDS20, FoundError) -->
 	globals__io_lookup_bool_option(verbose, Verbose),
 	globals__io_lookup_bool_option(statistics, Stats),
 
+	mercury_compile__puritycheck(HLDS3, Verbose, Stats, HLDS4),
+	mercury_compile__maybe_dump_hlds(HLDS4, "04", "puritycheck"),
+
 	mercury_compile__modecheck(HLDS4, Verbose, Stats, HLDS5,
 		FoundModeError, UnsafeToContinue),
 	mercury_compile__maybe_dump_hlds(HLDS5, "05", "modecheck"),
@@ -914,6 +917,24 @@
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
+
+:- pred mercury_compile__puritycheck(module_info, bool, bool,
+				module_info, io__state, io__state).
+:- mode mercury_compile__puritycheck(in, in, in, out, di, uo) is det.
+
+mercury_compile__puritycheck(HLDS0, Verbose, Stats, HLDS) -->
+	{ module_info_num_errors(HLDS0, NumErrors0) },
+	puritycheck(HLDS0, HLDS),
+	{ module_info_num_errors(HLDS, NumErrors) },
+	( { NumErrors \= NumErrors0 } ->
+		maybe_write_string(Verbose,
+			"% Program contains purity error(s).\n"),
+		io__set_exit_status(1)
+	;
+		maybe_write_string(Verbose,
+			"% Program is purity-correct.\n")
+	),
+	maybe_report_stats(Stats).
 
 :- pred mercury_compile__modecheck(module_info, bool, bool,
 				module_info, bool, bool, io__state, io__state).
Index: compiler/mercury_to_c.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_c.m,v
retrieving revision 1.27
diff -u -r1.27 mercury_to_c.m
--- mercury_to_c.m	1997/09/01 14:03:37	1.27
+++ mercury_to_c.m	1997/09/09 04:54:21
@@ -170,8 +170,9 @@
 	;
 		c_gen_indent(Indent),
 		io__write_string("/****\n"),
+		{ pred_info_get_purity(PredInfo, Purity) },
 		mercury_output_pred_type(TVarSet, unqualified(PredName),
-			ArgTypes, no, Context),
+			ArgTypes, no, Purity, Context),
 
 		{ pred_info_clauses_info(PredInfo, ClausesInfo) },
 		{ ClausesInfo = clauses_info(VarSet, _VarTypes, _, HeadVars,
Index: compiler/mercury_to_goedel.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_goedel.m,v
retrieving revision 1.60
diff -u -r1.60 mercury_to_goedel.m
--- mercury_to_goedel.m	1997/08/22 13:55:25	1.60
+++ mercury_to_goedel.m	1997/10/03 06:06:58
@@ -140,14 +140,14 @@
 goedel_output_item(mode_defn(VarSet, ModeDefn, _Cond), Context) -->
 	goedel_output_mode_defn(VarSet, ModeDefn, Context).
 
-goedel_output_item(pred(VarSet, PredName, TypesAndModes, _Det, _Cond), Context)
-		-->
+goedel_output_item(pred(VarSet, PredName, TypesAndModes, _Det, _Cond,
+		_Purity), Context) -->
 	io__write_string("\n"),
 	maybe_write_line_number(Context),
 	goedel_output_pred(VarSet, PredName, TypesAndModes, Context).
 
 goedel_output_item(func(VarSet, PredName, TypesAndModes, RetTypeAndMode, _Det,
-		_Cond), Context) -->
+		_Cond, _Purity), Context) -->
 	io__write_string("\n"),
 	maybe_write_line_number(Context),
 	goedel_output_func(VarSet, PredName, TypesAndModes, RetTypeAndMode,
@@ -615,6 +615,10 @@
 	goedel_output_term(A, VarSet),
 	io__write_string(" = "),
 	goedel_output_term(B, VarSet).
+
+goedel_output_goal_2(purity(Goal,_), VarSet, Indent) -->
+	% XXX we just ignore purity indicators altogether -- is this right?
+	goedel_output_goal(Goal, VarSet, Indent).
 
 
 :- pred goedel_output_call(term, varset, int, io__state, io__state).
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.119
diff -u -r1.119 mercury_to_mercury.m
--- mercury_to_mercury.m	1997/10/09 09:38:54	1.119
+++ mercury_to_mercury.m	1997/11/14 00:59:36
@@ -14,7 +14,7 @@
 :- module mercury_to_mercury.
 :- interface.
 
-:- import_module hlds_goal, hlds_data, hlds_pred, prog_data, (inst).
+:- import_module hlds_goal, hlds_data, hlds_pred, prog_data, (inst), purity.
 :- import_module list, io, varset, term.
 
 %	convert_to_mercury(ProgName, OutputFileName, Items)
@@ -23,12 +23,14 @@
 :- mode convert_to_mercury(in, in, in, di, uo) is det.
 
 :- pred mercury_output_pred_type(varset, sym_name, list(type),
-		maybe(determinism), term__context, io__state, io__state).
-:- mode mercury_output_pred_type(in, in, in, in, in, di, uo) is det.
+		maybe(determinism), purity, term__context,
+		io__state, io__state).
+:- mode mercury_output_pred_type(in, in, in, in, in, in, di, uo) is det.
 
 :- pred mercury_output_func_type(varset, sym_name, list(type), type,
-		maybe(determinism), term__context, io__state, io__state).
-:- mode mercury_output_func_type(in, in, in, in, in, in, di, uo) is det.
+		maybe(determinism), purity, term__context,
+		io__state, io__state).
+:- mode mercury_output_func_type(in, in, in, in, in, in, in, di, uo) is det.
 
 :- pred mercury_output_pred_mode_decl(varset, sym_name, list(mode),
 		maybe(determinism), term__context, io__state, io__state).
@@ -221,16 +223,17 @@
 	maybe_output_line_number(Context),
 	mercury_output_mode_defn(VarSet, ModeDefn, Context).
 
-mercury_output_item(pred(VarSet, PredName, TypesAndModes, Det, _Cond), Context)
-		-->
+mercury_output_item(pred(VarSet, PredName, TypesAndModes, Det, _Cond,
+		Purity), Context) -->
 	maybe_output_line_number(Context),
-	mercury_output_pred_decl(VarSet, PredName, TypesAndModes, Det, Context).
+	mercury_output_pred_decl(VarSet, PredName, TypesAndModes, Det,
+				 Purity, Context).
 
 mercury_output_item(func(VarSet, PredName, TypesAndModes, RetTypeAndMode, Det,
-		_Cond), Context) -->
+		_Cond, Purity), Context) -->
 	maybe_output_line_number(Context),
 	mercury_output_func_decl(VarSet, PredName, TypesAndModes,
-			RetTypeAndMode, Det, Context).
+			RetTypeAndMode, Det, Purity, Context).
 
 mercury_output_item(pred_mode(VarSet, PredName, Modes, MaybeDet, _Cond),
 			Context) -->
@@ -304,6 +307,9 @@
 		{ Pragma = fact_table(Pred, Arity, FileName) },
 		mercury_output_pragma_fact_table(Pred, Arity, FileName)
 	;
+		{ Pragma = promise_pure(Pred, Arity) },
+		mercury_output_pragma_decl(Pred, Arity, "promise_pure")
+	;
 		{ Pragma = termination_info(PredOrFunc, PredName, 
 			ModeList, Termination) },
 		termination__output_pragma_termination_info(PredOrFunc,
@@ -1053,12 +1059,15 @@
 %-----------------------------------------------------------------------------%
 
 :- pred mercury_output_pred_decl(varset, sym_name, list(type_and_mode),
-		maybe(determinism), term__context, io__state, io__state).
-:- mode mercury_output_pred_decl(in, in, in, in, in, di, uo) is det.
+		maybe(determinism), purity, term__context,
+		io__state, io__state).
+:- mode mercury_output_pred_decl(in, in, in, in, in, in, di, uo) is det.
 
-mercury_output_pred_decl(VarSet, PredName, TypesAndModes, MaybeDet, Context) -->
+mercury_output_pred_decl(VarSet, PredName, TypesAndModes, MaybeDet, Purity,
+		Context) -->
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
-	mercury_output_pred_type(VarSet, PredName, Types, MaybeDet, Context),
+	mercury_output_pred_type(VarSet, PredName, Types, MaybeDet, Purity,
+				 Context),
 	(
 		{ MaybeModes = yes(Modes) },
 		{ Modes \= [] }
@@ -1069,8 +1078,11 @@
 		[]
 	).
 
-mercury_output_pred_type(VarSet, PredName, Types, MaybeDet, _Context) -->
-	io__write_string(":- pred "),
+mercury_output_pred_type(VarSet, PredName, Types, MaybeDet, Purity,
+		_Context) -->
+	io__write_string(":- "),
+	write_purity_prefix(Purity),
+	io__write_string("pred "),
 	(
 		{ Types = [Type | Rest] }
 	->
@@ -1107,15 +1119,31 @@
 	),
 	io__write_string(".\n").
 
+
+% this works under the assumptions that all purity names but `pure' are prefix
+% operators, and that we never need `pure' indicators/declarations.
+
+:- pred write_purity_prefix(purity, io__state, io__state).
+:- mode write_purity_prefix(in, di, uo) is det.
+
+write_purity_prefix(Purity) -->
+	(   { Purity = pure } ->
+		[]
+	;
+		write_purity(Purity),
+		io__write_string(" ")
+	).
+
+
 %-----------------------------------------------------------------------------%
 
 :- pred mercury_output_func_decl(varset, sym_name, list(type_and_mode),
-		type_and_mode, maybe(determinism), term__context,
+		type_and_mode, maybe(determinism), purity, term__context,
 		io__state, io__state).
-:- mode mercury_output_func_decl(in, in, in, in, in, in, di, uo) is det.
+:- mode mercury_output_func_decl(in, in, in, in, in, in, in, di, uo) is det.
 
 mercury_output_func_decl(VarSet, FuncName, TypesAndModes, RetTypeAndMode,
-		MaybeDet, Context) -->
+		MaybeDet, Purity, Context) -->
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
 	{ split_type_and_mode(RetTypeAndMode, RetType, MaybeRetMode) },
 	(
@@ -1123,17 +1151,19 @@
 		{ MaybeRetMode = yes(RetMode) }
 	->
 		mercury_output_func_type(VarSet, FuncName, Types, RetType,
-				no, Context),
+				no, Purity, Context),
 		mercury_output_func_mode_decl(VarSet, FuncName, Modes, RetMode,
 				MaybeDet, Context)
 	;
 		mercury_output_func_type(VarSet, FuncName, Types, RetType,
-				MaybeDet, Context)
+				MaybeDet, Purity, Context)
 	).
 
-mercury_output_func_type(VarSet, FuncName, Types, RetType, MaybeDet, _Context)
-		-->
-	io__write_string(":- func "),
+mercury_output_func_type(VarSet, FuncName, Types, RetType, MaybeDet, Purity,
+		_Context) -->
+	io__write_string(":- "),
+	write_purity_prefix(Purity),
+	io__write_string("func "),
 	(
 		{ Types = [Type | Rest] }
 	->
@@ -1451,6 +1481,11 @@
 	io__write_string(" = "),
 	mercury_output_term(B, VarSet, no).
 
+mercury_output_goal_2(purity(Goal, Purity), VarSet, Indent) -->
+	write_purity_prefix(Purity),
+	mercury_output_goal(Goal, VarSet, Indent).
+
+
 :- pred mercury_output_call(sym_name, list(term), varset, int,
 	io__state, io__state).
 :- mode mercury_output_call(in, in, in, in, di, uo) is det.
@@ -1940,6 +1975,7 @@
 mercury_unary_prefix_op("func").
 mercury_unary_prefix_op("if").
 mercury_unary_prefix_op("import_module").
+mercury_unary_prefix_op("impure").
 mercury_unary_prefix_op("insert").
 mercury_unary_prefix_op("inst").
 mercury_unary_prefix_op("lib").
@@ -1954,6 +1990,7 @@
 mercury_unary_prefix_op("pred").
 mercury_unary_prefix_op("pure").
 mercury_unary_prefix_op("rule").	/* NU-Prolog */
+mercury_unary_prefix_op("semipure").
 mercury_unary_prefix_op("sorted").
 mercury_unary_prefix_op("spy").
 mercury_unary_prefix_op("type").
Index: compiler/mode_errors.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_errors.m,v
retrieving revision 1.47
diff -u -r1.47 mode_errors.m
--- mode_errors.m	1997/07/27 15:01:04	1.47
+++ mode_errors.m	1997/10/01 08:33:49
@@ -77,9 +77,10 @@
 	;	mode_error_unify_var_lambda(var, inst, inst)
 			% some sort of error in
 			% attempt to unify a variable with lambda expression
-	;	mode_error_conj(list(delayed_goal))
+	;	mode_error_conj(list(delayed_goal), schedule_culprit)
 			% a conjunction contains one or more unscheduleable
-			% goals
+			% goals; schedule_culprit gives the reason why
+			% they couldn't be scheduled.
 	;	mode_error_final_inst(int, var, inst, inst, final_inst_error)
 			% one of the head variables did not have the
 			% expected final inst on exit from the proc
@@ -87,6 +88,12 @@
 			% This is a dummy error - the actual message
 			% is output by module_qual.m.
 
+:- type schedule_culprit
+	--->	goal_itself_was_impure
+	;	goals_followed_by_impure_goal(hlds_goal)
+	;	just_because.	% we've reached the end of a conjunction
+				% and there were still delayed goals
+
 :- type final_inst_error
 	--->	too_instantiated
 	;	not_instantiated_enough
@@ -183,8 +190,8 @@
 			ArgInsts), ModeInfo) -->
 	report_mode_error_unify_var_functor(ModeInfo, Var, Name, Args, Inst,
 			ArgInsts).
-report_mode_error(mode_error_conj(Errors), ModeInfo) -->
-	report_mode_error_conj(ModeInfo, Errors).
+report_mode_error(mode_error_conj(Errors, Culprit), ModeInfo) -->
+	report_mode_error_conj(ModeInfo, Errors, Culprit).
 report_mode_error(mode_error_no_matching_mode(Vars, Insts), ModeInfo) -->
 	report_mode_error_no_matching_mode(ModeInfo, Vars, Insts).
 report_mode_error(mode_error_final_inst(ArgNum, Var, VarInst, Inst, Reason),
@@ -195,16 +202,19 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred report_mode_error_conj(mode_info, list(delayed_goal),
+:- pred report_mode_error_conj(mode_info, list(delayed_goal), schedule_culprit,
 				io__state, io__state).
-:- mode report_mode_error_conj(mode_info_no_io, in, di, uo) is det.
+:- mode report_mode_error_conj(mode_info_no_io, in, in, di, uo) is det.
 
-report_mode_error_conj(ModeInfo, Errors) -->
+report_mode_error_conj(ModeInfo, Errors, Culprit) -->
 	{ mode_info_get_context(ModeInfo, Context) },
 	{ mode_info_get_varset(ModeInfo, VarSet) },
 	{ find_important_errors(Errors, ImportantErrors, OtherErrors) },
+
+	% if there's more than one error, and we have verbose-errors
+	% enabled, report them all
 	globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
-	( { VerboseErrors = yes } ->
+	( { VerboseErrors = yes, Errors = [_, _ | _] } ->
 		mode_info_write_context(ModeInfo),
 		prog_out__write_context(Context),
 		io__write_string("  mode error in conjunction. The next "),
@@ -230,6 +240,28 @@
 	;
 		% There wasn't any error to report!  This can't happen.
 		{ error("report_mode_error_conj") }
+	),
+
+	% if the goal(s) couldn't be scheduled because we couldn't
+	% reorder things past an impure goal, then report that.
+	( { Culprit = just_because },
+		{ true } % we've already reported everything we can
+	; { Culprit = goal_itself_was_impure },
+		prog_out__write_context(Context),
+		io__write_string(
+		"  The goal could not be reordered, because it was impure.\n")
+	; { Culprit = goals_followed_by_impure_goal(ImpureGoal) },
+		prog_out__write_context(Context),
+		io__write_string(
+			"  The goal could not be reordered, because\n"),
+		prog_out__write_context(Context),
+		io__write_string(
+			"  it was followed by an impure goal.\n"),
+		{ ImpureGoal = _ - ImpureGoalInfo },
+		{ goal_info_get_context(ImpureGoalInfo, ImpureGoalContext) },
+		prog_out__write_context(ImpureGoalContext),
+		io__write_string(
+			"  This is the location of the impure goal.\n")
 	).
 
 :- pred find_important_errors(list(delayed_goal), list(delayed_goal),
Index: compiler/modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modes.m,v
retrieving revision 1.206
diff -u -r1.206 modes.m
--- modes.m	1997/11/13 06:27:07	1.206
+++ modes.m	1997/11/14 00:32:27
@@ -276,7 +276,7 @@
 :- import_module type_util, mode_util, code_util, prog_data, unify_proc.
 :- import_module globals, options, mercury_to_mercury, hlds_out, int, set.
 :- import_module passes_aux, typecheck, module_qual, clause_to_proc.
-:- import_module modecheck_unify, modecheck_call, inst_util.
+:- import_module modecheck_unify, modecheck_call, inst_util, purity.
 :- import_module list, map, varset, term, prog_out, string, require, std_util.
 :- import_module assoc_list.
 
@@ -767,13 +767,9 @@
 	modecheck_goal(G0, G),
 	mode_checkpoint(exit, "some").
 
-modecheck_goal_expr(call(PredId0, _, Args0, _, Context, PredName0),
-                GoalInfo0, Goal) -->
-        % do the last step of type-checking
+modecheck_goal_expr(call(PredId, _, Args0, _, Context, PredName),
+		GoalInfo0, Goal) -->
         =(ModeInfo0),
-        { resolve_pred_overloading(PredId0, Args0, PredName0, PredName,
-                ModeInfo0, PredId) },
-
 	mode_checkpoint(enter, "call"),
 	mode_info_set_call_context(call(PredId)),
 	{ mode_info_get_instmap(ModeInfo0, InstMap0) },
@@ -934,7 +930,7 @@
 	mode_info_set_delay_info(DelayInfo1),
 	mode_info_add_goals_live_vars(Goals0),
 
-	modecheck_conj_list_2(Goals0, Goals),
+	modecheck_conj_list_2(Goals0, [], Goals, ImpurityErrors),
 
 	=(ModeInfo3),
 	{ mode_info_get_errors(ModeInfo3, NewErrors) },
@@ -945,13 +941,21 @@
 	{ delay_info__leave_conj(DelayInfo4, DelayedGoals, DelayInfo5) },
 	mode_info_set_delay_info(DelayInfo5),
 
+	% we only report impurity errors if there were no other errors
 	( { DelayedGoals = [] } ->
-		[]
+		% XXX perhaps we should report all the impurity errors,
+		% rather than just the first one
+		( { ImpurityErrors = [FirstImpurityError | _Rest] } ->
+			mode_info_add_error(FirstImpurityError)
+	      	;
+			[]
+	      	)	       
 	; { DelayedGoals = [delayed_goal(_DVars, Error, _DGoal)] } ->
 		mode_info_add_error(Error)
 	;
 		{ get_all_waiting_vars(DelayedGoals, Vars) },
-		mode_info_error(Vars, mode_error_conj(DelayedGoals))
+		mode_info_error(Vars,
+			mode_error_conj(DelayedGoals, just_because))
 	).
 
 mode_info_add_goals_live_vars([]) --> [].
@@ -966,9 +970,13 @@
 	mode_info_remove_live_vars(Vars),
 	mode_info_remove_goals_live_vars(Goals).
 
-:- pred modecheck_conj_list_2(list(hlds_goal), list(hlds_goal),
-				mode_info, mode_info).
-:- mode modecheck_conj_list_2(in, out, mode_info_di, mode_info_uo) is det.
+:- type impurity_errors == list(mode_error_info).
+
+:- pred modecheck_conj_list_2(list(hlds_goal), impurity_errors,
+			list(hlds_goal), impurity_errors,
+			mode_info, mode_info).
+:- mode modecheck_conj_list_2(in, in, out, out, mode_info_di, mode_info_uo)
+	is det.
 
 	% Schedule a conjunction.
 	% If it's empty, then there is nothing to do.
@@ -977,8 +985,19 @@
 	% pending goal (if any), and if not, we delay the goal.  Then we
 	% continue attempting to schedule all the rest of the goals.
 
-modecheck_conj_list_2([], []) --> [].
-modecheck_conj_list_2([Goal0 | Goals0], Goals) -->
+modecheck_conj_list_2([], ImpurityErrors, [], ImpurityErrors) --> [].
+modecheck_conj_list_2([Goal0 | Goals0], ImpurityErrors0,
+		Goals, ImpurityErrors) -->
+
+	{ Goal0 = _GoalExpr - GoalInfo0 },
+	( { goal_info_is_impure(GoalInfo0) } ->
+		{ Impure = yes },
+		check_for_impurity_error(Goal0, ImpurityErrors0,
+					 ImpurityErrors1)
+	;
+		{ Impure = no },
+		{ ImpurityErrors1 = ImpurityErrors0 }
+	),
 
 		% Hang onto the original instmap & delay_info
 	mode_info_dcg_get_instmap(InstMap0),
@@ -997,14 +1016,31 @@
 		% and delay the goal.
 	=(ModeInfo1),
 	{ mode_info_get_errors(ModeInfo1, Errors) },
-	( { Errors = [ FirstError | _] } ->
+	(   { Errors = [ FirstErrorInfo | _] } ->
 		mode_info_set_errors([]),
 		mode_info_set_instmap(InstMap0),
 		mode_info_add_live_vars(NonLocalVars),
-		{ delay_info__delay_goal(DelayInfo0, FirstError, Goal0,
-					DelayInfo1) }
-	;
-		{ mode_info_get_delay_info(ModeInfo1, DelayInfo1) }
+		{ delay_info__delay_goal(DelayInfo0, FirstErrorInfo,
+					 Goal0, DelayInfo1) },
+		%  delaying an impure goal is an impurity error
+		( { Impure = yes } ->
+			{ FirstErrorInfo = mode_error_info(Vars, _, _, _) },
+			{ ImpureError = mode_error_conj(
+				[delayed_goal(Vars, FirstErrorInfo, Goal0)],
+				goal_itself_was_impure) },
+			=(ModeInfo2),
+			{ mode_info_get_context(ModeInfo2, Context) },
+			{ mode_info_get_mode_context(ModeInfo2, ModeContext) },
+			{ ImpureErrorInfo = mode_error_info( Vars, ImpureError,
+						Context, ModeContext) },
+			{ ImpurityErrors2 = [ImpureErrorInfo |
+						ImpurityErrors1] }
+		;   
+			{ ImpurityErrors2 = ImpurityErrors1 }
+		)
+	;   
+		{ mode_info_get_delay_info(ModeInfo1, DelayInfo1) },
+		{ ImpurityErrors2 = ImpurityErrors1 }
 	),
 
 		% Next, we attempt to wake up any pending goals,
@@ -1022,16 +1058,67 @@
 	mode_info_dcg_get_instmap(InstMap),
 	( { instmap__is_unreachable(InstMap) } ->
 		mode_info_remove_goals_live_vars(Goals1),
-		{ Goals2  = [] }
+		{ Goals2  = [] },
+		{ ImpurityErrors = ImpurityErrors2 }
 	;
-		modecheck_conj_list_2(Goals1, Goals2)
+		modecheck_conj_list_2(Goals1, ImpurityErrors2,
+				      Goals2, ImpurityErrors)
 	),
+
 	( { Errors = [] } ->
+		% we successfully scheduled this goal, so insert
+		% it in the list of successfully scheduled goals
 		{ Goals = [Goal | Goals2] }
 	;
+		% we delayed this goal -- it will be stored in the delay_info
 		{ Goals = Goals2 }
 	).
 
+%  check whether there are any delayed goals at the point where
+%  we are about to schedule an impure goal.  If so, that is an error.
+:- pred check_for_impurity_error(hlds_goal, impurity_errors, impurity_errors,
+		mode_info, mode_info).
+:- mode check_for_impurity_error(in, in, out, mode_info_di, mode_info_uo)
+	is det.
+check_for_impurity_error(Goal, ImpurityErrors0, ImpurityErrors) -->
+	=(ModeInfo0),
+	{ mode_info_get_delay_info(ModeInfo0, DelayInfo0) },
+	{ delay_info__leave_conj(DelayInfo0, DelayedGoals,
+				 DelayInfo1) },
+	{ delay_info__enter_conj(DelayInfo1, DelayInfo) },
+	{ mode_info_get_module_info(ModeInfo0, ModuleInfo) },
+	{ mode_info_get_predid(ModeInfo0, PredId) },
+	{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
+	{ pred_info_clauses_info(PredInfo, ClausesInfo) },
+	{ ClausesInfo = clauses_info(_,_,_,HeadVars,_) },
+	(   { no_non_headvar_unification_goals(DelayedGoals, HeadVars) } ->
+		{ ImpurityErrors = ImpurityErrors0 }
+	;
+		mode_info_set_delay_info(DelayInfo),
+		{ get_all_waiting_vars(DelayedGoals, Vars) },
+		{ ModeError = mode_error_conj(DelayedGoals,
+					goals_followed_by_impure_goal(Goal)) },
+		=(ModeInfo1),
+		{ mode_info_get_context(ModeInfo1, Context) },
+		{ mode_info_get_mode_context(ModeInfo1, ModeContext) },
+		{ ImpurityError = mode_error_info(Vars, ModeError,
+					Context, ModeContext) },
+		{ ImpurityErrors = [ImpurityError | ImpurityErrors0] }
+	).
+
+	
+:- pred no_non_headvar_unification_goals(list(delayed_goal), list(var)).
+:- mode no_non_headvar_unification_goals(in, in) is semidet.
+
+no_non_headvar_unification_goals([], _).
+no_non_headvar_unification_goals([delayed_goal(_,_,Goal-_)|Goals], HeadVars) :-
+	Goal = unify(Var,Rhs,_,_,_),
+	(   member(Var, HeadVars)
+	;   Rhs = var(OtherVar),
+	    member(OtherVar, HeadVars)
+	),
+	no_non_headvar_unification_goals(Goals, HeadVars).
+
 :- pred dcg_set_state(T, T, T).
 :- mode dcg_set_state(in, in, out) is det.
 
@@ -1191,8 +1278,7 @@
 	modecheck_set_var_inst(Var0, InitialInst, FinalInst,
 				Var, ExtraGoals0, ExtraGoals1),
 	modecheck_set_var_inst_list_2(Vars0, InitialInsts, FinalInsts,
-				ExtraGoals1, Vars, ExtraGoals).
-
+ 				ExtraGoals1, Vars, ExtraGoals).
 :- pred modecheck_set_var_inst(var, inst, inst, var, extra_goals, extra_goals,
 				mode_info, mode_info).
 :- mode modecheck_set_var_inst(in, in, in, out, in, out,
@@ -1418,34 +1504,6 @@
 		% XXX could do better; it's not really explicit
 mode_context_to_unify_context(uninitialized, _, _) :-
 	error("mode_context_to_unify_context: uninitialized context").
-
-%-----------------------------------------------------------------------------%
-
-:- pred resolve_pred_overloading(pred_id, list(var), sym_name, sym_name,
-                                mode_info, pred_id).
-:- mode resolve_pred_overloading(in, in, in, out, mode_info_ui, out) is det.
-        %
-        % In the case of a call to an overloaded predicate, typecheck.m
-        % does not figure out the correct pred_id.  We must do that here.
-        %
-resolve_pred_overloading(PredId0, Args0, PredName0, PredName,
-                        ModeInfo0, PredId) :-
-        ( invalid_pred_id(PredId0) ->
-                %
-                % Find the set of candidate pred_ids for predicates which
-                % have the specified name and arity
-                %
-                mode_info_get_module_info(ModeInfo0, ModuleInfo0),
-                mode_info_get_predid(ModeInfo0, ThisPredId),
-                module_info_pred_info(ModuleInfo0, ThisPredId, PredInfo),
-                pred_info_typevarset(PredInfo, TVarSet),
-                mode_info_get_var_types(ModeInfo0, VarTypes0),
-                typecheck__resolve_pred_overloading(ModuleInfo0, Args0,
-                        VarTypes0, TVarSet, PredName0, PredName, PredId)
-        ;
-                PredId = PredId0,
-                PredName = PredName0
-        ).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: compiler/module_qual.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/module_qual.m,v
retrieving revision 1.24
diff -u -r1.24 module_qual.m
--- module_qual.m	1997/10/09 09:38:57	1.24
+++ module_qual.m	1997/11/14 01:00:10
@@ -131,8 +131,8 @@
 	add_mode_defn(ModeDefn, Info0, Info).
 collect_mq_info_2(module_defn(_, ModuleDefn), Info0, Info) :-
 	process_module_defn(ModuleDefn, Info0, Info).
-collect_mq_info_2(pred(_,_,_,_,_), Info, Info).
-collect_mq_info_2(func(_,_,_,_,_,_), Info, Info).
+collect_mq_info_2(pred(_,_,_,_,_,_), Info, Info).
+collect_mq_info_2(func(_,_,_,_,_,_,_), Info, Info).
 collect_mq_info_2(pred_mode(_,_,_,_,_), Info, Info).
 collect_mq_info_2(func_mode(_,_,_,_,_,_), Info, Info).
 collect_mq_info_2(pragma(_), Info, Info).
@@ -258,16 +258,17 @@
 		module_defn(A, ModuleDefn) - Context, Info0, Info, Continue) -->
 	{ update_import_status(ModuleDefn, Info0, Info, Continue) }.
 
-module_qualify_item(pred(A, SymName, TypesAndModes0, D, E) - Context,
-		pred(A, SymName, TypesAndModes, D, E) - Context,
+module_qualify_item(pred(A, SymName, TypesAndModes0, D, E, F) - Context,
+		pred(A, SymName, TypesAndModes, D, E, F) - Context,
 		Info0, Info, yes) -->
 	{ list__length(TypesAndModes0, Arity) },
 	{ mq_info_set_error_context(Info0, pred(SymName - Arity) - Context,
 								Info1) },
 	qualify_types_and_modes(TypesAndModes0, TypesAndModes, Info1, Info).
 
-module_qualify_item(func(A,SymName, TypesAndModes0, TypeAndMode0,D,E) - Context,
-		func(A, SymName, TypesAndModes, TypeAndMode, D, E) - Context,
+module_qualify_item(
+		func(A,SymName,TypesAndModes0,TypeAndMode0,D,E,F) - Context,
+		func(A,SymName,TypesAndModes,TypeAndMode,D,E,F) - Context,
 		Info0, Info, yes) -->
 	{ list__length(TypesAndModes0, Arity) },
 	{ mq_info_set_error_context(Info0, func(SymName - Arity) - Context,
@@ -608,6 +609,8 @@
 				Info, Info) --> [].
 qualify_pragma(fact_table(SymName, Arity, FileName),
 	fact_table(SymName, Arity, FileName), Info, Info) --> [].
+qualify_pragma(promise_pure(SymName, Arity), promise_pure(SymName, Arity),
+		Info, Info) --> [].
 qualify_pragma(termination_info(PredOrFunc, SymName, ModeList0, Termination), 
 		termination_info(PredOrFunc, SymName, ModeList, Termination), 
 		Info0, Info) --> 
Index: compiler/prog_data.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_data.m,v
retrieving revision 1.26
diff -u -r1.26 prog_data.m
--- prog_data.m	1997/10/09 09:39:05	1.26
+++ prog_data.m	1997/11/14 07:17:36
@@ -18,7 +18,7 @@
 
 :- interface.
 
-:- import_module hlds_data, hlds_pred, (inst).
+:- import_module hlds_data, hlds_pred, (inst), purity.
 :- import_module term_util, list, map, varset, term, std_util.
 
 %-----------------------------------------------------------------------------%
@@ -52,11 +52,11 @@
 	; 	module_defn(varset, module_defn)
 
 	; 	pred(varset, sym_name, list(type_and_mode),
-			maybe(determinism), condition)
+			maybe(determinism), condition, purity)
 		%     VarNames, PredName, ArgTypes, Deterministicness, Cond
 
 	; 	func(varset, sym_name, list(type_and_mode), type_and_mode,
-			maybe(determinism), condition)
+			maybe(determinism), condition, purity)
 		%       VarNames, PredName, ArgTypes, ReturnType,
 		%       Deterministicness, Cond
 
@@ -130,6 +130,9 @@
 	;	fact_table(sym_name, arity, string)
 			% Predname, Arity, Fact file name.
 
+	;	promise_pure(sym_name, arity)
+			% Predname, Arity
+
 	;	termination_info(pred_or_func, sym_name, list(mode),
 			termination)
 			% the list(mode) is the declared argmodes of the
@@ -191,7 +194,8 @@
 	;	if_then(vars,goal,goal)
 	;	if_then_else(vars,goal,goal,goal)
 	;	call(sym_name, list(term))
-	;	unify(term, term).
+	;	unify(term, term)
+	;	purity(goal,purity).
 
 :- type goals		==	list(goal).
 :- type vars		==	list(var).
Index: compiler/prog_io.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io.m,v
retrieving revision 1.165
diff -u -r1.165 prog_io.m
--- prog_io.m	1997/11/02 12:29:13	1.165
+++ prog_io.m	1997/11/14 01:10:14
@@ -100,6 +100,7 @@
 
 :- import_module prog_io_goal, prog_io_dcg, prog_io_pragma, prog_io_util.
 :- import_module hlds_data, hlds_pred, prog_util, globals, options, (inst).
+:- import_module purity.
 :- import_module bool, int, string, std_util, parser, term_io, dir, require.
 :- import_module varset, term.
 
@@ -514,11 +515,12 @@
 process_decl(ModuleName, VarSet, "type", [TypeDecl], Result) :-
 	parse_type_decl(ModuleName, VarSet, TypeDecl, Result).
 
+	%  If this clause is changed, also modify clause below for "impure."
 process_decl(ModuleName, VarSet, "pred", [PredDecl], Result) :-
-	parse_type_decl_pred(ModuleName, VarSet, PredDecl, Result).
+	parse_type_decl_pred(ModuleName, VarSet, PredDecl, pure, Result).
 
 process_decl(ModuleName, VarSet, "func", [FuncDecl], Result) :-
-	parse_type_decl_func(ModuleName, VarSet, FuncDecl, Result).
+	parse_type_decl_func(ModuleName, VarSet, FuncDecl, pure, Result).
 
 process_decl(ModuleName, VarSet, "mode", [ModeDecl], Result) :-
 	parse_mode_decl(ModuleName, VarSet, ModeDecl, Result).
@@ -661,6 +663,38 @@
 process_decl(ModuleName, VarSet, "pragma", Pragma, Result):-
 	parse_pragma(ModuleName, VarSet, Pragma, Result).
 
+	%  XXX I'm not very happy with this.  I believe this should
+	%  recursively call process_decl in order to process the pred or func
+	%  declaration.  The information that the pred/func decl is preceeded
+	%  by "impure" should be carried by another argument, which can be
+	%  generalised to a list of declared properties or attributes.  Then
+	%  each predicate for handling a declaration would have to handle
+	%  the list of properties, and complain about any invalid properties.
+	%  This is a more general solution, and avoids the code duplication of
+	%  the calls to parse_type_decl_{pred,func}.
+
+process_decl(ModuleName, VarSet, "impure", [Decl], Result):-
+	process_purity_decl(ModuleName, VarSet, (impure), Decl, Result).
+process_decl(ModuleName, VarSet, "semipure", [Decl], Result):-
+	process_purity_decl(ModuleName, VarSet, (semipure), Decl, Result).
+
+
+:- pred process_purity_decl(string, varset, purity, term, maybe1(item)).
+:- mode process_purity_decl(in, in, in, in, out) is det.
+
+process_purity_decl(ModuleName, VarSet, Purity, Decl, Result) :-
+	(   Decl = term__functor(term__atom("pred"), [PredDecl], _Context)
+	->	
+		    parse_type_decl_pred(ModuleName, VarSet,
+					 PredDecl, Purity, Result)
+% 	;   Decl = term__functor(term__atom("func"), [FuncDecl], _Context)
+% 	->	
+% 		    parse_type_decl_func(ModuleName, VarSet,
+% 					 FuncDecl, Purity, Result)
+	;   
+		Result = error("Invalid impurity declaration", Decl)
+	).
+
 :- pred parse_type_decl(string, varset, term, maybe1(item)).
 :- mode parse_type_decl(in, in, in, out) is det.
 parse_type_decl(ModuleName, VarSet, TypeDecl, Result) :-
@@ -729,43 +763,42 @@
 
 %-----------------------------------------------------------------------------%
 
-	% parse_type_decl_pred(Pred, Condition, Result) succeeds
-	% if Pred is a predicate type declaration, and binds Condition
-	% to the condition for that declaration (if any), and Result to
-	% a representation of the declaration.
-:- pred parse_type_decl_pred(string, varset, term, maybe1(item)).
-:- mode parse_type_decl_pred(in, in, in, out) is det.
+	% parse_type_decl_pred(ModuleName, VarSet, Pred, Purity, Result)
+	% succeeds if Pred is a predicate type declaration, and binds Result
+	% to a representation of the declaration.
+:- pred parse_type_decl_pred(string, varset, term, purity, maybe1(item)).
+:- mode parse_type_decl_pred(in, in, in, in, out) is det.
 
-parse_type_decl_pred(ModuleName, VarSet, Pred, R) :-
+parse_type_decl_pred(ModuleName, VarSet, Pred, Purity, R) :-
 	get_condition(Pred, Body, Condition),
 	get_determinism(Body, Body2, MaybeDeterminism),
         process_type_decl_pred(ModuleName, MaybeDeterminism, VarSet, Body2,
-                                Condition, R).
+                                Condition, Purity, R).
 
 :- pred process_type_decl_pred(string, maybe1(maybe(determinism)), varset,
-				term, condition, maybe1(item)).
-:- mode process_type_decl_pred(in, in, in, in, in, out) is det.
+				term, condition, purity, maybe1(item)).
+:- mode process_type_decl_pred(in, in, in, in, in, in, out) is det.
 
-process_type_decl_pred(_MNm, error(Term, Reason), _, _, _,
+process_type_decl_pred(_MNm, error(Term, Reason), _, _, _, _,
 			error(Term, Reason)).
 process_type_decl_pred(ModuleName, ok(MaybeDeterminism), VarSet, Body,
-			Condition, R) :-
-        process_pred(ModuleName, VarSet, Body, Condition, MaybeDeterminism, R).
+			Condition, Purity, R) :-
+        process_pred(ModuleName, VarSet, Body, Condition, MaybeDeterminism,
+		     Purity, R).
 
 %-----------------------------------------------------------------------------%
 
-	% parse_type_decl_func(Func, Condition, Result) succeeds
-	% if Func is a function type declaration, and binds Condition
-	% to the condition for that declaration (if any), and Result to
+	% parse_type_decl_func(ModuleName, Varset, Func, Purity, Result)
+	% succeeds if Func is a function type declaration, and binds Result to
 	% a representation of the declaration.
-:- pred parse_type_decl_func(string, varset, term, maybe1(item)).
-:- mode parse_type_decl_func(in, in, in, out) is det.
+:- pred parse_type_decl_func(string, varset, term, purity, maybe1(item)).
+:- mode parse_type_decl_func(in, in, in, in, out) is det.
 
-parse_type_decl_func(ModuleName, VarSet, Func, R) :-
+parse_type_decl_func(ModuleName, VarSet, Func, Purity, R) :-
 	get_condition(Func, Body, Condition),
 	get_determinism(Body, Body2, MaybeDeterminism),
-        process_maybe1_to_t(process_func(ModuleName, VarSet, Body2, Condition),
-				MaybeDeterminism, R).
+        process_maybe1_to_t(process_func(ModuleName, VarSet, Body2, Condition,
+					 Purity), MaybeDeterminism, R).
 
 %-----------------------------------------------------------------------------%
 
@@ -1079,25 +1112,26 @@
 	% parse a `:- pred p(...)' declaration
 
 :- pred process_pred(string, varset, term, condition, maybe(determinism),
-			maybe1(item)).
-:- mode process_pred(in, in, in, in, in, out) is det.
+			purity, maybe1(item)).
+:- mode process_pred(in, in, in, in, in, in, out) is det.
 
-process_pred(ModuleName, VarSet, PredType, Cond, MaybeDet, Result) :-
+process_pred(ModuleName, VarSet, PredType, Cond, MaybeDet, Purity, Result) :-
 	parse_qualified_term(ModuleName, PredType, PredType,
 		"`:- pred' declaration", R),
-	process_pred_2(R, PredType, VarSet, MaybeDet, Cond, Result).
+	process_pred_2(R, PredType, VarSet, MaybeDet, Cond, Purity, Result).
 
 :- pred process_pred_2(maybe_functor, term, varset, maybe(determinism),
-			condition, maybe1(item)).
-:- mode process_pred_2(in, in, in, in, in, out) is det.
-process_pred_2(ok(F, As0), PredType, VarSet, MaybeDet, Cond, Result) :-
+			condition, purity, maybe1(item)).
+:- mode process_pred_2(in, in, in, in, in, in, out) is det.
+process_pred_2(ok(F, As0), PredType, VarSet, MaybeDet, Cond, Purity, Result) :-
 	(
 		convert_type_and_mode_list(As0, As)
 	->
 		(
 			verify_type_and_mode_list(As)
 		->
-			Result = ok(pred(VarSet, F, As, MaybeDet, Cond))
+			Result = ok(pred(VarSet, F, As, MaybeDet, Cond,
+					 Purity))
 		;
 			Result = error("some but not all arguments have modes", PredType)
 		)
@@ -1105,7 +1139,7 @@
 		Result = error("syntax error in `:- pred' declaration",
 				PredType)
 	).
-process_pred_2(error(M, T), _, _, _, _, error(M, T)).
+process_pred_2(error(M, T), _, _, _, _, _, error(M, T)).
 
 %-----------------------------------------------------------------------------%
 
@@ -1137,11 +1171,11 @@
 
 	% parse a `:- func p(...)' declaration
 
-:- pred process_func(string, varset, term, condition, maybe(determinism),
-			maybe1(item)).
-:- mode process_func(in, in, in, in, in, out) is det.
+:- pred process_func(string, varset, term, condition, purity,
+			maybe(determinism), maybe1(item)).
+:- mode process_func(in, in, in, in, in, in, out) is det.
 
-process_func(ModuleName, VarSet, Term, Cond, MaybeDet, Result) :-
+process_func(ModuleName, VarSet, Term, Cond, Purity, MaybeDet, Result) :-
 	(
 		Term = term__functor(term__atom("="),
 				[FuncTerm, ReturnTypeTerm], _Context)
@@ -1149,16 +1183,16 @@
 		parse_qualified_term(ModuleName, FuncTerm, Term,
 			"`:- func' declaration", R),
 		process_func_2(R, FuncTerm, ReturnTypeTerm, VarSet, MaybeDet,
-				Cond, Result)
+				Cond, Purity, Result)
 	;
 		Result = error("`=' expected in `:- func' declaration", Term)
 	).
 
 :- pred process_func_2(maybe_functor, term, term, varset, maybe(determinism),
-			condition, maybe1(item)).
-:- mode process_func_2(in, in, in, in, in, in, out) is det.
+			condition, purity, maybe1(item)).
+:- mode process_func_2(in, in, in, in, in, in, in, out) is det.
 process_func_2(ok(F, As0), FuncTerm, ReturnTypeTerm, VarSet, MaybeDet, Cond,
-		Result) :-
+		Purity, Result) :-
 	( convert_type_and_mode_list(As0, As) ->
 		( \+ verify_type_and_mode_list(As) ->
 			Result = error("some but not all arguments have modes",
@@ -1187,7 +1221,7 @@
 					FuncTerm)
 			;
 				Result = ok(func(VarSet, F, As, ReturnType,
-					MaybeDet, Cond))
+					MaybeDet, Cond, Purity))
 			)
 		;
 			Result = error(
@@ -1199,7 +1233,7 @@
 			"syntax error in arguments of `:- func' declaration",
 					FuncTerm)
 	).
-process_func_2(error(M, T), _, _, _, _, _, error(M, T)).
+process_func_2(error(M, T), _, _, _, _, _, _, error(M, T)).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/prog_io_dcg.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_dcg.m,v
retrieving revision 1.7
diff -u -r1.7 prog_io_dcg.m
--- prog_io_dcg.m	1997/11/02 12:29:20	1.7
+++ prog_io_dcg.m	1997/11/14 00:32:38
@@ -32,7 +32,7 @@
 
 :- implementation.
 
-:- import_module prog_io_goal, prog_util, prog_data.
+:- import_module prog_io_goal, prog_util, prog_data, purity.
 :- import_module int, string, std_util, varset, list.
 
 %-----------------------------------------------------------------------------%
@@ -137,6 +137,12 @@
 parse_dcg_goal_2("{}", [G], _, VarSet0, N, Var,
 		Goal, VarSet, N, Var) :-
 	parse_goal(G, VarSet0, Goal, VarSet).
+parse_dcg_goal_2("impure", [G], Context, VarSet0, N0, Var0,
+		purity(Goal,(impure))-Context, VarSet, N, Var) :-
+	parse_dcg_goal(G, VarSet0, N0, Var0, Goal, VarSet, N, Var).
+parse_dcg_goal_2("semipure", [G], Context, VarSet0, N0, Var0,
+		purity(Goal,(semipure))-Context, VarSet, N, Var) :-
+	parse_dcg_goal(G, VarSet0, N0, Var0, Goal, VarSet, N, Var).
 
 	% Empty list - just unify the input and output DCG args.
 parse_dcg_goal_2("[]", [], Context, VarSet0, N0, Var0,
Index: compiler/prog_io_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_goal.m,v
retrieving revision 1.7
diff -u -r1.7 prog_io_goal.m
--- prog_io_goal.m	1997/11/02 12:29:22	1.7
+++ prog_io_goal.m	1997/11/14 00:32:39
@@ -113,7 +113,7 @@
 
 :- implementation.
 
-:- import_module hlds_data.
+:- import_module hlds_data, purity.
 :- import_module int, string, std_util.
 
 	% Parse a goal.
@@ -236,6 +236,10 @@
 	% but then `is/2' itself is a bit of a hack
 	%
 parse_goal_2("is", [A, B], V, unify(A, B), V).
+parse_goal_2("impure", [A0], V0, purity(A,(impure)), V) :-
+	parse_goal(A0, V0, A, V).
+parse_goal_2("semipure", [A0], V0, purity(A,(semipure)), V) :-
+	parse_goal(A0, V0, A, V).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.8
diff -u -r1.8 prog_io_pragma.m
--- prog_io_pragma.m	1997/11/02 12:29:23	1.8
+++ prog_io_pragma.m	1997/11/14 01:11:00
@@ -322,6 +322,13 @@
 		ErrorTerm)
 	).
 
+parse_pragma_type(ModuleName, "promise_pure", PragmaTerms,
+				ErrorTerm, _VarSet, Result) :-
+	parse_simple_pragma(ModuleName, "promise_pure",
+		lambda([Name::in, Arity::in, Pragma::out] is det,
+			Pragma = promise_pure(Name, Arity)),
+		PragmaTerms, ErrorTerm, Result).
+
 parse_pragma_type(ModuleName, "termination_info", PragmaTerms, ErrorTerm,
 	_VarSet, Result) :-
     (
@@ -429,6 +436,7 @@
 		lambda([Name::in, Arity::in, Pragma::out] is det,
 			Pragma = check_termination(Name, Arity)),
 		PragmaTerms, ErrorTerm, Result).
+
 
 :- pred parse_simple_pragma(module_name, string,
 			pred(sym_name, int, pragma_type),
Index: compiler/prog_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_util.m,v
retrieving revision 1.35
diff -u -r1.35 prog_util.m
--- prog_util.m	1997/07/27 15:01:32	1.35
+++ prog_util.m	1997/10/03 06:00:42
@@ -182,6 +182,10 @@
 		unify(TermA, TermB)) :-
 	term__substitute(TermA0, OldVar, term__variable(NewVar), TermA),
 	term__substitute(TermB0, OldVar, term__variable(NewVar), TermB).
+prog_util__rename_in_goal_expr(purity(Goal0, Purity), OldVar, NewVar,
+		purity(Goal, Purity)) :-
+	prog_util__rename_in_goal(Goal0, OldVar, NewVar, Goal).
+
 
 :- pred prog_util__rename_in_vars(list(var), var, var, list(var)).
 :- mode prog_util__rename_in_vars(in, in, in, out) is det.
Index: compiler/simplify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/simplify.m,v
retrieving revision 1.46
diff -u -r1.46 simplify.m
--- simplify.m	1997/09/01 14:04:39	1.46
+++ simplify.m	1997/11/06 07:31:14
@@ -65,7 +65,7 @@
 :- import_module code_aux, det_analysis, follow_code, goal_util, const_prop.
 :- import_module hlds_module, hlds_goal, hlds_data, (inst), inst_match.
 :- import_module globals, options, passes_aux, prog_data, mode_util, type_util.
-:- import_module code_util, quantification, modes.
+:- import_module code_util, quantification, modes, purity.
 :- import_module bool, list, set, map, require, std_util, term, varset, int.
 
 %-----------------------------------------------------------------------------%
@@ -171,6 +171,7 @@
 		% XXX we should warn about this (if the goal wasn't `fail')
 		%
 		Detism = failure,
+		\+ goal_info_is_impure(GoalInfo0),
 		( det_info_get_fully_strict(DetInfo, no)
 		; code_aux__goal_cannot_loop(ModuleInfo, Goal0)
 		)
@@ -194,6 +195,7 @@
 		simplify_info_get_instmap(Info0, InstMap0),
 		det_no_output_vars(NonLocalVars, InstMap0, InstMapDelta,
 			DetInfo),
+		\+ goal_info_is_impure(GoalInfo0),
 		( det_info_get_fully_strict(DetInfo, no)
 		; code_aux__goal_cannot_loop(ModuleInfo, Goal0)
 		)
@@ -503,10 +505,12 @@
 	%
 	% check for duplicate calls to the same procedure
 	%
-	( simplify_do_calls(Info2) ->
+	( simplify_do_calls(Info2),
+	  goal_info_is_pure(GoalInfo0) ->	
 		common__optimise_call(PredId, ProcId, Args, Goal0, GoalInfo0,
 			Goal1, Info2, Info3)
-	; simplify_do_warn_calls(Info0) ->
+	; simplify_do_warn_calls(Info0),
+	  goal_info_is_pure(GoalInfo0) ->
 		% we need to do the pass, for the warnings, but we ignore
 		% the optimized goal and instead use the original one
 		common__optimise_call(PredId, ProcId, Args, Goal0, GoalInfo0,
@@ -772,7 +776,8 @@
 
 simplify__goal_2(Goal0, GoalInfo, Goal, GoalInfo, Info0, Info) :-
 	Goal0 = pragma_c_code(_, _, PredId, ProcId, Args, _, _, _),
-	( simplify_do_calls(Info0) ->
+	( simplify_do_calls(Info0),
+	  goal_info_is_pure(GoalInfo) ->	
 		common__optimise_call(PredId, ProcId, Args, Goal0,
 			GoalInfo, Goal, Info0, Info)
 	;
@@ -1221,6 +1226,8 @@
 	(
 		simplify_do_warn(Info4),
 		Goal = _ - GoalInfo,
+		% don't warn about impure disjuncts that can't succeed
+		\+ goal_info_is_impure(GoalInfo),
 		goal_info_get_determinism(GoalInfo, Detism),
 		determinism_components(Detism, _, MaxSolns),
 		MaxSolns = at_most_zero
Index: compiler/special_pred.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/special_pred.m,v
retrieving revision 1.15
diff -u -r1.15 special_pred.m
--- special_pred.m	1997/07/27 15:01:38	1.15
+++ special_pred.m	1997/10/17 06:01:33
@@ -50,6 +50,9 @@
 :- pred special_pred_get_type(string, list(Type), Type).
 :- mode special_pred_get_type(in, in, out) is semidet.
 
+:- pred special_pred_description(special_pred_id, string).
+:- mode special_pred_description(in, out) is det.
+
 :- implementation.
 
 :- import_module type_util.
@@ -108,5 +111,10 @@
 	list__reverse(Types, [_, T | _]).
 special_pred_get_type("__Compare__", Types, T) :-
 	list__reverse(Types, [T | _]).
+
+
+special_pred_description(unify, "unification predicate").
+special_pred_description(compare, "comparison predicate").
+special_pred_description(index, "indexing predicate").
 
 %-----------------------------------------------------------------------------%
Index: compiler/typecheck.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/typecheck.m,v
retrieving revision 1.218
diff -u -r1.218 typecheck.m
--- typecheck.m	1997/11/13 06:27:30	1.218
+++ typecheck.m	1997/11/14 00:32:54
@@ -2899,16 +2899,17 @@
 	{ pred_info_arg_types(PredInfo, VarSet, Types0) },
 	{ strip_builtin_qualifiers_from_type_list(Types0, Types) },
 	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
+	{ pred_info_get_purity(PredInfo, Purity) },
 	{ MaybeDet = no },
 	prog_out__write_context(Context),
 	io__write_string("Inferred "),
 	(	{ PredOrFunc = predicate },
 		mercury_output_pred_type(VarSet, Name, Types, MaybeDet,
-			Context)
+			Purity, Context)
 	;	{ PredOrFunc = function },
 		{ pred_args_to_func_args(Types, ArgTypes, RetType) },
 		mercury_output_func_type(VarSet, Name, ArgTypes,
-			RetType, MaybeDet, Context)
+			RetType, MaybeDet, Purity, Context)
 	).
 
 %-----------------------------------------------------------------------------%
Index: compiler/notes/compiler_design.html
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.8
diff -u -r1.8 compiler_design.html
--- compiler_design.html	1997/11/08 13:12:08	1.8
+++ compiler_design.html	1997/11/14 00:33:06
@@ -211,6 +211,15 @@
 	  that are used in a variety of different places within the compiler
 	</ul>
 
+<dt> purity analysis
+	
+	<dd>
+	purity.m is responsible for purity checking, as well as
+	defining the <CODE>purity</CODE> type and a few public
+	operations on it.  It also completes the handling of predicate
+	and function overloading for cases which typecheck.m is unable
+	to handle.
+
 <dt> mode analysis
 
 	<dd>
================ end part 1/2 ================



More information about the developers mailing list