[m-rev.] for review: disallow impure parallel conjuncts

Peter Wang wangp at students.cs.mu.oz.au
Tue Aug 15 10:23:47 AEST 2006


Estimated hours taken: 1.5
Branches: main

Disallow impure parallel conjuncts as they can introduce concurrency issues.
e.g. in the following X could be bound to `foo' or `bar' in different runs.

    impure set_mutvar(foo),
    (
	semipure get_mutvar(X)
    &
	impure set_mutvar(bar)
    )


compiler/purity.m:
	When computing the purity of parallel goals, add error messages
	if they are found to be semipure and impure.

tests/invalid/purity/Mmakefile:
tests/invalid/purity/impure_par_conj.err_exp:
tests/invalid/purity/impure_par_conj.m:
	Add a test case.


Index: compiler/purity.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.97
diff -u -r1.97 purity.m
--- compiler/purity.m	27 Jul 2006 05:01:22 -0000	1.97
+++ compiler/purity.m	14 Aug 2006 23:59:10 -0000
@@ -460,8 +460,15 @@
 
 compute_expr_purity(conj(ConjType, Goals0), conj(ConjType, Goals), _,
         Purity, ContainsTrace, !Info) :-
-    compute_goals_purity(Goals0, Goals, purity_pure, Purity,
-        contains_no_trace_goal, ContainsTrace, !Info).
+    (
+        ConjType = plain_conj,
+        compute_goals_purity(Goals0, Goals, purity_pure, Purity,
+            contains_no_trace_goal, ContainsTrace, !Info)
+    ;
+        ConjType = parallel_conj,
+        compute_parallel_goals_purity(Goals0, Goals, purity_pure, Purity,
+            contains_no_trace_goal, ContainsTrace, !Info)
+    ).
 compute_expr_purity(Goal0, Goal, GoalInfo, ActualPurity,
         contains_no_trace_goal, !Info) :-
     Goal0 = plain_call(PredId0, ProcId, Vars, BIState, UContext, Name0),
@@ -905,6 +912,30 @@
     !:ContainsTrace = worst_contains_trace(GoalContainsTrace, !.ContainsTrace),
     compute_cases_purity(Cases0, Cases, !Purity, !ContainsTrace, !Info).
 
+:- pred compute_parallel_goals_purity(list(hlds_goal)::in,
+    list(hlds_goal)::out, purity::in, purity::out, contains_trace_goal::in,
+    contains_trace_goal::out, purity_info::in, purity_info::out) is det.
+
+compute_parallel_goals_purity([], [], !Purity, !ContainsTrace, !Info).
+compute_parallel_goals_purity([Goal0 | Goals0], [Goal | Goals], !Purity,
+        !ContainsTrace, !Info) :-
+    compute_goal_purity(Goal0, Goal, GoalPurity, GoalContainsTrace, !Info),
+    (
+        GoalPurity = purity_pure
+    ;
+        ( GoalPurity = purity_semipure
+        ; GoalPurity = purity_impure
+        ),
+        Goal0 = _ - GoalInfo0,
+        goal_info_get_context(GoalInfo0, Context),
+        purity_info_add_message(error(impure_parallel_conjunct_error(Context,
+            GoalPurity)), !Info)
+    ),
+    !:Purity = worst_purity(GoalPurity, !.Purity),
+    !:ContainsTrace = worst_contains_trace(GoalContainsTrace, !.ContainsTrace),
+    compute_parallel_goals_purity(Goals0, Goals, !Purity, !ContainsTrace,
+        !Info).
+
 :- func worst_contains_trace(contains_trace_goal, contains_trace_goal)
     = contains_trace_goal.
 
@@ -1045,7 +1076,8 @@
     --->    missing_body_impurity_error(prog_context, pred_id)
     ;       closure_purity_error(prog_context, purity, purity)
             % closure_purity_error(Context, DeclaredPurity, ActualPurity)
-    ;       impure_unification_expr_error(prog_context, purity).
+    ;       impure_unification_expr_error(prog_context, purity)
+    ;       impure_parallel_conjunct_error(prog_context, purity).
 
 :- type post_typecheck_warning
     --->    unnecessary_body_impurity_decl(prog_context, pred_id, purity)
