for review: fix for spurious mode errors

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Oct 28 21:27:05 AEDT 1998


On 02-Oct-1998, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 21-Apr-1998, Thomas Charles CONWAY <conway at hydra.cs.mu.oz.au> wrote:
> > 
> > The following module reports a mode error in main when you try to compile it.
> > It also has an undefined predicate foobie called from foldit.
> > If you fix the undefined predicate error in foldit, the mode error in main
> > goes away.
> 
> After much debugging, I have figured out the cause of this error.
> Basically what happens is that since foldit has a type error,
> typecheck.m deletes it from the list of predicates.
> This means that purity.m does not call post_typecheck__finish_pred
> for that predicate, which means that the mode declaration for that
> predicate does not get module-qualified.  This then leads to
> a spurious mode error in main/2 where it calls foldit.

Here's the fix.  Tom, could you please review this one?

----------------------

Estimated hours taken: 6

Fix a bug where type errors were causing spurious mode errors,

compiler/post_typecheck.m:
	Add new predicate post_typecheck__ill_typed_pred,
	which just module-qualifies the pred declaration for that pred.
	This is necessary to avoid spurious mode errors in predicates
	that call the ill-typed pred.

compiler/typecheck.m:
	Call post_typecheck__ill_typed_pred on ill-typed predicates
	before calling module_info_remove_pred.  We need to call it
	here because later passes won't process the pred once it
	has been removed.

tests/invalid/Mmakefile:
tests/invalid/spurious_mode_error.m:
tests/invalid/spurious_mode_error.err_exp:
	Regression test for the above-mentioned bug.

Index: compiler/post_typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/post_typecheck.m,v
retrieving revision 1.2
diff -u -r1.2 post_typecheck.m
--- post_typecheck.m	1998/07/08 20:57:07	1.2
+++ post_typecheck.m	1998/10/07 05:21:27
@@ -70,6 +70,10 @@
 		pred_info, pred_info, io__state, io__state).
 :- mode post_typecheck__finish_imported_pred(in, in, in, out, di, uo) is det.
 
+:- pred post_typecheck__finish_ill_typed_pred(module_info, pred_id,
+		pred_info, pred_info, io__state, io__state).
+:- mode post_typecheck__finish_ill_typed_pred(in, in, in, out, di, uo) is det.
+
 %-----------------------------------------------------------------------------%
 :- implementation.
 
@@ -301,15 +305,40 @@
 post_typecheck__finish_pred(ModuleInfo, PredId, PredInfo1, PredInfo) -->
 	{ maybe_add_default_mode(ModuleInfo, PredInfo1, PredInfo2, _) },
 	{ copy_clauses_to_procs(PredInfo2, PredInfo3) },
