[m-dev.] for review: bug fix for mode analysis

Simon Taylor stayl at cs.mu.OZ.AU
Thu May 13 11:32:52 AEST 1999


Hi,

David Overton, could you please review this.

Thanks,
Simon.

Estimated hours taken: 10

Fix a code generator abort reported by Stephane Marie
<stephane.marie at detexis.thomson-csf.com>.

The bug was in the code to work out the instmap after a deconstruction
unification with complicated sub-unifications.
The instmap_delta for the unification contained only the bindings for
the first argument for which a new variable was created.

The test case now gives an error during mode analysis
rather than a code generator abort (for unifications procedures
of imported types) or a mode error during unique mode analysis
(for local types).

compiler/modes.m:
compiler/modecheck_call.m:
compiler/modecheck_unify.m:
	Simplify the code to handle extra goals by not attempting
	to bodge together the instmap after the main goal.
	Instead, the code now creates the extra unifications and
	rechecks the goal with the unifications added.

compiler/mode_info.m:
	Add a field to say whether we are reprocessing a goal after
	adding extra goals. Abort if the reprocessing adds more extra goals.

	The `may_changed_called_proc' field is now separate from
	the `how_to_check_goal' field. This is used to avoid
	repeating the search for the best procedure when rerunning
	mode analysis after adding the extra goals.

compiler/modecheck_unify.m:
	Removed predicate unify_vars - it is no longer used.

compiler/unify_proc.m:
	Call module_info_remove_predid if there are mode errors
	in a unification procedure to avoid spurious determinism
	errors.

tests/hard_coded/Mmakefile:
tests/hard_coded/partial_implied_mode.m:
tests/hard_coded/partial_implied_mode.err_exp:
	Test case. It would be nicer if the error message pointed
	to the unification which caused the unification procedure
	to be created, rather than the type declaration in the
	interface file.

Index: compiler/mode_info.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_info.m,v
retrieving revision 1.48
diff -u -u -r1.48 mode_info.m
--- mode_info.m	1998/11/20 04:08:27	1.48
+++ mode_info.m	1999/05/10 05:53:03
@@ -67,14 +67,16 @@
 	% modes.m or unique_modes.m.
 :- type how_to_check_goal
 	--->    check_modes
-	;       check_unique_modes(may_change_called_proc).
-
+	;       check_unique_modes
+	.
 	
-	% Is unique modes allowed to change which procedure of a predicate
+	% Is mode analysis allowed to change which procedure of a predicate
 	% is called. It may not change the called procedure after deforestation
 	% has performed a generalisation step, since that could result
 	% in selecting a less efficient mode, or one which doesn't even
 	% have the same termination behaviour.
+	% Also, when rechecking a goal after adding extra goals, it is
+	% not necessary to choose again which procedure is to be called.
 :- type may_change_called_proc
 	--->	may_change_called_proc
 	;	may_not_change_called_proc.
@@ -84,8 +86,10 @@
 :- type mode_info.
 
 :- pred mode_info_init(io__state, module_info, pred_id, proc_id, prog_context,
-		set(prog_var), instmap, how_to_check_goal, mode_info).
-:- mode mode_info_init(di, in, in, in, in, in, in, in, mode_info_uo) is det.
+		set(prog_var), instmap, how_to_check_goal,
+		may_change_called_proc, mode_info).
+:- mode mode_info_init(di, in, in, in, in, in, in, in, in,
+		mode_info_uo) is det.
 
 :- pred mode_info_get_io_state(mode_info, io__state).
 :- mode mode_info_get_io_state(mode_info_get_io_state, uo) is det.
@@ -261,6 +265,19 @@
 :- pred mode_info_set_how_to_check(how_to_check_goal, mode_info, mode_info).
 :- mode mode_info_set_how_to_check(in, mode_info_di, mode_info_uo) is det.
 
+:- pred mode_info_get_may_change_called_proc(mode_info,
+		may_change_called_proc).
+:- mode mode_info_get_may_change_called_proc(mode_info_ui, out) is det.
+
+:- pred mode_info_set_may_change_called_proc(may_change_called_proc,
+		mode_info, mode_info).
+:- mode mode_info_set_may_change_called_proc(in,
+		mode_info_di, mode_info_uo) is det.
+
+:- pred mode_info_set_checking_extra_goals(bool, mode_info, mode_info).
+:- mode mode_info_set_checking_extra_goals(in,
+		mode_info_di, mode_info_uo) is det.
+
 /*
 :- inst uniq_mode_info	=	bound_unique(
 					mode_info(
@@ -268,7 +285,8 @@
 						ground, ground, ground,
 						ground, ground, ground, ground,
 						ground, ground, ground, ground,
-						ground, ground, ground, ground
+						ground, ground, ground, ground,
+						ground
 					)
 				).
 */
@@ -287,7 +305,8 @@
 						dead, ground, ground, ground,
 						ground, ground, ground, ground,
 						ground, ground, ground, ground,
-						ground, ground, ground, ground
+						ground, ground, ground, ground,
+						ground
 					)
 				).
 */
