%-----------------------------------------------------------------------------% % vim: ft=mercury ts=4 sw=4 et %-----------------------------------------------------------------------------% % % This test exhibits many instances of the problem demonstrated by gh72[ab]. % The instances are designed to stress-test the compilation transformation % that implements the fix (compiler/direct_arg_in_out.m). % :- module gh72. :- interface. :- import_module io. :- pred main(io::di, io::uo) is det. :- implementation. :- import_module list. :- import_module string. :- import_module solutions. %-----------------------------------------------------------------------------% main(!IO) :- conj_tests(!IO), disj_test_init(!IO), switch_test_init(10, !IO), switch_test_init(11, !IO), switch_test_init(12, !IO), switch_test_init(13, !IO), ite_test_init(10, !IO), ite_test_init(11, !IO), ite_test_init(12, !IO), ite_test_init(13, !IO), method_tests("string", "hij", !IO), method_tests("int", 53, !IO). %-----------------------------------------------------------------------------% :- pred conj_tests(io::di, io::uo) is det. conj_tests(!IO) :- A = f1(_), conj_test(A, !IO), B = f2(_), conj_test(B, !IO), C = f3(_), conj_test(C, !IO), D = f4(package("start4", "d")), conj_test(D, !IO). :- pred conj_test(t, io, io). :- mode conj_test(t4 >> ground, di, uo) is det. conj_test(T, !IO) :- fill3("c", T), fill2("b", T), fill1("a", T), io.write_string(dump_t_nl(T), !IO). %-----------------------------------------------------------------------------% :- pred disj_test_init(io::di, io::uo) is det. disj_test_init(!IO) :- io.format("\ndisj_test_init(f1)\n", [], !IO), solutions(disj_init_f1, SolnStrSet1), list.foldl(io.write_string, SolnStrSet1, !IO), io.format("disj_test_init(f2)\n", [], !IO), solutions(disj_init_f2, SolnStrSet2), list.foldl(io.write_string, SolnStrSet2, !IO), io.format("disj_test_init(f3)\n", [], !IO), solutions(disj_init_f3, SolnStrSet3), list.foldl(io.write_string, SolnStrSet3, !IO), io.write_string("end\n", !IO). :- pred disj_init_f1(string). :- mode disj_init_f1(out) is nondet. :- pragma no_inline(disj_init_f1/1). disj_init_f1(Str) :- disj_init(N, f1(_), Str0), Str = string.int_to_string(N) ++ ": " ++ Str0. :- pred disj_init_f2(string). :- mode disj_init_f2(out) is nondet. :- pragma no_inline(disj_init_f2/1). disj_init_f2(Str) :- disj_init(N, f2(_), Str0), Str = string.int_to_string(N) ++ ": " ++ Str0. :- pred disj_init_f3(string). :- mode disj_init_f3(out) is nondet. :- pragma no_inline(disj_init_f3/1). disj_init_f3(Str) :- disj_init(N, f3(_), Str0), Str = string.int_to_string(N) ++ ": " ++ Str0. :- pred disj_init(int, t, string). :- mode disj_init(out, t4 >> ground, out) is nondet. :- pragma no_inline(disj_init/3). :- pragma no_determinism_warning(pred(disj_init/3)). disj_init(N, T, Str) :- ( N = 10, NStr = string.int_to_string(N), fill1("1" ++ NStr, T), fill2("2" ++ NStr, T), fill3("3" ++ NStr, T), ( StrA = NStr ++ ", " ++ dump_t(T) ; StrA = NStr ++ "; " ++ dump_t(T) ) ; N = 11, NStr = string.int_to_string(N), fill1("a" ++ NStr, T), fill23("b" ++ NStr, T), StrA = NStr ++ ", " ++ dump_t(T) ; N = 12, NStr = string.int_to_string(N), fill23(NStr, T), fill1(NStr, T), StrA = NStr ++ ", no_t" ), % Test that the most up-to-date version of T reaches the code % after the disjunction. StrB = dump_t_nl(T), Str = StrA ++ " | " ++ StrB. %-----------------------------------------------------------------------------% :- pred switch_test_init(int::in, io::di, io::uo) is det. switch_test_init(N, !IO) :- io.format("\nswitch_test_init(%d, f1)\n", [i(N)], !IO), solutions(switch_init_f1(N), SolnStrSet1), list.foldl(io.write_string, SolnStrSet1, !IO), io.format("switch_test_init(%d, f2)\n", [i(N)], !IO), solutions(switch_init_f2(N), SolnStrSet2), list.foldl(io.write_string, SolnStrSet2, !IO), io.format("switch_test_init(%d, f3)\n", [i(N)], !IO), solutions(switch_init_f3(N), SolnStrSet3), list.foldl(io.write_string, SolnStrSet3, !IO), io.write_string("end\n", !IO). :- pred switch_init_f1(int, string). :- mode switch_init_f1(in, out) is nondet. :- pragma no_inline(switch_init_f1/2). switch_init_f1(N, Str) :- switch_init(N, f1(_), Str). :- pred switch_init_f2(int, string). :- mode switch_init_f2(in, out) is nondet. :- pragma no_inline(switch_init_f2/2). switch_init_f2(N, Str) :- switch_init(N, f2(_), Str). :- pred switch_init_f3(int, string). :- mode switch_init_f3(in, out) is nondet. :- pragma no_inline(switch_init_f3/2). switch_init_f3(N, Str) :- switch_init(N, f3(_), Str). :- pred switch_init(int, t, string). :- mode switch_init(in, t4 >> ground, out) is nondet. :- pragma no_inline(switch_init/3). switch_init(N, T, StrA ++ " | " ++ StrB) :- NStr = string.int_to_string(N), ( N = 10, fill1("1" ++ NStr, T), fill2("2" ++ NStr, T), fill3("3" ++ NStr, T), ( StrA = NStr ++ ", " ++ dump_t(T) ; StrA = NStr ++ "; " ++ dump_t(T) ) ; N = 11, fill1("a" ++ NStr, T), fill23("b" ++ NStr, T), StrA = NStr ++ ", " ++ dump_t(T) ; N = 12, fill23(NStr, T), fill1(NStr, T), StrA = NStr ++ ", no_t" ), % Test that the most up-to-date version of T reaches the code % after the switch. StrB = dump_t_nl(T). %-----------------------------------------------------------------------------% :- pred ite_test_init(int::in, io::di, io::uo) is det. ite_test_init(N, !IO) :- io.format("\nite_test_init(%d, f1)\n", [i(N)], !IO), solutions(ite_init_f1(N), SolnStrSet1), list.foldl(io.write_string, SolnStrSet1, !IO), io.format("ite_test_init(%d, f2)\n", [i(N)], !IO), solutions(ite_init_f2(N), SolnStrSet2), list.foldl(io.write_string, SolnStrSet2, !IO), io.format("ite_test_init(%d, f3)\n", [i(N)], !IO), solutions(ite_init_f3(N), SolnStrSet3), list.foldl(io.write_string, SolnStrSet3, !IO), io.write_string("end\n", !IO). :- pred ite_init_f1(int, string). :- mode ite_init_f1(in, out) is nondet. :- pragma no_inline(ite_init_f1/2). ite_init_f1(N, Str) :- ite_init(N, f1(_), Str). :- pred ite_init_f2(int, string). :- mode ite_init_f2(in, out) is nondet. :- pragma no_inline(ite_init_f2/2). ite_init_f2(N, Str) :- ite_init(N, f2(_), Str). :- pred ite_init_f3(int, string). :- mode ite_init_f3(in, out) is nondet. :- pragma no_inline(ite_init_f3/2). ite_init_f3(N, Str) :- ite_init(N, f3(_), Str). :- pred ite_init(int, t, string). :- mode ite_init(in, t4 >> ground, out) is nondet. :- pragma no_inline(ite_init/3). ite_init(N, T, StrA ++ " | " ++ StrB) :- NStr = string.int_to_string(N), % While direct_arg_in_out.m is prepared for situations in which % a daio variable such as T is instantiated in both the condition % and the then-part of an if-then-else, we can't test that here, % because if e.g. we move the call to fill1 into the condition, % mode analysis generates an error. ( if N = 10 then fill1("1" ++ NStr, T), fill2("2" ++ NStr, T), fill3("3" ++ NStr, T), ( StrA = NStr ++ ", " ++ dump_t(T) ; StrA = NStr ++ ", " ++ dump_t(T) ) else if N = 11 then fill1("a" ++ NStr, T), fill23("b" ++ NStr, T), StrA = NStr ++ ", " ++ dump_t(T) else if N = 12 then fill23(NStr, T), fill1(NStr, T), StrA = NStr ++ ", no_t" else fail ), % Test that the most up-to-date version of T reaches the code % after the if-then-else. StrB = dump_t_nl(T). %-----------------------------------------------------------------------------% :- pred method_tests(string::in, S::in, io::di, io::uo) is det <= fxc(S). method_tests(Msg, S, !IO) :- io.format("\nmethod test %s\n", [s(Msg)], !IO), fx(S, f1(_), "p1", S1), fx(S, f2(package("test2", "test2")), "p2", S2), fx(S, f3(package("test3", "test3")), "p3", S3), fx(S, f4(package("test4", "test4")), "p4", S4), io.write_string(S1, !IO), io.write_string(S2, !IO), io.write_string(S3, !IO), io.write_string(S4, !IO). :- typeclass fxc(S) where [ pred fx(S, t, string, string), mode fx(in, t234 >> ground, in, out) is det ]. :- instance fxc(string) where [ pred(fx/4) is fx_string ]. :- instance fxc(int) where [ pred(fx/4) is fx_int ]. :- pred fx_string(string, t, string, string). :- mode fx_string(in, t234 >> ground, in, out) is det. fx_string(S0, T, Prefix, Str) :- fill1(S0, T), Str = Prefix ++ " " ++ dump_t_nl(T). :- pred fx_int(int, t, string, string). :- mode fx_int(in, t234 >> ground, in, out) is det. fx_int(I0, T, Prefix, Str) :- fill1(string.int_to_string(I0), T), Str = Prefix ++ " " ++ dump_t_nl(T). %-----------------------------------------------------------------------------% :- type t ---> f1(package) ; f2(package) ; f3(package) ; f4(package). :- inst t4 for t/0 ---> f1(free) ; f2(free) ; f3(free) ; f4(ground). :- inst t34 for t/0 ---> f1(free) ; f2(free) ; f3(ground) ; f4(ground). :- inst t234 for t/0 ---> f1(free) ; f2(ground) ; f3(ground) ; f4(ground). :- type package ---> package(string, string). %-----------------------------------------------------------------------------% :- func dump_t_nl(t) = string. :- pragma no_inline(dump_t_nl/1). dump_t_nl(T) = dump_t(T) ++ "\n". :- func dump_t(t) = string. :- pragma no_inline(dump_t/1). dump_t(f1(Package)) = "f1(" ++ dump_package(Package) ++ ")". dump_t(f2(Package)) = "f2(" ++ dump_package(Package) ++ ")". dump_t(f3(Package)) = "f3(" ++ dump_package(Package) ++ ")". dump_t(f4(Package)) = "f4(" ++ dump_package(Package) ++ ")". :- func dump_package(package) = string. :- pragma no_inline(dump_t/1). dump_package(package(A, B)) = "package(" ++ A ++ ", " ++ B ++ ")". %-----------------------------------------------------------------------------% :- pred fill3(string, t). :- mode fill3(in, t4 >> t34) is det. :- pragma no_inline(fill3/2). fill3(S, T0) :- ( T0 = f1(_) ; T0 = f2(_) ; T0 = f3(package("fill3", S)) ; T0 = f4(_) ). :- pred fill23(string, t). :- mode fill23(in, t4 >> t234) is det. :- pragma no_inline(fill3/2). fill23(S, T0) :- ( T0 = f1(_) ; T0 = f2(package("fill2", S)) ; T0 = f3(package("fill3", S)) ; T0 = f4(_) ). :- pred fill2(string, t). :- mode fill2(in, t34 >> t234) is det. :- pragma no_inline(fill2/2). fill2(S, T0) :- ( T0 = f1(_) ; T0 = f2(package("fill2", S)) ; T0 = f3(_) ; T0 = f4(_) ). :- pred fill1(string, t). :- mode fill1(in, t234 >> ground) is det. :- pragma no_inline(fill1/2). fill1(S, T0) :- ( T0 = f1(package("fill1", S)) ; T0 = f2(_) ; T0 = f3(_) ; T0 = f4(_) ). %-----------------------------------------------------------------------------%