diff: report errors for duplicate mode declarations

Fergus Henderson fjh at cs.mu.oz.au
Sun Nov 23 15:31:15 AEDT 1997


Report an error for duplicate mode declarations.

compiler/modes.m:
	Check for duplicate mode declarations.

compiler/modecheck_call.m:
	Add new predicate modes_are_indistinguishable, for use by modes.m.

compiler/mode_errors.m:
	Add predicate report_indistinguishable_mode_error to mode_errors.m,
	so that modes.m can use it to report duplicate mode declarations.

compiler/mode_errors.m:
compiler/mercury_to_mercury.m:
	Move some code in mode_errors.m into a new predicate
	mercury_output_mode_subdecls/8 in mercury_to_mercury.m.

compiler/make_hlds.m:
	Update a few comments.

tests/invalid/Mmakefile:
tests/invalid/duplicate_modes.m:
tests/invalid/duplicate_modes.err_exp:
	Test cases for the above change.

cvs diff -N compiler/make_hlds.m compiler/mercury_to_mercury.m compiler/mode_errors.m compiler/modecheck_call.m compiler/modes.m tests/invalid/Mmakefile tests/invalid/duplicate_modes.err_exp tests/invalid/duplicate_modes.m
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/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/23 04:27:25
@@ -1439,12 +1439,11 @@
 	;
 		[]
 	),
-		% add the mode declaration to the proc_info for this procedure.
-		% XXX we should check that this mode declaration
-		% isn't the same as an existing one
+
+		% add the mode declaration to the pred_info for this procedure.
 	{ ArgLives = no },
 	{ add_new_proc(PredInfo0, Arity, Modes, yes(Modes), ArgLives,
-			MaybeDet, MContext, PredInfo, _) },
+			MaybeDet, MContext, PredInfo, _NewProcId) },
 	{ map__det_update(Preds0, PredId, PredInfo, Preds) },
 	{ predicate_table_set_preds(PredicateTable1, Preds, PredicateTable) },
 	{ module_info_set_predicate_table(ModuleInfo0, PredicateTable,
@@ -1514,6 +1513,7 @@
 	% Higher numbers mean lower priority.
 	% This works because mode analysis tries each mode in turn,
 	% starting with the lowest-numbered modes.
+	% XXX This is obsolete!
 
 :- pred determinism_priority(determinism, int).
 :- mode determinism_priority(in, out) is det.
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/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/23 03:06:38
@@ -34,14 +34,19 @@
 		maybe(determinism), term__context, io__state, io__state).
 :- mode mercury_output_pred_mode_decl(in, in, in, in, in, di, uo) is det.
 
-:- pred mercury_output_pred_mode_subdecl(varset, sym_name, list(mode),
-		maybe(determinism), term__context, io__state, io__state).
-:- mode mercury_output_pred_mode_subdecl(in, in, in, in, in, di, uo) is det.
-
 :- pred mercury_output_func_mode_decl(varset, sym_name, list(mode), mode,
 		maybe(determinism), term__context, io__state, io__state).
 :- mode mercury_output_func_mode_decl(in, in, in, in, in, in, di, uo) is det.
 
+:- pred mercury_output_mode_subdecl(pred_or_func, varset, sym_name,
+		list(mode), maybe(determinism), term__context,
+		io__state, io__state).
+:- mode mercury_output_mode_subdecl(in, in, in, in, in, in, di, uo) is det.
+
+:- pred mercury_output_pred_mode_subdecl(varset, sym_name, list(mode),
+		maybe(determinism), term__context, io__state, io__state).
+:- mode mercury_output_pred_mode_subdecl(in, in, in, in, in, di, uo) is det.
+
 :- pred mercury_output_func_mode_subdecl(varset, sym_name, list(mode), mode,
 		maybe(determinism), term__context, io__state, io__state).
 :- mode mercury_output_func_mode_subdecl(in, in, in, in, in, in, di, uo) is det.
@@ -1151,6 +1156,19 @@
 	io__write_string(".\n").
 
 %-----------------------------------------------------------------------------%
+
+	% Output a mode declaration for a predicate or function.
+
+mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes, MaybeDet,
+		Context) -->
+	(	{ PredOrFunc = predicate },
+		mercury_output_pred_mode_subdecl(InstVarSet, Name, Modes,
+				MaybeDet, Context)
+	;	{ PredOrFunc = function },
+		{ pred_args_to_func_args(Modes, ArgModes, RetMode) },
+		mercury_output_func_mode_subdecl(InstVarSet, Name, ArgModes,
+				RetMode, MaybeDet, Context)
+	).
 
 	% Output a mode declaration for a predicate.
 