@@ -377,7 +396,20 @@
 					% If `yes', then we may need
 					% to repeat mode inference.
 
-			how_to_check_goal
+			how_to_check_goal,
+
+			may_change_called_proc,
+					% Is mode analysis allowed
+					% to change which procedure
+					% is called?
+
+			bool		% Are we rechecking a goal after
+					% introducing unifications for
+					% complicated sub-unifications
+					% or an implied mode?
+					% If so, redoing the mode check
+					% should not introduce more
+					% extra unifications.
 		).
 
 	% The normal inst of a mode_info struct: ground, with
@@ -389,7 +421,7 @@
 	% Initialize the mode_info
 
 mode_info_init(IOState, ModuleInfo, PredId, ProcId, Context,
-		LiveVars, InstMapping0, HowToCheck, ModeInfo) :-
+		LiveVars, InstMapping0, HowToCheck, MayChangeProc, ModeInfo) :-
 	mode_context_init(ModeContext),
 	LockedVars = [],
 	delay_info__init(DelayInfo),
@@ -407,110 +439,121 @@
 
 	Changed = no,
 
+	CheckingExtraGoals = no,
+
 	ModeInfo = mode_info(
 		IOState, ModuleInfo, PredId, ProcId, VarSet, VarTypes,
 		Context, ModeContext, InstMapping0, LockedVars, DelayInfo,
 		ErrorList, LiveVarsList, NondetLiveVarsList, [], [],
-		Changed, HowToCheck
+		Changed, HowToCheck, MayChangeProc, CheckingExtraGoals
 	).
 
 %-----------------------------------------------------------------------------%
 
 	% Lots of very boring access predicates.
 
-mode_info_get_io_state(mode_info(IOState0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_io_state(
+		mode_info(IOState0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		IOState) :-
 	% XXX
 	unsafe_promise_unique(IOState0, IOState).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_io_state( mode_info(_,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R),
+mode_info_set_io_state(mode_info(_,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T),
 		IOState0,
-		mode_info(IOState,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)) :-
+		mode_info(IOState,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)) :-
 	% XXX
 	unsafe_promise_unique(IOState0, IOState).
 
 %-----------------------------------------------------------------------------%
 
 mode_info_get_module_info(
-	mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_), ModuleInfo).
+		mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+		ModuleInfo).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_module_info(mode_info(A,_,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R),
+mode_info_set_module_info(mode_info(A,_,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T),
 		ModuleInfo,
-		mode_info(A,ModuleInfo,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)).
+		mode_info(A,ModuleInfo,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_preds(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_preds(
+		mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		Preds) :-
 	module_info_preds(ModuleInfo, Preds).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_modes(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_modes(
+		mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		Modes) :-
 	module_info_modes(ModuleInfo, Modes).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_insts(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_insts(
+		mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		Insts) :-
 	module_info_insts(ModuleInfo, Insts).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_predid(mode_info(_,_,PredId,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_predid(mode_info(_,_,PredId,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		PredId).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_procid(mode_info(_,_,_,ProcId,_,_,_,_,_,_,_,_,_,_,_,_,_,_), 
+mode_info_get_procid(mode_info(_,_,_,ProcId,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_), 
 		ProcId).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_varset(mode_info(_,_,_,_,VarSet,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_varset(mode_info(_,_,_,_,VarSet,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		VarSet).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_varset(VarSet, mode_info(A,B,C,D,_,F,G,H,I,J,K,L,M,N,O,P,Q,R),
-			mode_info(A,B,C,D,VarSet,F,G,H,I,J,K,L,M,N,O,P,Q,R)).
+mode_info_set_varset(VarSet,
+		mode_info(A,B,C,D,_,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,VarSet,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_var_types(mode_info(_,_,_,_,_,VarTypes,_,_,_,_,_,_,_,_,_,_,_,_),
-				VarTypes).
+mode_info_get_var_types(
+		mode_info(_,_,_,_,_,VarTypes,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+		VarTypes).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_var_types(VTypes, mode_info(A,B,C,D,E,_,G,H,I,J,K,L,M,N,O,P,Q,R),
-			mode_info(A,B,C,D,E,VTypes,G,H,I,J,K,L,M,N,O,P,Q,R)).
+mode_info_set_var_types(VTypes,
+		mode_info(A,B,C,D,E,_,G,H,I,J,K,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,VTypes,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_context(mode_info(_,_,_,_,_,_,Context,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_context(mode_info(_,_,_,_,_,_,Context,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		Context).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_context(Context, mode_info(A,B,C,D,E,F,_,H,I,J,K,L,M,N,O,P,Q,R),
-			mode_info(A,B,C,D,E,F,Context,H,I,J,K,L,M,N,O,P,Q,R)).
+mode_info_set_context(Context,
+		mode_info(A,B,C,D,E,F,_,H,I,J,K,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,Context,H,I,J,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
 mode_info_get_mode_context(
-		mode_info(_,_,_,_,_,_,_,ModeContext,_,_,_,_,_,_,_,_,_,_),
+		mode_info(_,_,_,_,_,_,_,ModeContext,_,_,_,_,_,_,_,_,_,_,_,_),
 		ModeContext).
 
 %-----------------------------------------------------------------------------%
 
 mode_info_set_mode_context(ModeContext,
-		mode_info(A,B,C,D,E,F,G,_,I,J,K,L,M,N,O,P,Q,R),
-		mode_info(A,B,C,D,E,F,G,ModeContext,I,J,K,L,M,N,O,P,Q,R)).
+		mode_info(A,B,C,D,E,F,G,_,I,J,K,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,G,ModeContext,I,J,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
@@ -539,7 +582,7 @@
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_instmap(mode_info(_,_,_,_,_,_,_,_,InstMap,_,_,_,_,_,_,_,_,_),
+mode_info_get_instmap(mode_info(_,_,_,_,_,_,_,_,InstMap,_,_,_,_,_,_,_,_,_,_,_),
 		InstMap).
 
 	% mode_info_dcg_get_instmap/3 is the same as mode_info_get_instmap/2
@@ -551,8 +594,10 @@
 %-----------------------------------------------------------------------------%
 
 mode_info_set_instmap( InstMap,
-		mode_info(A,B,C,D,E,F,G,H,InstMap0,J,DelayInfo0,L,M,N,O,P,Q,R),
-		mode_info(A,B,C,D,E,F,G,H,InstMap,J,DelayInfo,L,M,N,O,P,Q,R)) :-
+		mode_info(A,B,C,D,E,F,G,H,InstMap0,J,
+			DelayInfo0,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,G,H,InstMap,J,
+			DelayInfo,L,M,N,O,P,Q,R,S,T)) :-
 	( instmap__is_unreachable(InstMap), instmap__is_reachable(InstMap0) ->
 		delay_info__bind_all_vars(DelayInfo0, DelayInfo)
 	;
@@ -562,29 +607,32 @@
 %-----------------------------------------------------------------------------%
 
 mode_info_get_locked_vars(
-		mode_info(_,_,_,_,_,_,_,_,_,LockedVars,_,_,_,_,_,_,_,_),
+		mode_info(_,_,_,_,_,_,_,_,_,LockedVars,_,_,_,_,_,_,_,_,_,_),
 		LockedVars).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_locked_vars( mode_info(A,B,C,D,E,F,G,H,I,_,K,L,M,N,O,P,Q,R),
-	LockedVars, mode_info(A,B,C,D,E,F,G,H,I,LockedVars,K,L,M,N,O,P,Q,R)).
+mode_info_set_locked_vars( mode_info(A,B,C,D,E,F,G,H,I,_,K,L,M,N,O,P,Q,R,S,T),
+	LockedVars,
+	mode_info(A,B,C,D,E,F,G,H,I,LockedVars,K,L,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_,_),
+mode_info_get_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_,_,_,_),
 		Errors).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_num_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_,_),
+mode_info_get_num_errors(
+		mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_,_,_,_),
 		NumErrors) :-
 	list__length(Errors, NumErrors).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_errors( Errors, mode_info(A,B,C,D,E,F,G,H,I,J,K,_,M,N,O,P,Q,R), 
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,Errors,M,N,O,P,Q,R)).
+mode_info_set_errors(Errors,
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,_,M,N,O,P,Q,R,S,T), 
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,Errors,M,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
@@ -598,9 +646,9 @@
 
 mode_info_add_live_vars(NewLiveVars,
 		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-			LiveVars0,NondetLiveVars0,O,P,Q,R),
+			LiveVars0,NondetLiveVars0,O,P,Q,R,S,T),
 		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-			LiveVars,NondetLiveVars,O,P,Q,R)) :-
+			LiveVars,NondetLiveVars,O,P,Q,R,S,T)) :-
 
 	LiveVars = [NewLiveVars | LiveVars0],
 	NondetLiveVars = [NewLiveVars | NondetLiveVars0].
@@ -610,9 +658,9 @@
 
 mode_info_remove_live_vars(OldLiveVars, ModeInfo0, ModeInfo) :-
 	ModeInfo0 = mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-				LiveVars0, NondetLiveVars0,O,P,Q,R),
+				LiveVars0, NondetLiveVars0,O,P,Q,R,S,T),
 	ModeInfo1 = mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-				LiveVars, NondetLiveVars,O,P,Q,R),
+				LiveVars, NondetLiveVars,O,P,Q,R,S,T),
 	(
 		list__delete_first(LiveVars0, OldLiveVars, LiveVars1),
 		list__delete_first(NondetLiveVars0, OldLiveVars,
@@ -639,7 +687,8 @@
 
 	% Check whether a variable is live or not
 
-mode_info_var_is_live(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_,_,_),
+mode_info_var_is_live(
+		mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_,_,_,_,_),
 		Var, Result) :-
 	(
 		% some [LiveVars] 
@@ -654,7 +703,7 @@
 	% Check whether a variable is nondet_live or not.
 
 mode_info_var_is_nondet_live(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,
-		NondetLiveVarsList,_,_,_,_), Var, Result) :-
+		NondetLiveVarsList,_,_,_,_,_,_), Var, Result) :-
 	(
 		% some [LiveVars] 
 		list__member(LiveVars, NondetLiveVarsList),
@@ -666,7 +715,7 @@
 	).
 
 mode_info_get_liveness(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,
-		_,_,_,_,_), LiveVars) :-
+		_,_,_,_,_,_,_), LiveVars) :-
 	set__init(LiveVars0),
 	mode_info_get_liveness_2(LiveVarsList, LiveVars0, LiveVars).
 
@@ -676,11 +725,11 @@
 	mode_info_get_liveness_2(LiveVarsList, LiveVars1, LiveVars).
 
 mode_info_get_live_vars(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,
-		_,_,_,_,_), LiveVarsList).
+		_,_,_,_,_,_,_), LiveVarsList).
 
 mode_info_set_live_vars(LiveVarsList,
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,_,N,O,P,Q,R),
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,LiveVarsList,N,O,P,Q,R)).
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,_,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,LiveVarsList,N,O,P,Q,R,S,T)).
 
 %-----------------------------------------------------------------------------%
 
@@ -733,47 +782,72 @@
 		mode_info_var_is_locked_2(Sets, Var, Reason)
 	).
 
-mode_info_get_delay_info(mode_info(_,_,_,_,_,_,_,_,_,_,DelayInfo,_,_,_,_,_,_,_),
-	DelayInfo).
+mode_info_get_delay_info(
+		mode_info(_,_,_,_,_,_,_,_,_,_,DelayInfo,_,_,_,_,_,_,_,_,_),
+		DelayInfo).
 
 mode_info_set_delay_info(DelayInfo,
-		mode_info(A,B,C,D,E,F,G,H,I,J,_,L,M,N,O,P,Q,R),
-		mode_info(A,B,C,D,E,F,G,H,I,J,DelayInfo,L,M,N,O,P,Q,R)).
+		mode_info(A,B,C,D,E,F,G,H,I,J,_,L,M,N,O,P,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,DelayInfo,L,M,N,O,P,Q,R,S,T)).
 
 mode_info_get_nondet_live_vars(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,
-			NondetLiveVars,_,_,_,_), NondetLiveVars).
+			NondetLiveVars,_,_,_,_,_,_), NondetLiveVars).
 
 mode_info_set_nondet_live_vars(NondetLiveVars,
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,_,O,P,Q,R),
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,NondetLiveVars,O,P,Q,R)).
+	mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,_,O,P,Q,R,S,T),
+	mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,NondetLiveVars,O,P,Q,R,S,T)).
 
 mode_info_get_last_checkpoint_insts(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,
-		LastCheckpointInsts,_,_,_), LastCheckpointInsts).
+		LastCheckpointInsts,_,_,_,_,_), LastCheckpointInsts).
 
 mode_info_set_last_checkpoint_insts(LastCheckpointInsts,
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,_,P,Q,R),
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,_,P,Q,R,S,T),
 			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,
-				LastCheckpointInsts,P,Q,R)).
+				LastCheckpointInsts,P,Q,R,S,T)).
 
 mode_info_get_parallel_vars(PVars, ModeInfo, ModeInfo) :-
-	ModeInfo = mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,PVars,_,_).
+	ModeInfo = mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,PVars,_,_,_,_).
 
 mode_info_set_parallel_vars(PVars,
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,_,Q,R),
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,PVars,Q,R)).
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,_,Q,R,S,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,PVars,Q,R,S,T)).
 
-mode_info_get_changed_flag(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Changed,_),
-				Changed).
+mode_info_get_changed_flag(
+		mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Changed,_,_,_),
+		Changed).
 
 mode_info_set_changed_flag(Changed,
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,_,R),
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Changed,R)).
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,_,R,S,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Changed,R,S,T)).
 
-mode_info_get_how_to_check(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,How),
+mode_info_get_how_to_check(
+		mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,How,_,_),
 		How).
 
-mode_info_set_how_to_check(How, mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,_),
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,How)).
+mode_info_set_how_to_check(How,
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,_,S,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,How,S,T)).
+
+mode_info_get_may_change_called_proc(
+		mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,MayChange,_),
+		MayChange).
+
+mode_info_set_may_change_called_proc(MayChange,
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,_,T),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,MayChange,T)).
+
+mode_info_set_checking_extra_goals(Checking,
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,Checking0),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,Checking)) :-
+	( Checking0 = yes, Checking = yes ->
+		% This should never happen - once the extra goals are
+		% introduced, rechecking the goal should not introduce
+		% more extra goals.
+		error(
+		"mode analysis: rechecking extra goals adds more extra goals")
+	;
+		true
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/modecheck_call.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modecheck_call.m,v
retrieving revision 1.27
diff -u -u -r1.27 modecheck_call.m
--- modecheck_call.m	1998/11/20 04:08:30	1.27
+++ modecheck_call.m	1999/05/10 05:53:04
@@ -25,16 +25,17 @@
 :- import_module prog_data, modes, mode_info.
 :- import_module list, std_util.
 
-:- pred modecheck_call_pred(pred_id, list(prog_var), maybe(determinism),
-		proc_id, list(prog_var), extra_goals, mode_info, mode_info).
-:- mode modecheck_call_pred(in, in, in, out, out, out,
-				mode_info_di, mode_info_uo) is det.
+:- pred modecheck_call_pred(pred_id, proc_id, list(prog_var),
+		maybe(determinism), proc_id, list(prog_var),
+		extra_goals, mode_info, mode_info).
+:- mode modecheck_call_pred(in, in, in, in, out, out, out,
+		mode_info_di, mode_info_uo) is det.
 
 :- pred modecheck_higher_order_call(pred_or_func, prog_var, list(prog_var),
 		list(type), list(mode), determinism, list(prog_var),
 		extra_goals, mode_info, mode_info).
 :- mode modecheck_higher_order_call(in, in, in, out, out, out, out, out,
-				mode_info_di, mode_info_uo) is det.
+		mode_info_di, mode_info_uo) is det.
 
 :- pred modecheck_higher_order_pred_call(prog_var, list(prog_var), pred_or_func,
 		hlds_goal_info, hlds_goal_expr, mode_info, mode_info).
@@ -88,12 +89,11 @@
 	modecheck_higher_order_call(PredOrFunc, PredVar, Args0,
 			Types, Modes, Det, Args, ExtraGoals),
 
-	=(ModeInfo),
 	{ Call = higher_order_call(PredVar, Args, Types, Modes, Det,
 			PredOrFunc) },
-	{ handle_extra_goals(Call, ExtraGoals, GoalInfo0,
+	handle_extra_goals(Call, ExtraGoals, GoalInfo0,
 			[PredVar | Args0], [PredVar | Args],
-			InstMap0, ModeInfo, Goal) },
+			InstMap0, Goal),
 	mode_info_unset_call_context,
 	mode_checkpoint(exit, "higher-order predicate call").
 
@@ -108,12 +108,11 @@
 	modecheck_higher_order_call(function, FuncVar, Args1,
 			Types, Modes, Det, Args, ExtraGoals),
 
-	=(ModeInfo),
 	{ Call = higher_order_call(FuncVar, Args, Types, Modes, Det,
 				function) },
-	{ handle_extra_goals(Call, ExtraGoals, GoalInfo0,
-				[FuncVar | Args1], [FuncVar | Args],
-				InstMap0, ModeInfo, Goal) },
+	handle_extra_goals(Call, ExtraGoals, GoalInfo0,
+			[FuncVar | Args1], [FuncVar | Args],
+			InstMap0, Goal),
 
 	mode_info_unset_call_context,
 	mode_checkpoint(exit, "higher-order function call").
@@ -178,17 +177,29 @@
 		ExtraGoals = no_extra_goals
 	).
 
-modecheck_call_pred(PredId, ArgVars0, DeterminismKnown,
+modecheck_call_pred(PredId, ProcId0, ArgVars0, DeterminismKnown,
 		TheProcId, ArgVars, ExtraGoals, ModeInfo0, ModeInfo) :-
 
-		% Get the list of different possible modes for the called
-		% predicate
+	mode_info_get_may_change_called_proc(ModeInfo0, MayChangeCalledProc),
+
 	mode_info_get_preds(ModeInfo0, Preds),
 	mode_info_get_module_info(ModeInfo0, ModuleInfo),
 	map__lookup(Preds, PredId, PredInfo0),
 	maybe_add_default_mode(ModuleInfo, PredInfo0, PredInfo, _),
 	pred_info_procedures(PredInfo, Procs),
-	map__keys(Procs, ProcIds),
+
+	( MayChangeCalledProc = may_not_change_called_proc ->
+		( invalid_proc_id(ProcId0) ->
+			error("modecheck_call_pred: invalid proc_id")
+		;
+			ProcIds = [ProcId0]
+		)
+	;
+			% Get the list of different possible
+			% modes for the called predicate
+		map__keys(Procs, ProcIds)
+	),
+
 	pred_info_get_markers(PredInfo, Markers),
 
 		% In order to give better diagnostics, we handle the
@@ -206,7 +217,9 @@
 		ExtraGoals = no_extra_goals
 	;
 		ProcIds = [ProcId],
-		\+ check_marker(Markers, infer_modes)
+		( \+ check_marker(Markers, infer_modes)
+		; MayChangeCalledProc = may_not_change_called_proc
+		)
 	->
 		TheProcId = ProcId,
 		map__lookup(Procs, ProcId, ProcInfo),
Index: compiler/modecheck_unify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modecheck_unify.m,v
retrieving revision 1.36
diff -u -u -r1.36 modecheck_unify.m
--- modecheck_unify.m	1998/11/20 04:08:31	1.36
+++ modecheck_unify.m	1999/05/10 06:11:41
@@ -21,7 +21,7 @@
 :- interface.
 
 :- import_module hlds_goal, hlds_data, prog_data, mode_info.
-:- import_module map, list.
+:- import_module map.
 
 	% Modecheck a unification
 :- pred modecheck_unification(prog_var, unify_rhs, unification, unify_context,
@@ -36,13 +36,12 @@
 :- mode categorize_unify_var_var(in, in, in, in, in, in, in, in, in,
 			mode_info_di, out, mode_info_uo) is det.
 
-	% Given a unification goal, which must be something that can be
-	% returned from categorize_unify_var_var (i.e.  a unification
-	% of two vars, a unification of a var and a functor, or a
-	% conjunction thereof), return a list of all the variables in the
-	% goal.
-:- pred unify_vars(hlds_goal_expr, list(prog_var)).
-:- mode unify_vars(in, out) is det.
+	% Create a unification between the two given variables.
+	% The goal's mode and determinism information is not filled in.
+:- pred modecheck_unify__create_var_var_unification(prog_var, prog_var,
+		mode_info, hlds_goal).
+:- mode modecheck_unify__create_var_var_unification(in, in,
+		mode_info_ui, out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -53,11 +52,11 @@
 :- import_module hlds_module, hlds_goal, hlds_pred, hlds_out.
 :- import_module mode_debug, mode_util, mode_info, modes, mode_errors.
 :- import_module inst_match, inst_util, unify_proc, code_util, unique_modes.
-:- import_module typecheck, modecheck_call, (inst), quantification.
-:- import_module term, varset.
+:- import_module typecheck, modecheck_call, (inst), quantification, make_hlds.
 
-:- import_module bool, std_util, int, set, require.
+:- import_module bool, list, std_util, int, set, require.
 :- import_module string, assoc_list.
+:- import_module term, varset.
 
 %-----------------------------------------------------------------------------%
 
@@ -126,7 +125,7 @@
 		% then don't bother checking, since they will have already
 		% been expanded.)
 		%
-		HowToCheckGoal \= check_unique_modes(_),
+		HowToCheckGoal \= check_unique_modes,
 		ConsId0 = cons(unqualified(ApplyName), _),
 		( ApplyName = "apply" ; ApplyName = "" ),
 		Arity >= 1,
@@ -150,7 +149,7 @@
 		% As an optimization, if HowToCheck = check_unique_modes,
 		% then don't bother checking, since they will have already
 		% been expanded.
-		HowToCheckGoal \= check_unique_modes(_),
+		HowToCheckGoal \= check_unique_modes,
 
 		% Find the set of candidate predicates which have the
 		% specified name and arity (and module, if module-qualified)
@@ -451,7 +450,7 @@
 		% if we're being called from unique_modes.m, then we need to 
 		% call unique_modes__check_goal rather than modecheck_goal.
 		(
-			HowToCheckGoal = check_unique_modes(_)
+			HowToCheckGoal = check_unique_modes
 		->
 			unique_modes__check_goal(Goal0, Goal, ModeInfo6,
 				ModeInfo7)
@@ -566,7 +565,8 @@
 			out, mode_info_di, mode_info_uo) is det.
 
 modecheck_unify_functor(X, TypeOfX, ConsId0, ArgVars0, Unification0,
-			UnifyContext, GoalInfo0, Goal, ModeInfo0, ModeInfo) :-
+			UnifyContext, GoalInfo0, Goal, ModeInfo0,
+			FinalModeInfo) :-
 	mode_info_get_module_info(ModeInfo0, ModuleInfo0),
 	mode_info_get_how_to_check(ModeInfo0, HowToCheckGoal),
 
@@ -705,18 +705,20 @@
 		Unification = construct(ConstructTarget, _, _, _),
 		mode_info_var_is_live(ModeInfo, ConstructTarget, dead)
 	->
-		Goal = conj([])
+		Goal = conj([]),
+		FinalModeInfo = ModeInfo
 	;
 		Det = failure
 	->
 		% This optimisation is safe because the only way that
 		% we can analyse a unification as having no solutions
 		% is that the unification always fails.
-		%
+		%,
 		% Unifying two preds is not erroneous as far as the
 		% mode checker is concerned, but a mode _error_.
 		map__init(Empty),
-		Goal = disj([], Empty)
+		Goal = disj([], Empty),
+		FinalModeInfo = ModeInfo
 	;
 		Functor = functor(ConsId, ArgVars),
 		Unify = unify(X, Functor, Mode, Unification,
@@ -732,7 +734,7 @@
 		% wouldn't have the correct determinism annotations.)
 		%
 		(
-			HowToCheckGoal = check_unique_modes(_),
+			HowToCheckGoal = check_unique_modes,
 			ExtraGoals \= no_extra_goals,
 			instmap__is_reachable(InstMap0)
 		->
@@ -741,8 +743,8 @@
 			true
 		),
 		handle_extra_goals(Unify, ExtraGoals, GoalInfo0,
-					[X0|ArgVars0], [X|ArgVars],
-					InstMap0, ModeInfo, Goal)
+			[X0|ArgVars0], [X|ArgVars],
+			InstMap0, Goal, ModeInfo, FinalModeInfo)
 	).
 
 %-----------------------------------------------------------------------------%
@@ -766,12 +768,12 @@
 	->
 		(
 			split_complicated_subunifies_2(ArgVars0, ArgModes0,
-				ArgVars1, ArgModes, ExtraGoals1)
+				ArgVars1, ExtraGoals1)
 		->
+			{ ExtraGoals = ExtraGoals1 },
 			{ ArgVars = ArgVars1 },
 			{ Unification = deconstruct(X, ConsId, ArgVars,
-							ArgModes, Det) },
-			{ ExtraGoals = ExtraGoals1 }
+							ArgModes0, Det) }
 		;
 			{ error("split_complicated_subunifies_2 failed") }
 		)
@@ -782,14 +784,13 @@
 	).
 
 :- pred split_complicated_subunifies_2(list(prog_var), list(uni_mode),
-		list(prog_var), list(uni_mode), extra_goals,
-		mode_info, mode_info).
-:- mode split_complicated_subunifies_2(in, in, out, out, out,
+		list(prog_var), extra_goals, mode_info, mode_info).
+:- mode split_complicated_subunifies_2(in, in, out, out,
 			mode_info_di, mode_info_uo) is semidet.
 
-split_complicated_subunifies_2([], [], [], [], no_extra_goals) --> [].
+split_complicated_subunifies_2([], [], [], no_extra_goals) --> [].
 split_complicated_subunifies_2([Var0 | Vars0], [UniMode0 | UniModes0],
-			Vars, UniModes, ExtraGoals, ModeInfo0, ModeInfo) :-
+			Vars, ExtraGoals, ModeInfo0, ModeInfo) :-
 	mode_info_get_module_info(ModeInfo0, ModuleInfo),
 	UniMode0 = (InitialInstX - InitialInstY -> FinalInstX - FinalInstY),
 	ModeX = (InitialInstX -> FinalInstX),
@@ -808,78 +809,42 @@
 		mode_info_set_varset(VarSet, ModeInfo0, ModeInfo1),
 		mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo2),
 
-		% change the main unification to use `Var' instead of Var0
-		UniMode = (InitialInstX - free -> InitialInstX - InitialInstX),
-
-		% Compute the instmap that results after the main unification.
-		% We just need to set the inst of `Var'.
-		mode_info_get_instmap(ModeInfo2, OrigInstMap),
-		instmap__set(OrigInstMap, Var, InitialInstX, InstMapAfterMain),
-		mode_info_set_instmap(InstMapAfterMain, ModeInfo2, ModeInfo3),
-
-		% create code to do a unification between `Var' and `Var0'
-		ModeVar0 = (InitialInstY -> FinalInstY),
-		ModeVar = (InitialInstX -> FinalInstX),
-
-		mode_info_get_module_info(ModeInfo3, ModuleInfo0),
-		(
-			abstractly_unify_inst(dead, InitialInstX, InitialInstY,
-				real_unify, ModuleInfo0, _, Det1, ModuleInfo1)
-		->
-			mode_info_set_module_info(ModeInfo3, ModuleInfo1,
-				ModeInfo4),
-			Det = Det1
-		;
-			ModeInfo4 = ModeInfo3,
-			Det = semidet
-			% XXX warning - it might be det in some cases.
-			% should we report an error here?  should this
-			% ever happen?
-		),
-		mode_info_get_mode_context(ModeInfo4, ModeContext),
-		mode_context_to_unify_context(ModeContext, ModeInfo4,
-						UnifyContext),
-		categorize_unify_var_var(ModeVar0, ModeVar,
-			live, dead, Var0, Var, Det, UnifyContext,
-			VarTypes, ModeInfo4, NewUnifyGoal, ModeInfo5),
-		unify_vars(NewUnifyGoal, NewUnifyGoalVars),
-
-		% compute the goal_info nonlocal vars & instmap delta
-		% for the newly created goal
-		% N.B. This may overestimate the set of non-locals,
-		% but that shouldn't cause any problems.
-		set__list_to_set(NewUnifyGoalVars, NonLocals),
-		( InitialInstY = FinalInstY ->
-			InstMapDeltaAL0 = []
-		;
-			InstMapDeltaAL0 = [Var0 - FinalInstY]
-		),
-		InstMapDeltaAL = [Var - FinalInstX | InstMapDeltaAL0],
-		instmap_delta_from_assoc_list(InstMapDeltaAL, InstMapDelta),
-		goal_info_init(GoalInfo0),
-		goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo1),
-		goal_info_set_instmap_delta(GoalInfo1, InstMapDelta, GoalInfo),
+		modecheck_unify__create_var_var_unification(Var0, Var,
+			ModeInfo2, ExtraGoal),
 
 		% insert the new unification at
 		% the start of the extra goals
