Files
mercury/tests/hard_coded/purity.m
Fergus Henderson 9e7ab444be Fix a bug in unique mode checking.
Estimated hours taken: 4

Fix a bug in unique mode checking.

compiler/unique_modes.m:
	Fix a bug reported by Serge Varennes
	<serge.varennes@detexis.thomson-csf.com>:
	we need to mark variables as `mostly_unique' rather
	than `unique' at all disjunctions, not just at model_non
	disjunctions, because model_semi and even model_det
	disjunctions can still have backtracking from one failing
	disjunct into the next disjunct.

	Also add a couple of comments.

tests/invalid/Mmakefile:
tests/invalid/uniq_modes.m:
tests/invalid/uniq_modes.err_exp:
	Add a regression test for this change.

tests/hard_coded/purity.m:
tests/hard_coded/cc_nondet_disj.m:
	Fix code that the compiler now rejects, due to the above change.
	The compiler is being a bit conservative to reject these cases,
	because the code won't actually violate unique-mode-correctness,
	but the conservatism here with disjunctions is similar to unique
	mode analysis's already existing conservatism with regard to
	if-then-elses, and the work-around for cases like this is easy,
	so I don't consider that to be a significant problem.

	The conservatism in question is that if it sees
	`{ test }, io__write_string("blah")' in a model_det/model_semi
	disjunct or in the condition of an if-then-else, it will report
	a unique mode error, since it doesn't realize that destructive
	update only occurs _after_ we have committed to this branch.

tests/hard_coded/Mmakefile:
	Disable the test case bidirectional.m, since the compiler now
	rejects it, due to the above change to unique_modes.m.
	The compiler is again being overly conservative in its analysis.
	The problem is similar to that in the two test cases above,
	unfortunately there is no easy work-around in this case.
	The compiler really ought to support this style of bidirectional
	code using unique modes, so I do consider this to be a significant
	problem, but the fix is a fair bit of work, so I will deal with
	that as a separate change.
1999-04-16 07:52:12 +00:00

165 lines
4.6 KiB
Mathematica

% Various checks that impurity declarations are treated properly.
:- module purity.
:- interface.
:- import_module io.
:- impure pred main(io__state::di, io__state::uo) is det.
:- implementation.
:- import_module int, list, string.
main -->
impure test1,
impure test2,
impure test3,
impure test4,
impure test1_inline,
impure test2_inline,
impure test3_inline,
impure test4_inline.
:- impure pred test1(io__state::di, io__state::uo) is det.
:- impure pred test2(io__state::di, io__state::uo) is det.
:- impure pred test3(io__state::di, io__state::uo) is det.
:- impure pred test4(io__state::di, io__state::uo) is det.
:- impure pred test1_inline(io__state::di, io__state::uo) is det.
:- impure pred test2_inline(io__state::di, io__state::uo) is det.
:- impure pred test3_inline(io__state::di, io__state::uo) is det.
:- impure pred test4_inline(io__state::di, io__state::uo) is det.
:- impure pred set_x(int::in) is det.
:- pragma c_code(set_x(X::in), will_not_call_mercury, "x=X;" ).
:- pragma no_inline(set_x/1).
:- impure pred incr_x is det.
:- pragma c_code(incr_x, will_not_call_mercury, "++x;" ).
:- pragma no_inline(incr_x/0).
:- semipure pred get_x(int::out) is det.
:- pragma c_code(get_x(X::out), will_not_call_mercury, "X=x;").
:- pragma no_inline(get_x/1).
:- impure pred set_x_inline(int::in) is det.
:- pragma c_code(set_x_inline(X::in), will_not_call_mercury, "x=X;" ).
:- pragma inline(set_x_inline/1).
:- impure pred incr_x_inline is det.
:- pragma c_code(incr_x_inline, will_not_call_mercury, "++x;" ).
:- pragma inline(incr_x_inline/0).
:- semipure pred get_x_inline(int::out) is det.
:- pragma c_code(get_x_inline(X::out), will_not_call_mercury, "X=x;").
:- pragma inline(get_x_inline/1).
:- pragma c_header_code("int x = 0;").
% tempt compiler to optimize away duplicate semipure goals.
test1 -->
{ semipure get_x(X) },
io__format("%d\n", [i(X)]),
{ impure set_x(X+1) },
{ semipure get_x(Y) },
io__format("%d\n", [i(Y)]).
% tempt compiler to optimize away duplicate impure goals, or to compile away
% det goals with no outputs.
test2 -->
{ impure incr_x },
{ impure incr_x },
{ semipure get_x(Y) },
io__format("%d\n", [i(Y)]).
% tempt compiler to optimize away impure goal in branch that cannot succeed.
test3 -->
( { impure incr_x },
{ fail }
; { semipure get_x(Y) }
),
io__format("%d\n", [i(Y)]).
/***
% This test used to be written as follows, but currently
% the unique mode analysis is not smart enough to realize
% that the disjuncts which update the I/O state won't
% backtrack over I/O if the code is written like that.
% tempt compiler to optimize away impure goal in branch that cannot succeed.
test3 -->
( { impure incr_x },
{ fail }
; { semipure get_x(Y) },
io__format("%d\n", [i(Y)])
).
***/
% regression test for problem with calls to implied modes of impure/semipure
% preds reporting spurious warnings about impurity markers in the wrong place.
test4 -->
{ semipure get_x(OldX) },
{ impure incr_x },
( { semipure get_x(OldX+1) } ->
io__write_string("test4 succeeds\n")
; io__write_string("test4 fails\n")
),
{ impure set_x(OldX) }.
% Now do it all again with inlining requested
% tempt compiler to optimize away duplicate semipure goals.
test1_inline -->
{ semipure get_x_inline(X) },
io__format("%d\n", [i(X)]),
{ impure set_x_inline(X+1) },
{ semipure get_x_inline(Y) },
io__format("%d\n", [i(Y)]).
% tempt compiler to optimize away duplicate impure goals, or to compile away
% det goals with no outputs.
test2_inline -->
{ impure incr_x_inline },
{ impure incr_x_inline },
{ semipure get_x_inline(Y) },
io__format("%d\n", [i(Y)]).
% tempt compiler to optimize away impure goal in branch that cannot succeed.
test3_inline -->
( { impure incr_x_inline },
{ fail }
; { semipure get_x_inline(Y) }
),
io__format("%d\n", [i(Y)]).
/***
% This test used to be written as follows, but currently
% the unique mode analysis is not smart enough to realize
% that the disjuncts which update the I/O state won't
% backtrack over I/O if the code is written like that.
% tempt compiler to optimize away impure goal in branch that cannot succeed.
test3_inline -->
( { impure incr_x_inline },
{ fail }
; { semipure get_x_inline(Y) },
io__format("%d\n", [i(Y)])
).
***/
% regression test for problem with calls to implied modes of impure/semipure
% preds reporting spurious warnings about impurity markers in the wrong place.
test4_inline -->
{ semipure get_x_inline(OldX) },
{ impure incr_x_inline },
( { semipure get_x_inline(OldX+1) } ->
io__write_string("test4_inline succeeds\n")
; io__write_string("test4_inline fails\n")
),
{ impure set_x_inline(OldX) }.