@@ -1065,6 +1097,9 @@
     ;
         Message = impure_unification_expr_error(Context, Purity),
         impure_unification_expr_error(Context, Purity, !IO)
+    ;
+        Message = impure_parallel_conjunct_error(Context, Purity),
+        impure_parallel_conjunct_error(Context, Purity, !IO)
     ).
 
 report_post_typecheck_message(ModuleInfo, warning(Warning), !IO) :-
@@ -1175,6 +1210,16 @@
         words("but expression was not a function call.")],
     write_error_pieces(Context, 0, Pieces, !IO).
 
+:- pred impure_parallel_conjunct_error(prog_context::in, purity::in,
+    io::di, io::uo) is det.
+
+impure_parallel_conjunct_error(Context, Purity, !IO) :-
+    purity_name(Purity, PurityName),
+    Pieces = [words("Purity error: parallel conjunct is"),
+        fixed(PurityName ++ ","),
+        words("but parallel conjuncts must be pure.")],
+    write_error_pieces(Context, 0, Pieces, !IO).
+
 %-----------------------------------------------------------------------------%
 
 :- type purity_info
Index: tests/invalid/purity/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/purity/Mmakefile,v
retrieving revision 1.9
diff -u -r1.9 Mmakefile
--- tests/invalid/purity/Mmakefile	21 Dec 2005 22:11:58 -0000	1.9
+++ tests/invalid/purity/Mmakefile	14 Aug 2006 23:48:15 -0000
@@ -9,6 +9,7 @@
 	impure_func_t5 \
 	impure_func_t5_fixed \
 	impure_func_t7 \
+	impure_par_conj \
 	impure_pred_t1 \
 	impure_pred_t1_fixed \
 	impure_pred_t2 \
Index: tests/invalid/purity/impure_par_conj.err_exp
===================================================================
RCS file: tests/invalid/purity/impure_par_conj.err_exp
diff -N tests/invalid/purity/impure_par_conj.err_exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/purity/impure_par_conj.err_exp	15 Aug 2006 00:04:38 -0000
@@ -0,0 +1,8 @@
+impure_par_conj.m:014: Purity error: parallel conjunct is semipure, but
+impure_par_conj.m:014:   parallel conjuncts must be pure.
+impure_par_conj.m:018: Purity error: parallel conjunct is impure, but parallel
+impure_par_conj.m:018:   conjuncts must be pure.
+impure_par_conj.m:022: Purity error: parallel conjunct is impure, but parallel
+impure_par_conj.m:022:   conjuncts must be pure.
+impure_par_conj.m:024: Purity error: parallel conjunct is semipure, but
+impure_par_conj.m:024:   parallel conjuncts must be pure.
Index: tests/invalid/purity/impure_par_conj.m
===================================================================
RCS file: tests/invalid/purity/impure_par_conj.m
diff -N tests/invalid/purity/impure_par_conj.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/purity/impure_par_conj.m	15 Aug 2006 00:19:42 -0000
@@ -0,0 +1,40 @@
+% We disallow impure parallel conjuncts as they can introduce concurrency
+% issues.
+
+:- module impure_par_conj.
+:- interface.
+:- import_module io.
+
+:- impure pred main(io::di, io::uo) is det.
+
+:- implementation.
+:- import_module int.
+
+main(!IO) :-
+    ( semipure get_mut(_)
+    & true
+    ),
+    ( true
+    & impure set_mut(1)
+    & true
+    ),
+    ( true
+    & impure set_mut(1)
+    & true
+    & semipure get_mut(_)
+    & true
+    ),
+    (
+	% This would be okay if the mutable was `thread_local' (which it isn't,
+	% as they're not implemented yet) or if you are absolutely certain that
+	% this mutable is only used by one thread (as in this case).
+	promise_pure
+	(
+	    semipure get_mut(X),
+	    impure set_mut(X + 1)
+	)
+    &
+	true
+    ).
+
+:- mutable(mut, int, 0, ground, [untrailed]).
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list