-		ExtraGoals0 = extra_goals([], after_goals(InstMapAfterMain,
-					[NewUnifyGoal - GoalInfo])),
+		ExtraGoals0 = extra_goals([], [ExtraGoal]),
 
 		% recursive call to handle the remaining variables...
 		split_complicated_subunifies_2(Vars0, UniModes0,
-				Vars1, UniModes1, ExtraGoals1,
-				ModeInfo5, ModeInfo),
+				Vars1, ExtraGoals1, ModeInfo2, ModeInfo),
 		Vars = [Var | Vars1],
-		UniModes = [UniMode | UniModes1],
 		append_extra_goals(ExtraGoals0, ExtraGoals1, ExtraGoals)
 	;
 		split_complicated_subunifies_2(Vars0, UniModes0,
-				Vars1, UniModes1, ExtraGoals,
-				ModeInfo0, ModeInfo),
-		Vars = [Var0 | Vars1],
-		UniModes = [UniMode0 | UniModes1]
+				Vars1, ExtraGoals, ModeInfo0, ModeInfo),
+		Vars = [Var0 | Vars1]
 	).
 
+modecheck_unify__create_var_var_unification(Var0, Var, ModeInfo,
+		ExtraGoal - GoalInfo) :-
+	mode_info_get_context(ModeInfo, Context),
+	mode_info_get_mode_context(ModeInfo, ModeContext),
+	mode_context_to_unify_context(ModeContext, ModeInfo, UnifyContext),
+	UnifyContext = unify_context(MainContext, SubContexts),
+	
+	create_atomic_unification(Var0, var(Var), Context,
+		MainContext, SubContexts, ExtraGoal - GoalInfo0),
+		
+	% compute the goal_info nonlocal vars
+	% for the newly created goal
+	% N.B. This may overestimate the set of non-locals,
+	% but that shouldn't cause any problems.
+	set__list_to_set([Var0, Var], NonLocals),
+	goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo1),
+	goal_info_set_context(GoalInfo1, Context, GoalInfo).
+
 %-----------------------------------------------------------------------------%
 
 % categorize_unify_var_var works out which category a unification