Index: compiler/mode_errors.m
===================================================================
RCS file: /home/mercury1/repository/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/11/23 04:16:07
@@ -141,6 +141,13 @@
 				io__state, io__state).
 :- mode write_mode_inference_messages(in, in, di, uo) is det.
 
+	% report an error for the case when two mode declarations
+	% declare indistinguishable modes
+
+:- pred report_indistinguishable_modes_error(proc_id, proc_id,
+		pred_id, pred_info, module_info, io__state, io__state).
+:- mode report_indistinguishable_modes_error(in, in, in, in, in, di, uo) is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -667,14 +674,8 @@
 
 	prog_out__write_context(Context),
 	io__write_string("In clause for `"),
-	(	{ PredOrFunc = predicate },
-		mercury_output_pred_mode_subdecl(InstVarSet, Name, Modes,
-				MaybeDet, Context)
-	;	{ PredOrFunc = function },
-		{ pred_args_to_func_args(Modes, ArgModes, RetMode) },
-		mercury_output_func_mode_subdecl(InstVarSet, Name, ArgModes,
-				RetMode, MaybeDet, Context)
-	),
+	mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
+				MaybeDet, Context),
 	io__write_string("':\n"),
 	{ mode_info_get_mode_context(ModeInfo, ModeContext) },
 	write_mode_context(ModeContext, Context, ModuleInfo).
@@ -910,6 +911,66 @@
 output_inst_list(Insts0, VarSet) -->
 	{ strip_builtin_qualifiers_from_inst_list(Insts0, Insts) },
 	mercury_output_inst_list(Insts, VarSet).
+
+%-----------------------------------------------------------------------------%
+
+report_indistinguishable_modes_error(OldProcId, NewProcId,
+		PredId, PredInfo, ModuleInfo) -->
+
+	io__set_exit_status(1),
+
+	{ pred_info_procedures(PredInfo, Procs) },
+	{ map__lookup(Procs, OldProcId, OldProcInfo) },
+	{ map__lookup(Procs, NewProcId, NewProcInfo) },
+	{ proc_info_context(OldProcInfo, OldContext) },
+	{ proc_info_context(NewProcInfo, NewContext) },
+
+	prog_out__write_context(NewContext),
+	io__write_string("In mode declarations for "),
+	hlds_out__write_pred_id(ModuleInfo, PredId),
+	io__write_string(":\n"),
+
+	prog_out__write_context(NewContext),
+	io__write_string("  error: duplicate mode declaration.\n"),
+
+	globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
+	( { VerboseErrors = yes } ->
+		prog_out__write_context(NewContext),
+		io__write_string("  Modes `"),
+		output_mode_decl(OldProcId, PredInfo),
+		io__write_string("'\n"),
+
+		prog_out__write_context(NewContext),
+		io__write_string("  and `"),
+		output_mode_decl(NewProcId, PredInfo),
+		io__write_string("'\n"),
+
+		prog_out__write_context(NewContext),
+		io__write_string("  are indistinguishable.\n")
+	;
+		[]
+	),
+
+	prog_out__write_context(OldContext),
+	io__write_string(
+		"  Here is the conflicting mode declaration.\n").
+
+:- pred output_mode_decl(proc_id, pred_info, io__state, io__state).
+:- mode output_mode_decl(in, in, di, uo) is det.
+
+output_mode_decl(ProcId, PredInfo) -->
+	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
+	{ pred_info_name(PredInfo, Name0) },
+	{ pred_info_procedures(PredInfo, Procs) },
+	{ map__lookup(Procs, ProcId, ProcInfo) },
+	{ proc_info_declared_argmodes(ProcInfo, Modes0) },
+	{ proc_info_declared_determinism(ProcInfo, MaybeDet) },
+	{ proc_info_context(ProcInfo, Context) },
+	{ varset__init(InstVarSet) },
+	{ Name = unqualified(Name0) },
+	{ strip_builtin_qualifiers_from_mode_list(Modes0, Modes) },
+	mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
+				MaybeDet, Context).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: compiler/modecheck_call.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modecheck_call.m,v
retrieving revision 1.17
diff -u -r1.17 modecheck_call.m
--- modecheck_call.m	1997/10/15 07:39:45	1.17
+++ modecheck_call.m	1997/11/23 03:14:01
@@ -45,6 +45,15 @@
 :- mode modecheck_higher_order_func_call(in, in, in, in, out,
 		mode_info_di, mode_info_uo) is det.
 
+	%
+	% Given two modes of a predicate, figure out whether
+	% they are indistinguishable; that is, whether any valid call to
+	% one mode would also be a valid call to the other.
+	% (If so, it is a mode error.)
+	%
+:- pred modes_are_indistinguishable(proc_id, proc_id, pred_info, module_info).
+:- mode modes_are_indistinguishable(in, in, in, in) is semidet.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -436,6 +445,51 @@
 
 %-----------------------------------------------------------------------------%
 