-	post_typecheck__finish_imported_pred(ModuleInfo, PredId,
+	post_typecheck__propagate_types_into_modes(ModuleInfo, PredId,
 			PredInfo3, PredInfo).
 
+	%
+	% For ill-typed preds, we just need to set the modes up correctly
+	% so that any calls to that pred from correctly-typed predicates
+	% won't result in spurious mode errors.
+	%
+post_typecheck__finish_ill_typed_pred(ModuleInfo, PredId,
+		PredInfo0, PredInfo) -->
+	{ maybe_add_default_mode(ModuleInfo, PredInfo0, PredInfo1, _) },
+	post_typecheck__propagate_types_into_modes(ModuleInfo, PredId,
+		PredInfo1, PredInfo).
+
+	% 
+	% For imported preds, we just need to ensure that all
+	% constructors occurring in predicate mode declarations are
+	% module qualified.
+	% 
+post_typecheck__finish_imported_pred(ModuleInfo, PredId,
+		PredInfo0, PredInfo) -->
+	post_typecheck__propagate_types_into_modes(ModuleInfo, PredId,
+		PredInfo0, PredInfo).
+
 	% 
 	% Ensure that all constructors occurring in predicate mode
 	% declarations are module qualified.
 	% 
-post_typecheck__finish_imported_pred(ModuleInfo, PredId, PredInfo0, PredInfo)
-		-->
+:- pred post_typecheck__propagate_types_into_modes(module_info, pred_id,
+		pred_info, pred_info, io__state, io__state).
+:- mode post_typecheck__propagate_types_into_modes(in, in, in, out, di, uo)
+		is det.
+post_typecheck__propagate_types_into_modes(ModuleInfo, PredId, PredInfo0,
+		PredInfo) -->
 	{ pred_info_arg_types(PredInfo0, ArgTypes) },
 	{ pred_info_procedures(PredInfo0, Procs0) },
 	{ pred_info_procids(PredInfo0, ProcIds) },
Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.252
diff -u -r1.252 typecheck.m
--- typecheck.m	1998/10/02 06:23:55	1.252
+++ typecheck.m	1998/10/28 10:18:45
@@ -159,6 +159,7 @@
 
 :- implementation.
 
+:- import_module post_typecheck.
 :- import_module hlds_goal, prog_util, type_util, modules, code_util.
 :- import_module prog_data, prog_io, prog_io_util, prog_out, hlds_out.
 :- import_module mercury_to_mercury, mode_util, options, getopt, globals.
@@ -263,33 +264,47 @@
 	(
 		{ pred_info_is_imported(PredInfo0) }
 	->
-		{ Error1 = Error0 },
-		{ ModuleInfo1 = ModuleInfo0 },
+		{ Error2 = Error0 },
+		{ ModuleInfo2 = ModuleInfo0 },
 		{ Changed2 = Changed0 }
 	;
 		typecheck_pred_type(PredId, PredInfo0, ModuleInfo0, 
-			MaybePredInfo, Changed1),
-		{
-			MaybePredInfo = yes(PredInfo),
-			Error1 = Error0,
-			map__det_update(Preds0, PredId, PredInfo, Preds),
-			module_info_set_preds(ModuleInfo0, Preds, ModuleInfo1)
+			PredInfo1, Error1, Changed1),
+		(
+			{ Error1 = no },
+			{ map__det_update(Preds0, PredId, PredInfo1, Preds) },
+			{ module_info_set_preds(ModuleInfo0, Preds,
+				ModuleInfo2) }
 		;
-			MaybePredInfo = no,
-			Error1 = yes,
-			module_info_remove_predid(ModuleInfo0, PredId,
-				ModuleInfo1)
-		},
+			{ Error1 = yes },
+			%
+			% if we get an error, we need to call
+			% post_typecheck__finish_ill_typed_pred on the
+			% pred, to ensure that its mode declaration gets
+			% properly module qualified; then we call
+			% `remove_predid', so that the predicate's definition
+			% will be ignored by later passes (the declaration
+			% will still be used to check any calls to it).
+			%
+			post_typecheck__finish_ill_typed_pred(ModuleInfo0,
+				PredId, PredInfo1, PredInfo),
+			{ map__det_update(Preds0, PredId, PredInfo, Preds) },
+			{ module_info_set_preds(ModuleInfo0, Preds,
+				ModuleInfo1) },
+			{ module_info_remove_predid(ModuleInfo1, PredId,
+				ModuleInfo2) }
+		),
+		{ bool__or(Error0, Error1, Error2) },
 		{ bool__or(Changed0, Changed1, Changed2) }
 	),
-	typecheck_pred_types_2(PredIds, ModuleInfo1, ModuleInfo, 
-		Error1, Error, Changed2, Changed).
+	typecheck_pred_types_2(PredIds, ModuleInfo2, ModuleInfo, 
+		Error2, Error, Changed2, Changed).
 
 :- pred typecheck_pred_type(pred_id, pred_info, module_info,
-	maybe(pred_info), bool, io__state, io__state).
-:- mode typecheck_pred_type(in, in, in, out, out, di, uo) is det.
+		pred_info, bool, bool, io__state, io__state).
+:- mode typecheck_pred_type(in, in, in, out, out, out, di, uo) is det.
 
-typecheck_pred_type(PredId, PredInfo0, ModuleInfo, MaybePredInfo, Changed,
+typecheck_pred_type(PredId, PredInfo0, ModuleInfo, PredInfo, Error, Changed,
 		IOState0, IOState) :-
 	(
 	    % Compiler-generated predicates are created already type-correct,
@@ -308,7 +323,7 @@
 	    ;
 	        PredInfo = PredInfo0
 	    ),
-	    MaybePredInfo = yes(PredInfo),
+	    Error = no,
 	    Changed = no,
 	    IOState = IOState0
 	;
@@ -334,12 +349,13 @@
 				VarTypes, HeadVars, Clauses0),
 			pred_info_set_clauses_info(PredInfo0, ClausesInfo,
 				PredInfo),
-			MaybePredInfo = yes(PredInfo),
+			Error = no,
 			Changed = no
 		;
 			report_error_no_clauses(PredId, PredInfo0, ModuleInfo,
 			    IOState0, IOState),
-			MaybePredInfo = no,
+			PredInfo = PredInfo0,
+			Error = yes,
 			Changed = no
 		)
 	    ;
@@ -513,13 +529,6 @@
 			Changed = no
 		),
 		typecheck_info_get_found_error(TypeCheckInfo4, Error),
-		(
-			Error = yes,
-			MaybePredInfo = no
-		;
-			Error = no,
-			MaybePredInfo = yes(PredInfo)
-		),
 		typecheck_info_get_io_state(TypeCheckInfo4, IOState)
 	    )
 	).
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.30
diff -u -r1.30 Mmakefile
--- Mmakefile	1998/10/28 06:15:19	1.30
+++ Mmakefile	1998/10/28 10:23:28
@@ -41,6 +41,7 @@
 	prog_io_erroneous.m \
 	qual_basic_test2.m \
 	qualified_cons_id2.m \
+	spurious_mode_error.m \
 	test_nested.m \
 	type_inf_loop.m \
 	type_loop.m \
Index: tests/invalid/spurious_mode_error.err_exp
===================================================================
RCS file: spurious_mode_error.err_exp
diff -N spurious_mode_error.err_exp
--- /dev/null	Wed Oct 28 21:24:31 1998
+++ spurious_mode_error.err_exp	Wed Oct 28 21:24:04 1998
@@ -0,0 +1,3 @@
+spurious_mode_error.m:079: In clause for predicate `spurious_mode_error:foldit/4':
+spurious_mode_error.m:079:   error: undefined predicate `foobie/3'.
+For more information, try recompiling with `-E'.
Index: tests/invalid/spurious_mode_error.m
===================================================================
RCS file: spurious_mode_error.m
diff -N spurious_mode_error.m
--- /dev/null	Wed Oct 28 21:24:31 1998
+++ spurious_mode_error.m	Wed Oct 28 21:23:44 1998
@@ -0,0 +1,126 @@
+:- module spurious_mode_error.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- import_module char, float, int, list, string, std_util.
+
+:- type opt(T)
+	--->	a(pred(int, T, T))
+	;	b(pred(string, T, T))
+	;	c(pred(float, T, T))
+	.
+
+:- inst opt = bound((
+		a(pred(in, in, out) is det)
+	;	b(pred(in, in, out) is det)
+	;	c(pred(in, in, out) is det)
+)).
+
+:- type f(T)
+	--->	f(
+			maybe(pred(int, T, T)),
+			maybe(pred(string, T, T)),
+			maybe(pred(float, T, T))
+		).
+
+:- inst m(I) = bound((no ; yes(I))).
+
+:- inst f = bound(f(
+		m(pred(in, in, out) is det),
+		m(pred(in, in, out) is det),
+		m(pred(in, in, out) is det)
+	)).
+
+main -->
+	{ makeit([a(foo), b(bar), c(baz)], f(no, no, no), Thing) },
+	{ foldit([i(23), s("42"), f(4.2)], Thing, 0, Stuff) },
+	write(Stuff).
+
+:- pred foldit(list(string__poly_type), f(T), T, T).
+:- mode foldit(in, in(f), in, out) is det.
+
+foldit([], _F, T, T).
+foldit([X|Xs], F, T0, T) :-
+	(
+		X = i(I),
+		(
+			F = f(no, _, _),
+			T1 = T0
+		;
+			F = f(yes(Z), _, _),
+			call(Z, I, T0, T1)
+		)
+	;
+		X = s(S),
+		(
+			F = f(_, no, _),
+			T1 = T0
+		;
+			F = f(_, yes(Z), _),
+			call(Z, S, T0, T1)
+		)
+	;
+		X = f(W),
+		(
+			F = f(_, _, no),
+			T1 = T0
+		;
+			F = f(_, _, yes(Z)),
+			call(Z, W, T0, T1)
+		)
+	;
+		X = c(J),
+		foobie(J, T0, T1)
+	),
+	foldit(Xs, F, T1, T).
+
+:- pred makeit(list(opt(T)), f(T), f(T)).
+:- mode makeit(in(list_skel(opt)), in(f), out(f)) is det.
+
+makeit([], F, F).
+makeit([Opt|Opts], F0, F) :-
+	add_opt(Opt, F0, F1),
+	makeit(Opts, F1, F).
+
+:- pred add_opt(opt(T), f(T), f(T)).
+:- mode add_opt(in(opt), in(f), out(f)) is det.
+
+add_opt(a(Z), F0, F) :-
+	F0 = f(_, B, C),
+	F = f(yes(Z), B, C).
+add_opt(b(Z), F0, F) :-
+	F0 = f(A, _, C),
+	F = f(A, yes(Z), C).
+add_opt(c(Z), F0, F) :-
+	F0 = f(A, B, _),
+	F = f(A, B, yes(Z)).
+
+:- pred foo(int, T, T).
+:- mode foo(in, in, out) is det.
+
+foo(_, T, T).
+
+:- pred bar(string, T, T).
+:- mode bar(in, in, out) is det.
+
+bar(_, T, T).
+
+:- pred baz(float, T, T).
+:- mode baz(in, in, out) is det.
+
+baz(_, T, T).
+
+/* XXX to make the bug go away, uncomment this predicate!
+:- pred foobie(char, T, T).
+:- mode foobie(in, in, out) is det.
+
+foobie(_, T, T).
+*/
+
+

--
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