@@ -1265,36 +1230,6 @@
 	varset__new_var(VarSet0, Var, VarSet1),
 	map__det_insert(VarTypes0, Var, Type, VarTypes1),
 	make_fresh_vars(Types, VarSet1, VarTypes1, Vars, VarSet, VarTypes).
-
-%-----------------------------------------------------------------------------%
-
-	% Given a unification goal, which must be something that can be
-	% returned from categorize_unify_var_var (i.e. a unification
-	% of two vars, a unification of a var and a functor,
-	% an empty disjunction (fail), or a conjunction thereof),
-	% return a list of all the variables in the goal.
-unify_vars(Unify, UnifyVars) :-
-	( Unify = unify(LHS, RHS, _, _, _), RHS = var(RHS_Var) ->
-		UnifyVars = [LHS, RHS_Var]
-	; Unify = unify(LHS, RHS, _, _, _), RHS = functor(_, RHS_ArgVars) ->
-		UnifyVars = [LHS | RHS_ArgVars]
-	; Unify = conj(List) ->
-		unify_conj_vars(List, UnifyVars)
-	; Unify = disj([], _StoreMap) ->
-		UnifyVars = []
-	;
-		error("modecheck_unify: unify_vars")
-	).
-
-:- pred unify_conj_vars(list(hlds_goal), list(prog_var)).
-:- mode unify_conj_vars(in, out) is det.
-
-unify_conj_vars([], []).
-unify_conj_vars([Goal | Goals], Vars) :-
-	quantification__goal_vars(Goal, Vars1Set),
-	set__to_sorted_list(Vars1Set, Vars1),
-	unify_conj_vars(Goals, Vars2),
-	list__append(Vars1, Vars2, Vars).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: compiler/modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modes.m,v
retrieving revision 1.229
diff -u -u -r1.229 modes.m
--- modes.m	1999/04/16 08:07:54	1.229
+++ modes.m	1999/05/10 06:46:51
@@ -146,15 +146,15 @@
 
 	% Mode-check or unique-mode-check the code for all the predicates
 	% in a module.
-:- pred check_pred_modes(how_to_check_goal, module_info, module_info, bool,
-				io__state, io__state).
-:- mode check_pred_modes(in, in, out, out, di, uo) is det.
+:- pred check_pred_modes(how_to_check_goal, may_change_called_proc,				module_info, module_info, bool, io__state, io__state).
+:- mode check_pred_modes(in, in, in, out, out, di, uo) is det.
 
 	% Mode-check or unique-mode-check the code for single predicate.
 
 :- pred modecheck_pred_mode(pred_id, pred_info, how_to_check_goal,
-			module_info, module_info, int, io__state, io__state).
-:- mode modecheck_pred_mode(in, in, in, in, out, out, di, uo) is det.
+		may_change_called_proc, module_info, module_info,
+		int, io__state, io__state).
+:- mode modecheck_pred_mode(in, in, in, in, in, out, out, di, uo) is det.
 
 	% Mode-check the code for predicate in a given mode.
 	% Returns the number of errs found and a bool `Changed'
@@ -172,9 +172,9 @@
 	% may be needed.
 
 :- pred modecheck_proc(proc_id, pred_id, how_to_check_goal,
-			module_info, module_info, int, bool,
-			io__state, io__state).
-:- mode modecheck_proc(in, in, in, in, out, out, out, di, uo) is det.
+		may_change_called_proc, module_info, module_info, int, bool,
+		io__state, io__state).
+:- mode modecheck_proc(in, in, in, in, in, out, out, out, di, uo) is det.
 
 	% Mode-check the code for predicate in a given mode.
 
@@ -260,8 +260,9 @@
 	;	extra_goals(
 			list(hlds_goal),	% goals to insert before
 						% the main goal
-			after_goals		% goals to append after
+			list(hlds_goal)		% goals to append after
 						% the main goal
+				
 		).
 :- type after_goals
 	--->	no_after_goals
@@ -278,13 +279,14 @@
 :- mode append_extra_goals(in, in, out) is det.
 
 	% handle_extra_goals combines MainGoal and ExtraGoals into a single
-	% hlds_goal_expr.
+	% hlds_goal_expr, rerunning mode analysis on the entire
+	% conjunction if ExtraGoals is not empty.
 	%
 :- pred handle_extra_goals(hlds_goal_expr, extra_goals,
 		hlds_goal_info, list(prog_var), list(prog_var),
-		instmap, mode_info, hlds_goal_expr).
-:- mode handle_extra_goals(in, in, in, in, in, in, mode_info_ui, out)
-	is det.
+		instmap, hlds_goal_expr, mode_info, mode_info).
+:- mode handle_extra_goals(in, in, in, in, in, in, out,
+		mode_info_di, mode_info_uo) is det.
 
 :- pred mode_context_to_unify_context(mode_context, mode_info, unify_context).
 :- mode mode_context_to_unify_context(in, mode_info_ui, out) is det.
@@ -314,7 +316,8 @@
 	io__set_output_stream(StdErr, OldStream),
 
 	maybe_write_string(Verbose, "% Mode-checking clauses...\n"),
-	check_pred_modes(check_modes, Module0, Module, UnsafeToContinue),
+	check_pred_modes(check_modes, may_change_called_proc,
+		Module0, Module, UnsafeToContinue),
 	maybe_report_stats(Statistics),
 
 	io__set_output_stream(OldStream, _).
@@ -323,13 +326,15 @@
 	
 	% Mode-check the code for all the predicates in a module.
 
-check_pred_modes(WhatToCheck, ModuleInfo0, ModuleInfo, UnsafeToContinue) -->
+check_pred_modes(WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, ModuleInfo, UnsafeToContinue) -->
 	{ module_info_predids(ModuleInfo0, PredIds) },
 	globals__io_lookup_int_option(mode_inference_iteration_limit,
 		MaxIterations),
-	modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, ModuleInfo0,
-					ModuleInfo1, UnsafeToContinue),
-	( { WhatToCheck = check_unique_modes(_) },
+	modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck,
+		MayChangeCalledProc, ModuleInfo0, ModuleInfo1,
+		UnsafeToContinue),
+	( { WhatToCheck = check_unique_modes },
 		write_mode_inference_messages(PredIds, yes, ModuleInfo1),
 		{ ModuleInfo2 = ModuleInfo1 }
 	; { WhatToCheck = check_modes },
@@ -345,11 +350,12 @@
 	% Iterate over the list of pred_ids in a module.
 
 :- pred modecheck_to_fixpoint(list(pred_id), int, how_to_check_goal,
-			module_info, module_info, bool, io__state, io__state).
-:- mode modecheck_to_fixpoint(in, in, in, in, out, out, di, uo) is det.
+		may_change_called_proc, module_info, module_info,
+		bool, io__state, io__state).
+:- mode modecheck_to_fixpoint(in, in, in, in, in, out, out, di, uo) is det.
 
-modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, ModuleInfo0,
-		ModuleInfo, UnsafeToContinue) -->
+modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, ModuleInfo, UnsafeToContinue) -->
 	{ ModuleInfo1 = ModuleInfo0 },
 
 	% save the old procedure bodies so that we can restore them for the
@@ -357,13 +363,13 @@
 	{ module_info_preds(ModuleInfo0, OldPredTable0) },
 
 	% analyze everything which has the "can-process" flag set to `yes'
