mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-24 13:53:54 +00:00
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.
165 lines
4.6 KiB
Mathematica
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) }.
|