+	%
+	% Given two modes of a predicate, figure out whether
+	% they are indistinguishable; that is, whether any valid call to
+	% one mode would also be a valid call to the other.
+	% (If so, it is a mode error.)
+	%
+	% The code for this is similar to the code for compare_procs/5 below.
+	%
+modes_are_indistinguishable(ProcId, OtherProcId, PredInfo, ModuleInfo) :-
+	pred_info_procedures(PredInfo, Procs),
+	map__lookup(Procs, ProcId, ProcInfo),
+	map__lookup(Procs, OtherProcId, OtherProcInfo),
+	%
+	% Compare the initial insts of the arguments
+	%
+	proc_info_argmodes(ProcInfo, ProcArgModes),
+	proc_info_argmodes(OtherProcInfo, OtherProcArgModes),
+	mode_list_get_initial_insts(ProcArgModes, ModuleInfo, InitialInsts),
+	mode_list_get_initial_insts(OtherProcArgModes, ModuleInfo,
+							OtherInitialInsts),
+	compare_inst_list(InitialInsts, OtherInitialInsts, CompareInsts,
+		ModuleInfo),
+	CompareInsts = same,
+	%
+	% Compare the expected livenesses of the arguments
+	%
+	get_arg_lives(ProcArgModes, ModuleInfo, ProcArgLives),
+	get_arg_lives(OtherProcArgModes, ModuleInfo, OtherProcArgLives),
+	compare_liveness_list(ProcArgLives, OtherProcArgLives, CompareLives),
+	CompareLives = same,
+	%
+	% Compare the determinisms --
+	%	If both are cc_, or if both are not cc_,
+	%	then they are indistinguishable.
+	%
+	proc_info_interface_determinism(ProcInfo, Detism),
+	proc_info_interface_determinism(OtherProcInfo, OtherDetism),
+	determinism_components(Detism, _CanFail, Solns),
+	determinism_components(OtherDetism, _OtherCanFail, OtherSolns),
+	( Solns = at_most_many_cc, OtherSolns = at_most_many_cc
+	; Solns \= at_most_many_cc, OtherSolns \= at_most_many_cc
+	).
+
+%-----------------------------------------------------------------------------%
+
 /*
 The algorithm for choose_best_match is supposed to be equivalent
 to the following specification:
@@ -497,8 +551,11 @@
 
 	%
 	% Given two modes of a predicate, figure out whether
-	% one of the is a better match than the other,
+	% one of them is a better match than the other,
 	% for calls which could match either mode.
+	%
+	% The code for this is similar to the code for
+	% modes_are_indistiguisable/4 above.
 	%
 :- pred compare_proc(proc_id, proc_id, match, proc_table, mode_info).
 :- mode compare_proc(in, in, out, in, mode_info_ui) is det.
Index: compiler/modes.m
===================================================================
RCS file: /home/mercury1/repository/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/23 04:11:44
@@ -427,8 +427,11 @@
 		{ NumErrors = 0 },
 		{ Changed = Changed0 }
 	;
+		check_for_indistinguishable_modes(ProcIds, PredId, PredInfo0,
+					ModuleInfo0, 0, NumErrors0),
 		modecheck_procs(ProcIds, PredId, ModuleInfo0, Changed0, 0,
-					ModuleInfo, Changed, NumErrors)
+					ModuleInfo, Changed, NumErrors1),
+		{ NumErrors is NumErrors0 + NumErrors1 }
 	).
 
 	% Iterate over the list of modes for a predicate.
@@ -448,6 +451,52 @@
 		% recursively process the remaining modes
 	modecheck_procs(ProcIds, PredId, ModuleInfo1, Changed1,
 			Errs1, ModuleInfo, Changed, Errs).
+
+%-----------------------------------------------------------------------------%
+
+:- pred check_for_indistinguishable_modes(list(proc_id),
+			pred_id, pred_info, module_info, int, int,
+			io__state, io__state).
+:- mode check_for_indistinguishable_modes(in, in, in, in, in, out,
+			di, uo) is det.
+
+check_for_indistinguishable_modes([], _, _, _, NumErrors, NumErrors) --> [].
+check_for_indistinguishable_modes([ProcId | ProcIds],
+		PredId, PredInfo, ModuleInfo, NumErrors0, NumErrors) -->
+	check_for_indistinguishable_mode(ProcIds, ProcId,
+		PredId, PredInfo, ModuleInfo, NumErrors0, NumErrors1),
+	check_for_indistinguishable_modes(ProcIds,
+		PredId, PredInfo, ModuleInfo, NumErrors1, NumErrors).
+
+:- pred check_for_indistinguishable_mode(list(proc_id), proc_id,
+			pred_id, pred_info, module_info, int, int,
+			io__state, io__state).
+:- mode check_for_indistinguishable_mode(in, in, in, in, in, in, out,
+			di, uo) is det.
+
+	% For each mode in the list, check that either that mode is the
+	% new mode we just added, or that it is distinguishable from the
+	% new mode.  If we find a mode that is indistinguishable from the
+	% one we just added, report an error.
+
+check_for_indistinguishable_mode([], _, _, _, _, NumErrors, NumErrors) --> [].
+check_for_indistinguishable_mode([ProcId | ProcIds], NewProcId,
+		PredId, PredInfo, ModuleInfo, NumErrors0, NumErrors) -->
+	(
+		{
+			ProcId = NewProcId
+		;
+			\+ modes_are_indistinguishable(ProcId, NewProcId,
+				PredInfo, ModuleInfo)
+		}
+	->
+		check_for_indistinguishable_mode(ProcIds, NewProcId,
+			PredId, PredInfo, ModuleInfo, NumErrors0, NumErrors)
+	;
+		report_indistinguishable_modes_error(ProcId, NewProcId,
+			PredId, PredInfo, ModuleInfo),
+		{ NumErrors is NumErrors0 + 1 }
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.4
diff -u -r1.4 Mmakefile
--- Mmakefile	1997/11/17 05:48:40	1.4
+++ Mmakefile	1997/11/23 04:21:46
@@ -12,6 +12,7 @@
 	circ_type.m \
 	constructor_warning.m \
 	det_errors.m \
+	duplicate_modes.m \
 	errors.m \
 	errors1.m \
 	errors2.m \
@@ -49,6 +50,7 @@
 
 MCFLAGS-multisoln_func	=	--infer-types
 MCFLAGS-any_mode	=	--infer-types
+MCFLAGS-duplicate_modes	=	--verbose-error-messages
 
 DEPS=		$(SOURCES:%.m=%.dep)
 DEPENDS=	$(SOURCES:%.m=%.depend)
Index: tests/invalid/duplicate_modes.err_exp
===================================================================
RCS file: duplicate_modes.err_exp
diff -N duplicate_modes.err_exp
--- /dev/null	Sun Nov 23 15:00:37 1997
+++ duplicate_modes.err_exp	Sun Nov 23 15:20:00 1997
@@ -0,0 +1,18 @@
+duplicate_modes.m:004: In mode declarations for predicate `duplicate_modes:p/0':
+duplicate_modes.m:004:   error: duplicate mode declaration.
+duplicate_modes.m:004:   Modes `p'
+duplicate_modes.m:004:   and `p is det'
+duplicate_modes.m:004:   are indistinguishable.
+duplicate_modes.m:003:   Here is the conflicting mode declaration.
+duplicate_modes.m:008: In mode declarations for predicate `duplicate_modes:q/2':
+duplicate_modes.m:008:   error: duplicate mode declaration.
+duplicate_modes.m:008:   Modes `q(in, out) is det'
+duplicate_modes.m:008:   and `q((ground -> ground), (free -> ground)) is det'
+duplicate_modes.m:008:   are indistinguishable.
+duplicate_modes.m:009:   Here is the conflicting mode declaration.
+duplicate_modes.m:015: In mode declarations for predicate `duplicate_modes:r/2':
+duplicate_modes.m:015:   error: duplicate mode declaration.
+duplicate_modes.m:015:   Modes `r(in, in) is det'
+duplicate_modes.m:015:   and `r(in, in) is semidet'
+duplicate_modes.m:015:   are indistinguishable.
+duplicate_modes.m:014:   Here is the conflicting mode declaration.
Index: tests/invalid/duplicate_modes.m
===================================================================
RCS file: duplicate_modes.m
diff -N duplicate_modes.m
--- /dev/null	Sun Nov 23 15:00:37 1997
+++ duplicate_modes.m	Sun Nov 23 15:21:57 1997
@@ -0,0 +1,34 @@
+:- module duplicate_modes.
+
+:- pred p.
+:- mode p is det.
+p.
+
+:- pred q(int, int).
+:- mode q(ground -> ground, free -> ground) is det.
+:- mode q(in, out) is det.
+
+q(X, X).
+
+:- pred r(int, int).
+:- mode r(in, in) is det.
+:- mode r(in, in) is semidet.
+
+r(_, _).
+
+% this one is legal (albeit not yet supported)
+:- pred s(int, int).
+:- mode s(in, out) is multi.
+:- mode s(in, out) is cc_multi.
+
+s(_, 42).
+s(_, 43).
+
+% this one is legal (albeit not yet supported)
+:- pred t(int, int).
+:- mode t(in(bound(1)), out) is multi.
+:- mode t(in(bound(2)), out) is cc_multi.
+
+t(_, 42).
+t(_, 43).
+

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list