-	modecheck_pred_modes_2(PredIds, WhatToCheck, ModuleInfo1, ModuleInfo2,
-				no, Changed1, 0, NumErrors),
+	modecheck_pred_modes_2(PredIds, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo1, ModuleInfo2, no, Changed1, 0, NumErrors),
 
 	% analyze the procedures whose "can-process" flag was no;
 	% those procedures were inserted into the unify requests queue.
-	modecheck_queued_procs(WhatToCheck, OldPredTable0, ModuleInfo2,
-					OldPredTable, ModuleInfo3, Changed2),
+	modecheck_queued_procs(WhatToCheck, OldPredTable0,
+		ModuleInfo2, OldPredTable, ModuleInfo3, Changed2),
 	io__get_exit_status(ExitStatus),
 
 	{ bool__or(Changed1, Changed2, Changed) },
@@ -409,8 +415,8 @@
 			),
 			{ MaxIterations1 is MaxIterations - 1 },
 			modecheck_to_fixpoint(PredIds, MaxIterations1,
-				WhatToCheck, ModuleInfo4,
-				ModuleInfo, UnsafeToContinue)
+				WhatToCheck, MayChangeCalledProc,
+				ModuleInfo4, ModuleInfo, UnsafeToContinue)
 		)
 	).
 
@@ -469,15 +475,16 @@
 	map__set(ProcTable0, ProcId, ProcInfo, ProcTable).
 
 :- pred modecheck_pred_modes_2(list(pred_id), how_to_check_goal,
-			module_info, module_info, bool, bool, int, int,
-			io__state, io__state).
-:- mode modecheck_pred_modes_2(in, in, in, out, in, out, in, out, di, uo)
+		may_change_called_proc, module_info, module_info,
+		bool, bool, int, int, io__state, io__state).
+:- mode modecheck_pred_modes_2(in, in, in, in, out, in, out, in, out, di, uo)
 			is det.
 
-modecheck_pred_modes_2([], _, ModuleInfo, ModuleInfo, Changed, Changed,
+modecheck_pred_modes_2([], _, _, ModuleInfo, ModuleInfo, Changed, Changed,
 		NumErrors, NumErrors) --> [].
-modecheck_pred_modes_2([PredId | PredIds], WhatToCheck, ModuleInfo0, ModuleInfo,
-		Changed0, Changed, NumErrors0, NumErrors) -->
+modecheck_pred_modes_2([PredId | PredIds], WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, ModuleInfo, Changed0, Changed,
+		NumErrors0, NumErrors) -->
 	{ module_info_preds(ModuleInfo0, Preds0) },
 	{ map__lookup(Preds0, PredId, PredInfo0) },
 	( { pred_info_is_imported(PredInfo0) } ->
@@ -492,8 +499,8 @@
 		write_modes_progress_message(PredId, PredInfo0, ModuleInfo0,
 			WhatToCheck),
 		modecheck_pred_mode_2(PredId, PredInfo0, WhatToCheck,
-			ModuleInfo0, ModuleInfo1, Changed0, Changed1,
-			ErrsInThisPred),
+			MayChangeCalledProc, ModuleInfo0, ModuleInfo1,
+			Changed0, Changed1, ErrsInThisPred),
 		{ ErrsInThisPred = 0 ->
 			ModuleInfo3 = ModuleInfo1
 		;
@@ -506,8 +513,9 @@
 		},
 		{ NumErrors1 is NumErrors0 + ErrsInThisPred }
 	),
-	modecheck_pred_modes_2(PredIds, WhatToCheck, ModuleInfo3, ModuleInfo,
-		Changed1, Changed, NumErrors1, NumErrors).
+	modecheck_pred_modes_2(PredIds, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo3, ModuleInfo, Changed1, Changed,
+		NumErrors1, NumErrors).
 
 :- pred write_modes_progress_message(pred_id, pred_info, module_info,
 			how_to_check_goal, io__state, io__state).
@@ -519,7 +527,7 @@
 		(	{ WhatToCheck = check_modes },
 			write_pred_progress_message("% Mode-analysing ",
 				PredId, ModuleInfo)
-		;	{ WhatToCheck = check_unique_modes(_) },
+		;	{ WhatToCheck = check_unique_modes },
 			write_pred_progress_message("% Unique-mode-analysing ",
 				PredId, ModuleInfo)
 		)
@@ -527,7 +535,7 @@
 		(	{ WhatToCheck = check_modes },
 			write_pred_progress_message("% Mode-checking ",
 				PredId, ModuleInfo)
-		;	{ WhatToCheck = check_unique_modes(_) },
+		;	{ WhatToCheck = check_unique_modes },
 			write_pred_progress_message("% Unique-mode-checking ",
 				PredId, ModuleInfo)
 		)
@@ -537,18 +545,20 @@
 
 	% Mode-check the code for single predicate.
 
-modecheck_pred_mode(PredId, PredInfo0, WhatToCheck, ModuleInfo0,
-		ModuleInfo, NumErrors) -->
+modecheck_pred_mode(PredId, PredInfo0, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, ModuleInfo, NumErrors) -->
 	modecheck_pred_mode_2(PredId, PredInfo0, WhatToCheck,
-		ModuleInfo0, ModuleInfo, no, _Changed, NumErrors).
+		MayChangeCalledProc, ModuleInfo0, ModuleInfo,
+		no, _Changed, NumErrors).
 
 :- pred modecheck_pred_mode_2(pred_id, pred_info, how_to_check_goal,
-			module_info, module_info, bool, bool, int,
-			io__state, io__state).
-:- mode modecheck_pred_mode_2(in, in, in, in, out, in, out, out, di, uo) is det.
+		may_change_called_proc, module_info, module_info,
+		bool, bool, int, io__state, io__state).
+:- mode modecheck_pred_mode_2(in, in, in, in, in,
+		out, in, out, out, di, uo) is det.
 
-modecheck_pred_mode_2(PredId, PredInfo0, WhatToCheck, ModuleInfo0, ModuleInfo,
-		Changed0, Changed, NumErrors) -->
+modecheck_pred_mode_2(PredId, PredInfo0, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, ModuleInfo, Changed0, Changed, NumErrors) -->
 	{ pred_info_procedures(PredInfo0, Procs0) },
 	{ map__keys(Procs0, ProcIds) },
 	( { WhatToCheck = check_modes } ->
@@ -563,29 +573,30 @@
 	;
 		{ NumErrors0 = 0 }
 	),
-	modecheck_procs(ProcIds, PredId, WhatToCheck,
+	modecheck_procs(ProcIds, PredId, WhatToCheck, MayChangeCalledProc,
 				ModuleInfo0, Changed0, NumErrors0,
 				ModuleInfo, Changed, NumErrors).
 
 	% Iterate over the list of modes for a predicate.
 
 :- pred modecheck_procs(list(proc_id), pred_id, how_to_check_goal,
-				module_info, bool, int,
-				module_info, bool, int, io__state, io__state).
-:- mode modecheck_procs(in, in, in, in, in, in, out, out, out, di, uo) is det.
+		may_change_called_proc, module_info, bool, int,
+		module_info, bool, int, io__state, io__state).
+:- mode modecheck_procs(in, in, in, in, in, in, in,
+		out, out, out, di, uo) is det.
 
-modecheck_procs([], _PredId,  _, ModuleInfo, Changed, Errs,
+modecheck_procs([], _PredId, _, _, ModuleInfo, Changed, Errs,
 				ModuleInfo, Changed, Errs) --> [].
-modecheck_procs([ProcId|ProcIds], PredId, WhatToCheck,
+modecheck_procs([ProcId|ProcIds], PredId, WhatToCheck, MayChangeCalledProc,
 				ModuleInfo0, Changed0, Errs0,
 				ModuleInfo, Changed, Errs) -->
 	% mode-check that mode of the predicate
-	modecheck_proc_2(ProcId, PredId, WhatToCheck,
+	modecheck_proc_2(ProcId, PredId, WhatToCheck, MayChangeCalledProc,
 				ModuleInfo0, Changed0,
 				ModuleInfo1, Changed1, NumErrors),
 	{ Errs1 is Errs0 + NumErrors },
 		% recursively process the remaining modes
-	modecheck_procs(ProcIds, PredId, WhatToCheck,
+	modecheck_procs(ProcIds, PredId, WhatToCheck, MayChangeCalledProc,
 				ModuleInfo1, Changed1, Errs1,
 				ModuleInfo, Changed, Errs).
 
@@ -640,22 +651,21 @@
 	% Mode-check the code for predicate in a given mode.
 
 modecheck_proc(ProcId, PredId, ModuleInfo0, ModuleInfo, NumErrors, Changed) -->
-	modecheck_proc(ProcId, PredId, check_modes,
+	modecheck_proc(ProcId, PredId, check_modes, may_change_called_proc,
 		ModuleInfo0, ModuleInfo, NumErrors, Changed).
 
-modecheck_proc(ProcId, PredId, WhatToCheck, ModuleInfo0,
+modecheck_proc(ProcId, PredId, WhatToCheck, MayChangeCalledProc, ModuleInfo0,
 			ModuleInfo, NumErrors, Changed) -->
-	modecheck_proc_2(ProcId, PredId, WhatToCheck, ModuleInfo0, no,
-			ModuleInfo, Changed, NumErrors).
+	modecheck_proc_2(ProcId, PredId, WhatToCheck, MayChangeCalledProc,
+			ModuleInfo0, no, ModuleInfo, Changed, NumErrors).
 
 :- pred modecheck_proc_2(proc_id, pred_id, how_to_check_goal,
-			module_info, bool, module_info, bool, int,
-			io__state, io__state).
-:- mode modecheck_proc_2(in, in, in, in, in, out, out, out, di, uo) is det.
+		may_change_called_proc, module_info, bool,
+		module_info, bool, int, io__state, io__state).
+:- mode modecheck_proc_2(in, in, in, in, in, in, out, out, out, di, uo) is det.
 
-modecheck_proc_2(ProcId, PredId, WhatToCheck,
-			ModuleInfo0, Changed0,
-			ModuleInfo, Changed, NumErrors) -->
+modecheck_proc_2(ProcId, PredId, WhatToCheck, MayChangeCalledProc,
+		ModuleInfo0, Changed0, ModuleInfo, Changed, NumErrors) -->
 		% get the proc_info from the module_info
 	{ module_info_pred_proc_info(ModuleInfo0, PredId, ProcId,
 					_PredInfo0, ProcInfo0) },
@@ -666,8 +676,9 @@
 	;
 			% modecheck it
 		modecheck_proc_3(ProcId, PredId, WhatToCheck,
-				ModuleInfo0, ProcInfo0, Changed0,
-				ModuleInfo1, ProcInfo, Changed, NumErrors),
+			MayChangeCalledProc, ModuleInfo0, ProcInfo0, Changed0,
+			ModuleInfo1, ProcInfo, Changed, NumErrors),
+
 			% save the proc_info back in the module_info
 		{ module_info_preds(ModuleInfo1, Preds1) },
 		{ map__lookup(Preds1, PredId, PredInfo1) },
@@ -681,18 +692,17 @@
 modecheck_proc_info(ProcId, PredId, ModuleInfo0, ProcInfo0,
 		ModuleInfo, ProcInfo, NumErrors) -->
 	{ WhatToCheck = check_modes },
-	modecheck_proc_3(ProcId, PredId, WhatToCheck,
+	modecheck_proc_3(ProcId, PredId, WhatToCheck, may_change_called_proc,
 			ModuleInfo0, ProcInfo0, no,
 			ModuleInfo, ProcInfo, _Changed, NumErrors).
 
 :- pred modecheck_proc_3(proc_id, pred_id, how_to_check_goal,
-			module_info, proc_info, bool,
-			module_info, proc_info, bool, int,
-			io__state, io__state).
-:- mode modecheck_proc_3(in, in, in, in, in, in, out, out, out, out, di, uo)
-	is det.
+		may_change_called_proc, module_info, proc_info, bool,
+		module_info, proc_info, bool, int, io__state, io__state).
+:- mode modecheck_proc_3(in, in, in, in, in, in, in,
+		out, out, out, out, di, uo) is det.
 
-modecheck_proc_3(ProcId, PredId, WhatToCheck,
+modecheck_proc_3(ProcId, PredId, WhatToCheck, MayChangeCalledProc,
 			ModuleInfo0, ProcInfo0, Changed0,
 			ModuleInfo, ProcInfo, Changed, NumErrors,
 			IOState0, IOState) :-
@@ -733,11 +743,12 @@
 
 		% initialize the mode info
 	mode_info_init(IOState0, ModuleInfo0, PredId, ProcId, Context,
-			LiveVars, InstMap0, WhatToCheck, ModeInfo0),
+		LiveVars, InstMap0, WhatToCheck,
+		MayChangeCalledProc, ModeInfo0),
 	mode_info_set_changed_flag(Changed0, ModeInfo0, ModeInfo1),
 
 		% modecheck the procedure body
-	( WhatToCheck = check_unique_modes(_) ->
+	( WhatToCheck = check_unique_modes ->
 		unique_modes__check_goal(Body0, Body, ModeInfo1, ModeInfo2)
 	;
 		modecheck_goal(Body0, Body, ModeInfo1, ModeInfo2)
@@ -1011,7 +1022,7 @@
 	modecheck_goal(G0, G),
 	mode_checkpoint(exit, "some").
 
-modecheck_goal_expr(call(PredId, _, Args0, _, Context, PredName),
+modecheck_goal_expr(call(PredId, ProcId0, Args0, _, Context, PredName),
 		GoalInfo0, Goal) -->
 	mode_checkpoint(enter, "call"),
 	mode_info_set_call_context(call(PredId)),
@@ -1019,15 +1030,15 @@
 	{ mode_info_get_instmap(ModeInfo0, InstMap0) },
 
 	{ DeterminismKnown = no },
-	modecheck_call_pred(PredId, Args0, DeterminismKnown,
+	modecheck_call_pred(PredId, ProcId0, Args0, DeterminismKnown,
 				Mode, Args, ExtraGoals),
 
 	=(ModeInfo),
 	{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
 	{ code_util__builtin_state(ModuleInfo, PredId, Mode, Builtin) },
 	{ Call = call(PredId, Mode, Args, Builtin, Context, PredName) },
-	{ handle_extra_goals(Call, ExtraGoals, GoalInfo0, Args0, Args,
-				InstMap0, ModeInfo, Goal) },
+	handle_extra_goals(Call, ExtraGoals, GoalInfo0, Args0, Args,
+				InstMap0, Goal),
 
 	mode_info_unset_call_context,
 	mode_checkpoint(exit, "call").
@@ -1068,7 +1079,7 @@
 
 	% to modecheck a pragma_c_code, we just modecheck the proc for 
 	% which it is the goal.
-modecheck_goal_expr(pragma_c_code(IsRecursive, PredId, _ProcId0, Args0,
+modecheck_goal_expr(pragma_c_code(IsRecursive, PredId, ProcId0, Args0,
 		ArgNameMap, OrigArgTypes, PragmaCode), GoalInfo, Goal) -->
 	mode_checkpoint(enter, "pragma_c_code"),
 	mode_info_set_call_context(call(PredId)),
@@ -1076,14 +1087,13 @@
 	=(ModeInfo0),
 	{ mode_info_get_instmap(ModeInfo0, InstMap0) },
 	{ DeterminismKnown = no },
-	modecheck_call_pred(PredId, Args0, DeterminismKnown,
+	modecheck_call_pred(PredId, ProcId0, Args0, DeterminismKnown,
 				ProcId, Args, ExtraGoals),
 
-	=(ModeInfo),
 	{ Pragma = pragma_c_code(IsRecursive, PredId, ProcId, Args0,
 			ArgNameMap, OrigArgTypes, PragmaCode) },
-	{ handle_extra_goals(Pragma, ExtraGoals, GoalInfo, Args0, Args,
-			InstMap0, ModeInfo, Goal) },
+	handle_extra_goals(Pragma, ExtraGoals, GoalInfo, Args0, Args,
+			InstMap0, Goal),
 
 	mode_info_unset_call_context,
 	mode_checkpoint(exit, "pragma_c_code").
@@ -1107,44 +1117,23 @@
 			extra_goals(BeforeGoals1, AfterGoals1),
 			extra_goals(BeforeGoals, AfterGoals)) :-
 	list__append(BeforeGoals0, BeforeGoals1, BeforeGoals),
-	append_after_goals(AfterGoals0, AfterGoals1, AfterGoals).
-
-:- pred append_after_goals(after_goals, after_goals, after_goals).
-:- mode append_after_goals(in, in, out) is det.
-
-append_after_goals(no_after_goals, AfterGoals, AfterGoals).
-append_after_goals(after_goals(InstMap, AfterGoals),
-		no_after_goals, after_goals(InstMap, AfterGoals)).
-append_after_goals(after_goals(InstMap0, AfterGoals0),
-			after_goals(_InstMap1, AfterGoals1),
-			after_goals(InstMap, AfterGoals)) :-
-	InstMap = InstMap0,
 	list__append(AfterGoals0, AfterGoals1, AfterGoals).
 
-handle_extra_goals(MainGoal, ExtraGoals, GoalInfo0, Args0, Args,
-		InstMapAtStart, ModeInfo, Goal) :-
-	% did we introduced any extra variables (and code)?
+handle_extra_goals(MainGoal, no_extra_goals, _GoalInfo0, _Args0, _Args,
+		_InstMap0, MainGoal, ModeInfo, ModeInfo).
+handle_extra_goals(MainGoal, extra_goals(BeforeGoals0, AfterGoals0),
+		GoalInfo0, Args0, Args, InstMap0, Goal, ModeInfo0, ModeInfo) :-
+	mode_info_get_errors(ModeInfo0, Errors),
 	(
-		ExtraGoals = no_extra_goals,
-		Goal = MainGoal	% no
-	;
-		ExtraGoals = extra_goals(BeforeGoals0, AfterGoalsInfo0),
-
-		% if there were any goals to be appended after the main goal,
-		% get them and the instmap after the main goal.
-		% If there are no goals to be append after the main goal, then
-		% the current instmap in the mode_info is the instmap
-		% after the main goal.
-		(
-			AfterGoalsInfo0 = after_goals(InstMapAfterMain,
-				AfterGoals0)
-		;
-			AfterGoalsInfo0 = no_after_goals,
-			mode_info_get_instmap(ModeInfo, InstMapAtEnd),
-			InstMapAfterMain = InstMapAtEnd,
-			AfterGoals0 = []
-		),
-
+		% There's no point adding extra goals if the code is
+		% unreachable anyway.
+		instmap__is_reachable(InstMap0),
+
+		% If we recorded errors processing the goal, it will
+		% have to be reprocessed anyway, so don't add the extra
+		% goals now.
+		Errors = []
+	->
 		%
 		% We need to be careful to update the delta-instmaps
 		% correctly, using the appropriate instmaps:
@@ -1166,20 +1155,51 @@
 		set__difference(NewArgVars, OldArgVars, IntroducedVars),
 		set__union(NonLocals0, IntroducedVars, OutsideVars),
 		set__intersect(OutsideVars, NewArgVars, NonLocals),
-		goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo1),
-
-		% compute the instmap delta for the main goal
-		compute_instmap_delta(InstMapAtStart, InstMapAfterMain,
-			NonLocals, DeltaInstMap),
-		goal_info_set_instmap_delta(GoalInfo1, DeltaInstMap, GoalInfo),
+		goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo),
 
 		% combine the main goal and the extra goals into a conjunction
 		Goal0 = MainGoal - GoalInfo,
 		goal_info_get_context(GoalInfo0, Context),
 		handle_extra_goals_contexts(BeforeGoals0, Context, BeforeGoals),
 		handle_extra_goals_contexts(AfterGoals0, Context, AfterGoals),
-		list__append(BeforeGoals, [Goal0 | AfterGoals], GoalList),
-		Goal = conj(GoalList)
+		list__append(BeforeGoals, [Goal0 | AfterGoals], GoalList0),
+
+		mode_info_get_may_change_called_proc(ModeInfo0,
+			MayChangeCalledProc0),
+
+		% Make sure we don't go into an infinite loop if
+		% there is a bug in the code to add extra goals.
+		mode_info_set_checking_extra_goals(yes, ModeInfo0, ModeInfo1),
+
+		% We've already worked out which procedure should be called,
+		% we don't need to do it again.
+		mode_info_set_may_change_called_proc(
+			may_not_change_called_proc, ModeInfo1, ModeInfo2),
+
+		mode_info_set_instmap(InstMap0, ModeInfo2, ModeInfo3),
+
+		% Recheck the goals to compute the instmap_deltas.
+		%
+		% This can fail even if the original check on the goal
+		% succeeded in the case of a unification procedure which
+		% binds a partially instantiated variable, because adding
+		% the extra goals can make the partially instantiated
+		% variables `live' after the main goal.
+		% The other thing to beware of in this case is that delaying
+		% must be disabled while processing the extra goals. If it
+		% is not, the main unification will be delayed until after the
+		% argument unifications, which turns them into assignments,
+		% and we end up repeating the process forever.
+		mode_info_add_goals_live_vars(GoalList0, ModeInfo3, ModeInfo4),
+		modecheck_conj_list_no_delay(GoalList0, GoalList,
+			ModeInfo4, ModeInfo5),
+		Goal = conj(GoalList),
+		mode_info_set_checking_extra_goals(no, ModeInfo5, ModeInfo6),
+		mode_info_set_may_change_called_proc(MayChangeCalledProc0,
+			ModeInfo6, ModeInfo)
+	;
+		Goal = MainGoal,
+		ModeInfo = ModeInfo0
 	).
 
 :- pred handle_extra_goals_contexts(list(hlds_goal), prog_context,
@@ -1201,6 +1221,22 @@
 
 %-----------------------------------------------------------------------------%
 
+	% Modecheck a conjunction without doing any reordering.
+	% This is used by handle_extra_goals above.
+:- pred modecheck_conj_list_no_delay(list(hlds_goal), list(hlds_goal),
+				mode_info, mode_info).
+:- mode modecheck_conj_list_no_delay(in, out,
+				mode_info_di, mode_info_uo) is det.
+
+modecheck_conj_list_no_delay([], []) --> [].
+modecheck_conj_list_no_delay([Goal0 | Goals0], [Goal | Goals]) -->
+	{ goal_get_nonlocals(Goal0, NonLocals) },
+	mode_info_remove_live_vars(NonLocals),
+	modecheck_goal(Goal0, Goal),
+	modecheck_conj_list_no_delay(Goals0, Goals).
+
+%-----------------------------------------------------------------------------%
+
 :- pred modecheck_conj_list(list(hlds_goal), list(hlds_goal),
 				mode_info, mode_info).
 :- mode modecheck_conj_list(in, out, mode_info_di, mode_info_uo) is det.
@@ -1653,31 +1689,21 @@
 				mode_info_di, mode_info_uo) is det.
 
 modecheck_set_var_inst(Var0, InitialInst, FinalInst, Var,
-			ExtraGoals0, ExtraGoals,
-			ModeInfo0, ModeInfo) :-
+		ExtraGoals0, ExtraGoals, ModeInfo0, ModeInfo) :-
 	mode_info_get_instmap(ModeInfo0, InstMap0),
 	( instmap__is_reachable(InstMap0) ->
 		% The new inst must be computed by unifying the
 		% old inst and the proc's final inst
 		instmap__lookup_var(InstMap0, Var0, VarInst0),
-		mode_info_get_module_info(ModeInfo0, ModuleInfo0),
-		(
-			abstractly_unify_inst(dead, VarInst0, FinalInst,
-				fake_unify, ModuleInfo0,
-				UnifyInst, Det1, ModuleInfo1)
-		->
-			ModuleInfo = ModuleInfo1,
-			VarInst = UnifyInst,
-			Det = Det1
+		handle_implied_mode(Var0, VarInst0, InitialInst,
+		 	Var, ExtraGoals0, ExtraGoals, ModeInfo0, ModeInfo1),
+		modecheck_set_var_inst(Var0, FinalInst, ModeInfo1, ModeInfo2),
+		( Var = Var0 ->
+			ModeInfo = ModeInfo2
 		;
-			error("modecheck_set_var_inst: unify_inst failed")
-		),
-		mode_info_set_module_info(ModeInfo0, ModuleInfo, ModeInfo1),
-		handle_implied_mode(Var0,
-			VarInst0, VarInst, InitialInst, FinalInst, Det,
-		 	Var, ExtraGoals0, ExtraGoals, ModeInfo1, ModeInfo2),
-		modecheck_set_var_inst(Var0, FinalInst, ModeInfo2, ModeInfo3),
-		modecheck_set_var_inst(Var, FinalInst, ModeInfo3, ModeInfo)
+			modecheck_set_var_inst(Var, FinalInst,
+				ModeInfo2, ModeInfo)
+		)
 	;
 		Var = Var0,
 		ExtraGoals = ExtraGoals0,
@@ -1777,13 +1803,13 @@
 % If this was a call to an implied mode for that variable, then we need to
 % introduce a fresh variable.
 
-:- pred handle_implied_mode(prog_var, inst, inst, inst, inst, determinism,
-		prog_var, extra_goals, extra_goals, mode_info, mode_info).
-:- mode handle_implied_mode(in, in, in, in, in, in, out, in, out,
-				mode_info_di, mode_info_uo) is det.
+:- pred handle_implied_mode(prog_var, inst, inst, prog_var,
+		extra_goals, extra_goals, mode_info, mode_info).
+:- mode handle_implied_mode(in, in, in, out, in, out,
+		mode_info_di, mode_info_uo) is det.
 
-handle_implied_mode(Var0, VarInst0, VarInst, InitialInst0, FinalInst, Det,
-		Var, ExtraGoals0, ExtraGoals, ModeInfo0, ModeInfo) :-
+handle_implied_mode(Var0, VarInst0, InitialInst0, Var,
+		ExtraGoals0, ExtraGoals, ModeInfo0, ModeInfo) :-
 	mode_info_get_module_info(ModeInfo0, ModuleInfo0),
 	inst_expand(ModuleInfo0, InitialInst0, InitialInst),
 	inst_expand(ModuleInfo0, VarInst0, VarInst1),
@@ -1846,8 +1872,7 @@
 				goal_info_set_instmap_delta(GoalInfo1,
 					InstmapDelta, GoalInfo),
 				NewExtraGoal = extra_goals(
-					[BeforeGoal - GoalInfo],
-					no_after_goals),
+					[BeforeGoal - GoalInfo], []),
 				append_extra_goals(ExtraGoals0, NewExtraGoal,
 					ExtraGoals),
 				ModeInfo0 = ModeInfo
@@ -1886,53 +1911,15 @@
 			map__lookup(VarTypes0, Var0, VarType),
 			map__set(VarTypes0, Var, VarType, VarTypes),
 			mode_info_set_varset(VarSet, ModeInfo0, ModeInfo1),
-			mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo2),
-
-			% Calculate the instmap after the main goal.
-			% We just need to set the inst of the newly
-			% introduced variable Var to the procedure
-			% argument's final inst.
-			mode_info_get_instmap(ModeInfo2, OrigInstMap),
-			instmap__set(OrigInstMap, Var, FinalInst,
-				InstMapAfterMain),
-			mode_info_set_instmap(InstMapAfterMain,
-				ModeInfo2, ModeInfo3),
+			mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo),
 
 			% Construct the code to do the unification
-			ModeVar0 = (VarInst0 -> VarInst),
-			ModeVar = (FinalInst -> VarInst),
-			mode_info_get_mode_context(ModeInfo3, ModeContext),
-			mode_context_to_unify_context(ModeContext, ModeInfo3,
-				UnifyContext),
-
-			categorize_unify_var_var(ModeVar0, ModeVar,
-				live, dead, Var0, Var, Det, UnifyContext,
-				VarTypes, ModeInfo3, NewUnifyGoal, ModeInfo),
-			unify_vars(NewUnifyGoal, NewUnifyGoalVars),
-
-			% compute the goal_info nonlocal vars & instmap delta
-			% N.B.  This may overestimate the set of nonlocal vars,
-			% but that should not cause any problems.
-			set__list_to_set(NewUnifyGoalVars, NonLocals),
-			( VarInst = VarInst0 ->
-				InstMapDeltaAL0 = []
-			;
-				InstMapDeltaAL0 = [Var0 - VarInst]
-			),
-			InstMapDeltaAL = [Var - VarInst | InstMapDeltaAL0],
-			instmap_delta_from_assoc_list(InstMapDeltaAL,
-				InstMapDelta),
-			goal_info_init(GoalInfo0),
-			goal_info_set_nonlocals(GoalInfo0, NonLocals,
-				GoalInfo1),
-			goal_info_set_instmap_delta(GoalInfo1, InstMapDelta,
-				GoalInfo),
+			modecheck_unify__create_var_var_unification(Var0, Var,
+				ModeInfo, ExtraGoal),
 
 			% append the goals together in the appropriate order:
 			% ExtraGoals0, then NewUnify
-			NewUnifyExtraGoal = extra_goals([], after_goals(
-						InstMapAfterMain,
-						[NewUnifyGoal - GoalInfo])),
+			NewUnifyExtraGoal = extra_goals([], [ExtraGoal]),
 			append_extra_goals(ExtraGoals0, NewUnifyExtraGoal,
 				ExtraGoals)
 		)
Index: compiler/pd_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/pd_util.m,v
retrieving revision 1.4
diff -u -u -r1.4 pd_util.m
--- pd_util.m	1998/11/20 04:08:45	1.4
+++ pd_util.m	1999/05/10 05:53:05
@@ -201,9 +201,10 @@
 	% If we perform generalisation, we shouldn't change any called
 	% procedures, since that could cause a less efficient version to
 	% be chosen.
-	{ HowToCheck = check_unique_modes(may_not_change_called_proc) },
+	{ MayChangeCalledProc = may_not_change_called_proc },
 	{ mode_info_init(IO0, ModuleInfo1, PredId, ProcId, Context,
-		LiveVars, InstMap0, HowToCheck, ModeInfo0) },
+		LiveVars, InstMap0, check_unique_modes,
+		MayChangeCalledProc, ModeInfo0) },
 
 	{ unique_modes__check_goal(Goal0, Goal, ModeInfo0, ModeInfo1) },
 	pd_info_lookup_bool_option(debug_pd, Debug),
Index: compiler/unify_proc.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unify_proc.m,v
retrieving revision 1.72
diff -u -u -r1.72 unify_proc.m
--- unify_proc.m	1998/11/20 04:09:37	1.72
+++ unify_proc.m	1999/05/11 07:00:52
@@ -352,7 +352,7 @@
 		%
 		% print progress message
 		%
-		( { HowToCheckGoal = check_unique_modes(_) } ->
+		( { HowToCheckGoal = check_unique_modes } ->
 			io__write_string(
 		    "% Analyzing modes, determinism, and unique-modes for\n% ")
 		;
@@ -406,10 +406,10 @@
 	->
 		io__set_exit_status(1),
 		{ OldPredTable = OldPredTable0 },
-		{ ModuleInfo = ModuleInfo2 },
+		{ module_info_remove_predid(ModuleInfo2, PredId, ModuleInfo) },
 		{ Changed = Changed1 }
 	;
-		( { HowToCheckGoal = check_unique_modes(_) } ->
+		( { HowToCheckGoal = check_unique_modes } ->
 			{ detect_switches_in_proc(ProcId, PredId,
 						ModuleInfo2, ModuleInfo3) },
 			detect_cse_in_proc(ProcId, PredId,
Index: compiler/unique_modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unique_modes.m,v
retrieving revision 1.51
diff -u -u -r1.51 unique_modes.m
--- unique_modes.m	1999/04/16 07:51:56	1.51
+++ unique_modes.m	1999/05/10 05:53:06
@@ -67,12 +67,12 @@
 %-----------------------------------------------------------------------------%
 
 unique_modes__check_module(ModuleInfo0, ModuleInfo) -->
-	check_pred_modes(check_unique_modes(may_change_called_proc),
+	check_pred_modes(check_unique_modes, may_change_called_proc,
 			ModuleInfo0, ModuleInfo, _UnsafeToContinue).
 
 unique_modes__check_proc(ProcId, PredId, ModuleInfo0, ModuleInfo, Changed) -->
 	modecheck_proc(ProcId, PredId,
-		check_unique_modes(may_change_called_proc),
+		check_unique_modes, may_change_called_proc,
 		ModuleInfo0, ModuleInfo, NumErrors, Changed),
 	( { NumErrors \= 0 } ->
 		io__set_exit_status(1)
@@ -492,11 +492,11 @@
 	%
 	mode_info_get_errors(ModeInfo2, Errors),
 	mode_info_set_errors(OldErrors, ModeInfo2, ModeInfo3),
-	mode_info_get_how_to_check(ModeInfo3, HowToCheck),
+	mode_info_get_may_change_called_proc(ModeInfo3, MayChangeCalledProc),
 	( Errors = [] ->
 		ProcId = ProcId0,
 		ModeInfo = ModeInfo3
-	; HowToCheck = check_unique_modes(may_not_change_called_proc) ->
+	; MayChangeCalledProc = may_not_change_called_proc ->
 		% We're not allowed to try a different procedure
 		% here, so just return all the errors.
 		ProcId = ProcId0,
@@ -519,7 +519,7 @@
 		%
 		mode_info_set_instmap(InstMap0, ModeInfo3, ModeInfo4),
 		proc_info_inferred_determinism(ProcInfo, Determinism),
-		modecheck_call_pred(PredId, ArgVars, yes(Determinism),
+		modecheck_call_pred(PredId, ProcId0, ArgVars, yes(Determinism),
 			ProcId, NewArgVars, ExtraGoals, ModeInfo4, ModeInfo),
 		
 		( NewArgVars = ArgVars, ExtraGoals = no_extra_goals ->
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/tests/invalid/Mmakefile,v
retrieving revision 1.39
diff -u -u -r1.39 Mmakefile
--- Mmakefile	1999/04/23 01:03:44	1.39
+++ Mmakefile	1999/05/11 06:08:42
@@ -34,6 +34,7 @@
 	no_exports.m \
 	nullary_ho_func_error.m \
 	occurs.m \
+	partial_implied_mode.m \
 	polymorphic_unification.m \
 	pragma_c_code_and_clauses1.m \
 	pragma_c_code_and_clauses2.m \
@@ -116,7 +117,7 @@
 
 # We only need to make the dependencies for test cases consisting of
 # multiple modules; currently the following are the only such cases.
-depend:	test_nested.depend
+depend:	test_nested.depend partial_implied_mode.depend
 
 
 clean:

tests/invalid/partial_implied_mode.m
===================================================================
% This is a test for partially implied modes where the overbound
% term is partially instantiated. This really shouldn't be an error,
% and won't be with the alias tracking mode checker. It's difficult
% to make this program legal with the current mode checker without
% disallowing construction of partially instantiated terms.
%
% The reason partial_implied_mode2.m has to be a separate module
% is because unification procedures for local types have unique mode
% analysis run on them (although it's really not necessary). 
% For local types, the code generator abort did not happen
% because unique_modes reported a mode error.
%
% Mercury rotd-1999-05-08 aborted during code generation on this
% test case.
:- module partial_implied_mode.

:- interface.

:- import_module map, list, partial_implied_mode2.

:- type quantitiesdico == map(quantity_key, physic_quantity).

:- pred search_quantitykey_1pin(pin, list(quantity_key),
		quantitiesdico, quantity_key).
:- mode search_quantitykey_1pin(in, in, in, out) is det.

:- implementation.

:- import_module require.

search_quantitykey_1pin(PIN, [CUR_K|L], QTY_DICO, K) :-
	(
		map__lookup(QTY_DICO, CUR_K,
			physic_quantity(PIN, _SYN, absol(_MEAS, _TBS)))
	->
		K = CUR_K
	;
		search_quantitykey_1pin(PIN, L, QTY_DICO, K)
	).
search_quantitykey_1pin(_, [], _, _) :-
	error(
	"search_quantitykey_1pin : no such absolute quantity in the list").

tests/invalid/partial_implied_mode.err_exp
===================================================================
partial_implied_mode2.int:015: In clause for `'__Unify__'((unique(partial_implied_mode2:physic_quantity(ground, free, unique(partial_implied_mode2:absol(free, free)))) -> bound(partial_implied_mode2:physic_quantity(ground, ground, bound(partial_implied_mode2:absol(ground, ground))))), (ground -> bound(partial_implied_mode2:physic_quantity(ground, ground, bound(partial_implied_mode2:absol(ground, ground))))))':
partial_implied_mode2.int:015:   mode error in unification of `V_1' and `partial_implied_mode2:physic_quantity(V_9, V_4, V_10)'.
partial_implied_mode2.int:015:   Variable `V_1' has instantiatedness `unique(partial_implied_mode2:physic_quantity(ground, free, unique(partial_implied_mode2:absol(free, free))))',
partial_implied_mode2.int:015:   term `partial_implied_mode2:physic_quantity(V_9, V_4, V_10)'
partial_implied_mode2.int:015:   has instantiatedness `partial_implied_mode2:physic_quantity(free, ground, free)'.
For more information, try recompiling with `-E'.

tests/invalid/partial_implied_mode2.m
===================================================================
% Type definitions for partial_implied_mode.m.
:- module partial_implied_mode2.

:- interface.

:- import_module std_util, list.

:- type pin.
:- type quantity_key.
:- type measure == int.
:- type tbs == int.

:- type physic_quantity
	--->	physic_quantity(pin, list(quantity_key), physic_nature).
:- type physic_nature
	--->	direct
	;	absol(maybe(measure), maybe(tbs))
	;	diff(pin, maybe(pair(quantity_key, quantity_key)),
			maybe(measure), maybe(tbs)).

:- type port_name_ref == int.
:- type master_port
	--->	port_name_ref(port_name_ref)
	;	anonymous_master_port(int).

:- type instance_path == list(int).
:- type component_key
	--->    component(instance_path).

:- type net_path == list(int).
:- type net_key
	--->    anonymous_net(int)
	;	named_net(net_path).

:- type pin
	--->	net_pin(net_key)
	;	component_pin(component_key, master_port).

:- type quantity_key == int.

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list