For review: Make Mercury cope with impure code
Peter Schachte
pets at cs.mu.oz.au
Fri Dec 5 18:43:59 AEDT 1997
Round 3 for this review.
Fergus asked that I backup my working directory after the last diff
and post the next (this) diff relative to that. Unfortunately, my
snapshotting technology was less that perfectly reliable, and I lost
the changes I made to the tests/invalid directory, so I'm including
the full diffs, which means I'm including the whole files, since
they're all new.
Make Mercury cope with impure code
The purpose of this diff is to allow Mercury programs to contain
impure Mercury code without the compiler changing its behavior
inappropriately, while still allowing the compiler to aggressively
optimize pure code. To do this, we require impure predicates to be so
declared, and calls to impure predicates to be flagged as such. We
also allow predicates implemented in terms of impure predicates to be
promised to be pure; lacking such a promise, any predicate that calls
an impure predicate is assumed to be impure.
At the moment, we don't allow impure functions (only predicates),
though some of the work necessary to support them has been done.
Note that to make the operators work properly, the precedence of the
`pred' and `func' operators has been changed from 1199 to 800.
Estimated hours taken: 150
compiler/purity.m:
New compiler pass for purity checking.
compiler/hlds_goal.m:
Add `impure' and `semipure' to the goal_feature enum.
compiler/hlds_out.m:
compiler/typecheck.m:
compiler/special_pred.m:
Fixed code that prints predicate name to write something more
helpful for special (compiler-generated) predicates. Added
code to print new markers. Added purity argument to
mercury_output_pred_type. New public predicate
special_pred_description/2 provides an english description for
each compiler-generated predicate.
compiler/hlds_pred.m:
Add `impure' and `semipure' to marker enum. Added new
public predicates to get predicate purity and whether or not
it's promised to be pure.
compiler/prog_data.m:
compiler/mercury_to_mercury.m:
compiler/prog_io.m:
compiler/prog_io_goal.m:
compiler/prog_io_pragma.m:
compiler/prog_io_dcg.m:
compiler/prog_util.m:
compiler/equiv_type.m:
compiler/intermod.m:
compiler/mercury_to_c.m:
compiler/module_qual.m:
Add purity argument to pred and func items. Add new `impure'
and `semipure' operators. Add promise_pure pragma. Add
purity/2 wrapper to goal_expr type.
compiler/make_hlds.m:
compiler/mercury_to_goedel.m:
Added purity argument to module_add_{pred,func},
clauses_info_add_pragma_c_code, and to pred and func items.
Handle promise_pure pragma. Handle purity/2 wrapper used to
handle user-written impurity annotations on goals.
compiler/mercury_compile.m:
Add purity checking pass between type and mode checking.
compiler/mode_errors.m:
Distinguish mode errors caused by impure goals preventing
goals being delayed.
compiler/modes.m:
Don't delay impure goals, and ensure before scheduling an
impure goal that no goals are delayed. Actually, we go ahead
and try to schedule goals even if impurity causes a problem,
and then if it still doesn't mode check, then we report an
ordinary mode error. Only if the clause would be mode correct
except for an impure goal do we report it as an impurity problem.
compiler/simplify.m:
Don't optimize away non-pure duplicate calls. We could do
better and still optimize duplicate semipure goals without an
intervening impure goal, but it's probably not worth the
trouble. Also don't eliminate impure goals on a failing branch.
compiler/notes/compiler_design.html:
Documented purity checking pass.
doc/reference_manual.texi:
Document purity system.
doc/transition_guide.texi:
library/nc_builtin.nl:
library/ops.m:
library/sp_builtin.nl:
New operators and new precdence for `pred' and `func'
operators.
tests/hard_coded/purity.m
tests/hard_coded/purity.exp
tests/hard_coded/Mmakefile:
tests/invalid/purity.m
tests/invalid/purity_nonsense.m
tests/invalid/purity.err_exp
tests/invalid/purity_nonsense.err_exp
tests/invalid/Mmakefile:
Test cases for purity.
--- last-make_hlds.m Fri Dec 5 18:25:21 1997
+++ make_hlds.m Fri Dec 5 18:18:39 1997
@@ -3353,9 +3353,9 @@
hlds_out__write_pred_call_id(Name/Arity),
io__write_string("\n"),
prog_out__write_context(Context),
- % XXX is `preceding' the right word here? Can't the pred or func decl
- % appear afterward? Would `corresponding' be a better word?
- io__write_string(" without preceding `pred' or `func' declaration\n").
+ % This used to say `preceding' instead of `corresponding.'
+ % Which is more correct?
+ io__write_string(" without corresponding `pred' or `func' declaration.\n").
:- pred undefined_mode_error(sym_name, int, term__context, string,
io__state, io__state).
--- last-modes.m Fri Dec 5 18:25:22 1997
+++ modes.m Fri Dec 5 10:55:30 1997
@@ -901,16 +901,11 @@
modecheck_goal(G0, G),
mode_checkpoint(exit, "some").
-modecheck_goal_expr(call(PredId0, _, Args0, _, Context, PredName0),
+modecheck_goal_expr(call(PredId, _, Args0, _, Context, PredName),
GoalInfo0, Goal) -->
- % Resolve overloading. This is only necessary when invoked to
- % modecheck a lambda goal; other overloading is handled in purity.m
- =(ModeInfo0),
- { resolve_pred_overloading(PredId0, Args0, PredName0, PredName,
- ModeInfo0, PredId) },
-
mode_checkpoint(enter, "call"),
mode_info_set_call_context(call(PredId)),
+ =(ModeInfo0),
{ mode_info_get_instmap(ModeInfo0, InstMap0) },
modecheck_call_pred(PredId, Args0, Mode, Args, ExtraGoals),
@@ -1215,7 +1210,10 @@
% check whether there are any delayed goals (other than headvar unifications)
% at the point where we are about to schedule an impure goal. If so, that is
-% an error.
+% an error. Headvar unifications are allowed to be delayed because in the
+% case of output arguments, they cannot be scheduled until the variable value
+% is known. If headvar unifications couldn't be delayed past impure goals,
+% impure predicates wouldn't be able to have outputs!
:- pred check_for_impurity_error(hlds_goal, impurity_errors, impurity_errors,
mode_info, mode_info).
:- mode check_for_impurity_error(in, in, out, mode_info_di, mode_info_uo)
@@ -1678,32 +1676,5 @@
{ Module = Module0 }.
-%-----------------------------------------------------------------------------%
-
-:- pred resolve_pred_overloading(pred_id, list(var), sym_name, sym_name,
- mode_info, pred_id).
-:- mode resolve_pred_overloading(in, in, in, out, mode_info_ui, out) is det.
- %
- % In the case of a call to an overloaded predicate, typecheck.m
- % does not figure out the correct pred_id. We must do that here.
- %
-resolve_pred_overloading(PredId0, Args0, PredName0, PredName,
- ModeInfo0, PredId) :-
- ( invalid_pred_id(PredId0) ->
- %
- % Find the set of candidate pred_ids for predicates which
- % have the specified name and arity
- %
- mode_info_get_module_info(ModeInfo0, ModuleInfo0),
- mode_info_get_predid(ModeInfo0, ThisPredId),
- module_info_pred_info(ModuleInfo0, ThisPredId, PredInfo),
- pred_info_typevarset(PredInfo, TVarSet),
- mode_info_get_var_types(ModeInfo0, VarTypes0),
- typecheck__resolve_pred_overloading(ModuleInfo0, Args0,
- VarTypes0, TVarSet, PredName0, PredName, PredId)
- ;
- PredId = PredId0,
- PredName = PredName0
- ).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
--- last-prog_io_dcg.m Fri Dec 5 18:25:23 1997
+++ prog_io_dcg.m Tue Dec 2 17:58:09 1997
@@ -284,10 +284,12 @@
( Goal1 = call(Pred, Args, pure) - Context ->
Goal = call(Pred, Args, Purity) - Context
;
- % XXX Should print a warning: user put an `impure' or
- % `semipure' marker on a non-atomic goal, or else they put
- % multiple markers on a goal.
- Goal = Goal1
+ % Inappropriate placement of an impurity marker, so we treat
+ % it like a predicate call. typecheck.m prints out something
+ % descriptive for these errors.
+ Goal1 = _ - Context,
+ purity_name(Purity, PurityString),
+ Goal = call(unqualified(PurityString), [G], pure) - Context
).
:- pred append_to_disjunct(goal, goal_expr, term__context, goal).
--- last-prog_io_goal.m Fri Dec 5 18:25:25 1997
+++ prog_io_goal.m Tue Dec 2 17:57:46 1997
@@ -251,10 +251,11 @@
( A1 = call(Pred, Args, pure) - _ ->
A = call(Pred, Args, Purity)
;
- % XXX Should print a warning: user put an `impure' or
- % `semipure' marker on a non-atomic goal, or else they put
- % multiple markers on a goal.
- A - _ = A1
+ % Inappropriate placement of an impurity marker, so we treat
+ % it like a predicate call. typecheck.m prints out something
+ % descriptive for these errors.
+ purity_name(Purity, PurityString),
+ A = call(unqualified(PurityString), [A0], pure)
).
--- last-purity.m Fri Dec 5 18:25:26 1997
+++ purity.m Tue Dec 2 16:50:13 1997
@@ -110,11 +110,11 @@
:- import_module make_hlds, hlds_data, hlds_pred, hlds_goal, prog_io_util.
:- import_module type_util, mode_util, code_util, prog_data, unify_proc.
-:- import_module globals, options, mercury_to_mercury, hlds_out, int, set.
+:- import_module globals, options, mercury_to_mercury, hlds_out.
:- import_module passes_aux, typecheck, module_qual, clause_to_proc.
-:- import_module modecheck_unify, modecheck_call, inst_util.
-:- import_module list, map, varset, term, prog_out, string, require, std_util.
-:- import_module assoc_list, bool.
+:- import_module modecheck_unify, modecheck_call, inst_util, prog_out.
+:- import_module list, map, varset, term, string, require, std_util.
+:- import_module assoc_list, bool, int, set.
%-----------------------------------------------------------------------------%
% Public Predicates
@@ -255,7 +255,7 @@
% this is indicated by already having the appropriate goal feature. (During
% the translation from term to goal, calls have their purity attached to
% them, and in the translation from goal to hlds_goal, the attached purity is
-% turned into the appropriate feature in the hlds_goal_info.
+% turned into the appropriate feature in the hlds_goal_info.)
:- pred puritycheck_pred(pred_id, pred_info, pred_info, module_info, int,
io__state, io__state).
@@ -309,12 +309,12 @@
[].
compute_purity([Clause0|Clauses0], [Clause|Clauses], PredInfo, ModuleInfo,
Purity0, Purity, NumErrors0, NumErrors) -->
- { Clause0 = clause(Ids, Body0-Info0, Context) },
+ { Clause0 = clause(Ids, Body0 - Info0, Context) },
compute_expr_purity(Body0, Body, Info0, PredInfo, ModuleInfo,
no, Bodypurity, NumErrors0, NumErrors1),
{ add_goal_info_purity_feature(Info0, Bodypurity, Info) },
{ worst_purity(Purity0, Bodypurity, Purity1) },
- { Clause = clause(Ids, Body-Info, Context) },
+ { Clause = clause(Ids, Body - Info, Context) },
compute_purity(Clauses0, Clauses, PredInfo, ModuleInfo,
Purity1, Purity, NumErrors1, NumErrors).
@@ -378,8 +378,8 @@
{ Unif = unify(A,RHS,C,D,E) },
error_if_body_purity_indicated(GoalInfo, NumErrors0, NumErrors1,
InClosure, "unification"),
- ( { RHS0 = lambda_goal(F, G, H, I, Goal0-Info0) } ->
- { RHS = lambda_goal(F, G, H, I, Goal-Info0) },
+ ( { RHS0 = lambda_goal(F, G, H, I, Goal0 - Info0) } ->
+ { RHS = lambda_goal(F, G, H, I, Goal - Info0) },
compute_expr_purity(Goal0, Goal, Info0, PredInfo, ModuleInfo,
yes, Purity, NumErrors1, NumErrors2),
error_if_closure_impure(GoalInfo, Purity,
@@ -415,15 +415,20 @@
InClosure, Purity3, NumErrors2, NumErrors),
{ worst_purity(Purity1, Purity2, Purity12) },
{ worst_purity(Purity12, Purity3, Purity) }.
-compute_expr_purity(Ccode, Ccode, _, _, _, _, pure, NumErrors, NumErrors) -->
- { Ccode = pragma_c_code(_,_,_,_,_,_,_,_) }.
+compute_expr_purity(Ccode, Ccode, _, _, ModuleInfo, _, Purity,
+ NumErrors, NumErrors) -->
+ { Ccode = pragma_c_code(_,_,PredId,_,_,_,_,_) },
+ { module_info_preds(ModuleInfo, Preds) },
+ { map__lookup(Preds, PredId, PredInfo) },
+ { pred_info_get_purity(PredInfo, Purity) }.
+
:- pred compute_goal_purity(hlds_goal, hlds_goal, pred_info,
module_info, bool, purity, int, int, io__state, io__state).
:- mode compute_goal_purity(in, out, in, in, in, out, in, out, di, uo) is det.
-compute_goal_purity(Goal0-GoalInfo0, Goal-GoalInfo, PredInfo, ModuleInfo,
+compute_goal_purity(Goal0 - GoalInfo0, Goal - GoalInfo, PredInfo, ModuleInfo,
InClosure, Purity, NumErrors0, NumErrors) -->
compute_expr_purity(Goal0, Goal, GoalInfo0, PredInfo, ModuleInfo,
InClosure, Purity, NumErrors0, NumErrors),
@@ -481,19 +486,19 @@
{ pred_info_context(PredInfo, Context) },
write_context_and_pred_id(ModuleInfo, PredInfo, PredId),
prog_out__write_context(Context),
- report_warning(" warning: declared "),
+ report_warning(" warning: declared `"),
write_purity(Purity),
- io__write_string(" but promised pure.\n"),
+ io__write_string("' but promised pure.\n"),
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
( { VerboseErrors = yes } ->
{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
prog_out__write_context(Context),
io__write_string(" A pure "),
hlds_out__write_pred_or_func(PredOrFunc),
- io__write_string(" that invokes non-pure code should be\n"),
+ io__write_string(" that invokes impure or semipure code should\n"),
prog_out__write_context(Context),
io__write_string(
- " promised pure and should have no impurity declaration.\n"
+ " be promised pure and should have no impurity declaration.\n"
)
;
[]
@@ -509,9 +514,9 @@
{ pred_info_context(PredInfo, Context) },
write_context_and_pred_id(ModuleInfo, PredInfo, PredId),
prog_out__write_context(Context),
- report_warning(" warning: declared "),
+ report_warning(" warning: declared `"),
write_purity(DeclPurity),
- io__write_string(" but actually "),
+ io__write_string("' but actually "),
write_purity(AcutalPurity),
io__write_string(".\n").
@@ -531,7 +536,7 @@
io__write_string(" This "),
hlds_out__write_pred_or_func(PredOrFunc),
io__write_string(
- " does not invoke any non-pure code,\n"
+ " does not invoke any impure or semipure code,\n"
),
prog_out__write_context(Context),
io__write_string(
--- last-typecheck.m Fri Dec 5 18:25:29 1997
+++ typecheck.m Thu Dec 4 15:00:20 1997
@@ -3912,12 +3967,14 @@
language_builtin("\\=", 2).
language_builtin(",", 2).
language_builtin(";", 2).
-language_builtin("\\+", 2).
-language_builtin("not", 2).
+language_builtin("\\+", 1).
+language_builtin("not", 1).
language_builtin("<=>", 2).
language_builtin("=>", 2).
language_builtin("<=", 2).
language_builtin("call", _).
+language_builtin("impure", 1).
+language_builtin("semipure", 1).
:- pred write_call_context(term__context, pred_call_id, int, unify_context,
io__state, io__state).
--- last-reference_manual.texi Fri Dec 5 18:25:50 1997
+++ reference_manual.texi Fri Dec 5 18:03:06 1997
@@ -2616,10 +2616,9 @@
the @dfn{strict commutative} operational semantics. This semantics
is equivalent to the strict sequential operational semantics except
that there is no requirement that function calls, conjunctions and disjunctions
-be executed left-to-right; they may be executed in any order.
- at c XXX May they be interleaved?
-(The order may even be different each time a particular goal
-is entered.)
+be executed left-to-right; they may be executed in any order, and may
+even be interleaved. Furthermore, the order may even be different each
+time a particular goal is entered.
As well as providing the strict sequential operational semantics,
Mercury implementations may optionally provide additional
@@ -3354,7 +3353,7 @@
@node Impurity
@section Impurity declarations
-In order to efficiently implement certain predicates, it is sometimes
+In order to efficiently implement certain predicates, it is occasionally
necessary to venture outside pure logic programming. Other predicates
cannot be implemented at all within the paradigm of logic programming,
for example, all solutions predicates. Such predicates are often
@@ -3373,6 +3372,14 @@
that are implemented in terms of impure predictes are assumed to be
impure themselves unless they are explicitly promised to be pure.
+Please note that the facilities described here are needed only very
+rarely. The main intent is for implementing language primitives such as
+the all solutions predicates. Any use of `impure' or `semipure'
+probably indicates either a weakness in the Mercury standard library, or
+the programmer's lack of familiarity with the standard library.
+Newcomers to Mercury are hence encouraged to @strong{skip this section}.
+
+
@menu
* Purity levels:: Choosing the right level of purity
@@ -3401,7 +3408,7 @@
is the behavior of pure predicates ever affected by the invocation of
other predicates.
-Most Mercury predicates are pure.
+The vast majority of Mercury predicates are pure.
@item semipure
Semipure predicates are just like pure predicates, except that their
@@ -3437,13 +3444,14 @@
The operational semantics of a Mercury predicate which invokes impure
code is a modified form of the @emph{strict sequential} semantics
-(@pxref{Semantics}). Firstly, only impure goals may not be reordered
-relative to other goals, pure and semipure goals may be reordered as
-long as they are not moved across an impure goal. Secondly, not even
-``minimal'' reordering of impure goals is permitted; if such reordering
-is needed, this is an error. Execution of impure goals is strict: they
-must be executed if they are reached, even if it can be determined that
-that computation cannot lead to successful termination.
+(@pxref{Semantics}). @emph{Impure} goals may not be reordered relative
+to any other goals; not even ``minimal'' reordering as implied by the
+modes is permitted. If any such reordering is needed, this is a mode
+error. However, @emph{pure} and @emph{semipure} goals may be reordered
+as long as they are not moved across an impure goal. Execution of
+impure goals is strict: they must be executed if they are reached, even
+if it can be determined that that computation cannot lead to successful
+termination.
Semipure goals can be given a ``contextual'' declarative semantics.
They cannot have any side-effects, so it is expected that, given the
@@ -3460,9 +3468,9 @@
@node Declaring impurity
@subsection Declaring predicate impurity
-A predicate is declared to be impure (semipure) by preceding the word
- at code{predicate} in its @code{pred} declaration with @code{impure}
-(@code{semipure}). That is, a declaration of the form:
+A predicate is declared to be impure or semipure by preceding the word
+ at code{pred} in its @code{pred} declaration with @code{impure}
+or @code{semipure}, respectively. That is, a declaration of the form:
@example
:- impure pred @var{Pred}(@var{Arguments...}).
@@ -3482,13 +3490,19 @@
@node Impure calls
@subsection Marking a call as impure
-If a predicate is impure (semipure), all calls to it must be preceded
-with the word @code{impure} (@code{semipure}). This allows someone
+If a predicate is impure or semipure, all calls to it must be preceded
+with the word @code{impure} or @code{semipure}, respectively. Note
+that only predicate calls need to (and are permitted to) be prefixed
+with @code{impure} or @code{semipure}, compound goals never need this.
+See @ref{Impurity Example} for an example of this.
+
+The requiremment that impure or semipure calls be marked with
+ at code{impure} or @code{semipure} allows someone
reading the code to tell which goals are not pure, making code which
-relies on side effects somewhat less mysterious. See @ref{Impurity
-Example} for an example of this. Note that only predicate calls need to
-be prefixed with @code{impure} or @code{semipure}, compound goals never
-need this.
+relies on side effects somewhat less mysterious. Furthermore, it means
+that if a call is @emph{not} preceded by @code{impure} or
+ at code{semipure}, then the reader can rely on the call having a proper
+declarative semantics, without hidden side-effects.
@node Promising purity
@@ -3496,12 +3510,13 @@
Some predicates which call impure or semipure predicates are themselves
pure. In fact, the main purpose of the Mercury impurity system is to
-allow users to write pure predicates using impure ones, while protecting
+allow programmers to write pure predicates using impure ones, while protecting
the procedural implementation from aggressive compiler optimizations.
Of course, the Mercury compiler cannot verify that a predicate is pure,
-so this is the user's responsibility.
+so it is the programmer's responsibility to ensure this. If a predicate
+is promised pure and is not, the behavior of the program is undefined.
-The user may promise that a predicate is pure using the
+The programmer may promise that a predicate is pure using the
@code{promise_pure} pragma:
@example
@@ -3517,12 +3532,13 @@
and so is not useful as is. It is meant only as an example.
@example
-:- pragma c_header_code("int max;").
+:- pragma c_header_code("#include <limits.h>").
+:- pragma c_header_code("Integer max;").
:- impure pred init_max is det.
:- pragma c_code(init_max,
will_not_call_mercury,
- "max = (int)(~(((unsigned)(~0))>>1));").
+ "max = INT_MIN;").
:- impure pred set_max(int::in) is det.
:- pragma c_code(set_max(X::in),
--- last-transition_guide.texi Fri Dec 5 18:25:51 1997
+++ transition_guide.texi Tue Dec 2 14:54:45 1997
@@ -152,9 +152,10 @@
and xfy 720
else xfy 1170
end_module fx 1199
+func fx 800
if fx 1160
import_module fx 1199
-impure fy 1199
+impure fy 800
inst fx 1199
is xfx 700
mod xfx 300
@@ -162,9 +163,9 @@
module fx 1199
not fy 900
or xfy 740
-pred fx 1180
+pred fx 800
rule fx 1199
-semipure fy 1199
+semipure fy 800
some fxy 950
then xfx 1150
type fx 1180
--- last-purity.m Fri Dec 5 18:28:43 1997
+++ purity.m Tue Dec 2 16:06:55 1997
@@ -11,13 +11,20 @@
main -->
impure test1,
impure test2,
- impure test3.
+ impure test3,
+ impure test1_inline,
+ impure test2_inline,
+ impure test3_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 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 set_x(int::in) is det.
:- pragma c_code(set_x(X::in), will_not_call_mercury, "x=X;" ).
@@ -29,6 +36,19 @@
:- pragma c_code(get_x(X::out), will_not_call_mercury, "X=x;").
+:- 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;").
@@ -54,6 +74,32 @@
( { impure incr_x },
{ fail }
; { semipure get_x(Y) },
+ io__format("%d\n", [i(Y)])
+ ).
+
+% Now do it all again with inlining requested
+
+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)])
).
--- last-purity.exp Fri Dec 5 18:28:44 1997
+++ purity.exp Tue Dec 2 16:09:08 1997
@@ -2,3 +2,7 @@
1
3
4
+4
+5
+7
+8
New File: tests/invalid/purity.err_exp
===================================================================
purity.m:028: In predicate `purity:w1/0':
purity.m:028: warning: declared `impure' but actually pure.
purity.m:032: In predicate `purity:w2/0':
purity.m:032: warning: declared `semipure' but actually pure.
purity.m:036: In predicate `purity:w3/0':
purity.m:036: warning: declared `impure' but actually semipure.
purity.m:040: In predicate `purity:w4/0':
purity.m:040: warning: unnecessary `promise_pure' pragma.
purity.m:045: In predicate `purity:w5/0':
purity.m:045: warning: declared `impure' but promised pure.
purity.m:050: In predicate `purity:w6/0':
purity.m:050: warning: declared `semipure' but promised pure.
purity.m:059: In predicate `purity:e1/0':
purity.m:059: error: predicate is impure.
purity.m:059: It must be declared `impure' or promised pure.
purity.m:064: In predicate `purity:e2/0':
purity.m:064: error: predicate is semipure.
purity.m:064: It must be declared `semipure' or promised pure.
purity.m:068: In predicate `purity:e3/0':
purity.m:068: error: predicate is impure.
purity.m:068: It must be declared `impure' or promised pure.
purity.m:074: In call to impure predicate `purity:imp/0':
purity.m:074: error: call must be preceded by `impure' indicator.
purity.m:078: In call to semipure predicate `purity:semi/0':
purity.m:078: error: call must be preceded by `semipure' indicator.
purity.m:112: Error in closure: closure is impure.
purity.m:118: Error in closure: closure is semipure.
purity.m:093: In unification predicate for type (purity:e8):
purity.m:093: error: predicate is impure.
purity.m:093: It must be pure.
purity.m:101: In unification predicate for type (purity:e9):
purity.m:101: error: predicate is semipure.
purity.m:101: It must be pure.
purity.m:083: In clause for `e6':
purity.m:083: in argument 1 of call to predicate `purity:in/1':
purity.m:083: mode error: variable `X' has instantiatedness `free',
purity.m:083: expected instantiatedness was `ground'.
purity.m:083: The goal could not be reordered, because
purity.m:083: it was followed by an impure goal.
purity.m:084: This is the location of the impure goal.
purity.m:090: In clause for `e7':
purity.m:090: in argument 1 of call to predicate `purity:imp1/1':
purity.m:090: mode error: variable `X' has instantiatedness `free',
purity.m:090: expected instantiatedness was `ground'.
purity.m:090: The goal could not be reordered, because it was impure.
For more information, try recompiling with `-E'.
New File: tests/invalid/purity.m
===================================================================
:- module purity.
%----------------------------------------------------------------
% Needed for later tests.
:- type foo ---> a ; b.
:- impure pred imp is det.
:- pragma c_code(imp, will_not_call_mercury, ";").
:- semipure pred semi is semidet.
:- pragma c_code(semi, will_not_call_mercury, "SUCCESS_INDICATOR=0;").
:- pred in(foo).
:- mode in(in) is semidet.
in(a).
:- impure pred imp1(foo).
:- mode imp1(in) is semidet.
:- pragma c_code(imp1(_X::in), will_not_call_mercury, "SUCCESS_INDICATOR=0;").
%----------------------------------------------------------------
% Warnings
:- impure pred w1 is det.
w1.
:- semipure pred w2 is det.
w2.
:- impure pred w3 is semidet.
w3 :- semipure semi.
:- pred w4 is det.
:- pragma promise_pure(w4/0).
w4.
:- impure pred w5 is det.
:- pragma promise_pure(w5/0).
w5 :- impure imp.
:- semipure pred w6 is semidet.
:- pragma promise_pure(w6/0).
w6 :- semipure semi.
%----------------------------------------------------------------
% Errors
:- pred e1 is det.
e1 :- impure imp.
:- pred e2 is semidet.
e2 :- semipure semi.
:- semipure pred e3 is det.
e3 :- impure imp.
:- impure pred e4 is det.
e4 :- imp.
:- semipure pred e5 is semidet.
e5 :- semi.
:- impure pred e6 is semidet.
e6 :-
in(X),
impure imp,
X = a.
:- impure pred e7 is semidet.
e7 :-
impure imp1(X),
X = a.
:- type e8 ---> e8(foo) where equality is imp2.
:- impure pred imp2(e8, e8).
:- mode imp2(in, in) is semidet.
:- pragma c_code(imp2(_X::in, _Y::in), will_not_call_mercury,
"SUCCESS_INDICATOR=0;").
:- type e9 ---> e9(foo) where equality is semi2.
:- semipure pred semi2(e9, e9).
:- mode semi2(in, in) is semidet.
:- pragma c_code(semi2(_X::in, _Y::in), will_not_call_mercury,
"SUCCESS_INDICATOR=0;").
:- pred e10 is semidet.
e10 :-
Goal1 = lambda([] is semidet, imp1(b)),
call(Goal1).
:- pred e11 is semidet.
e11 :-
Goal2 = lambda([] is semidet, semi),
call(Goal2).
New File: tests/invalid/purity_nonsense.err_exp
===================================================================
purity_nonsense.m:003: Error: invalid impurity declaration: func undefined_func = foo.
purity_nonsense.m:005: Syntax error at token 'type': unexpected token at start of (sub)term.
purity_nonsense.m:006: Syntax error at token 'mode': unexpected token at start of (sub)term.
purity_nonsense.m:010: Error: `promise_pure' pragma for purity_nonsense:undefined2/0
purity_nonsense.m:010: without corresponding `pred' or `func' declaration.
purity_nonsense.m:012: Error: clause for predicate `purity_nonsense:e12/0'
purity_nonsense.m:012: without preceding `pred' declaration.
purity_nonsense.m:013: Error: clause for predicate `purity_nonsense:e13/0'
purity_nonsense.m:013: without preceding `pred' declaration.
purity_nonsense.m:008: Error: no clauses for predicate `purity_nonsense:undefined/0'
purity_nonsense.m:012: In clause for predicate `purity_nonsense:e12/0':
purity_nonsense.m:012: in argument 1 of call to predicate `impure/1':
purity_nonsense.m:012: error: the language construct \+/1 should be
purity_nonsense.m:012: used as a goal, not as an expression.
purity_nonsense.m:012: In clause for predicate `purity_nonsense:e12/0':
purity_nonsense.m:012: in argument 1 of call to predicate `impure/1':
purity_nonsense.m:012: in argument 1 of functor `\+/1':
purity_nonsense.m:012: error: the language construct impure/1 should be
purity_nonsense.m:012: used as a goal, not as an expression.
purity_nonsense.m:012: In clause for predicate `purity_nonsense:e12/0':
purity_nonsense.m:012: in argument 1 of call to predicate `impure/1':
purity_nonsense.m:012: in argument 1 of functor `\+/1':
purity_nonsense.m:012: in argument 1 of functor `impure/1':
purity_nonsense.m:012: error: undefined symbol `imp/0'.
purity_nonsense.m:012: In clause for predicate `purity_nonsense:e12/0':
purity_nonsense.m:012: error: `impure' marker in an inappropriate place.
purity_nonsense.m:013: In clause for predicate `purity_nonsense:e13/0':
purity_nonsense.m:013: in argument 1 of call to predicate `semipure/1':
purity_nonsense.m:013: error: the language construct \+/1 should be
purity_nonsense.m:013: used as a goal, not as an expression.
purity_nonsense.m:013: In clause for predicate `purity_nonsense:e13/0':
purity_nonsense.m:013: in argument 1 of call to predicate `semipure/1':
purity_nonsense.m:013: in argument 1 of functor `\+/1':
purity_nonsense.m:013: error: the language construct semipure/1 should be
purity_nonsense.m:013: used as a goal, not as an expression.
purity_nonsense.m:013: In clause for predicate `purity_nonsense:e13/0':
purity_nonsense.m:013: in argument 1 of call to predicate `semipure/1':
purity_nonsense.m:013: in argument 1 of functor `\+/1':
purity_nonsense.m:013: in argument 1 of functor `semipure/1':
purity_nonsense.m:013: error: undefined symbol `semi/0'.
purity_nonsense.m:013: In clause for predicate `purity_nonsense:e13/0':
purity_nonsense.m:013: error: `semipure' marker in an inappropriate place.
For more information, try recompiling with `-E'.
New File: tests/invalid/purity_nonsense.m
===================================================================
:- module purity_nonsense.
:- impure func undefined_func = foo. % no impure functions (yet)
:- impure type badtype ---> oops.
:- impure mode badmode :: free -> free.
:- impure pred undefined.
:- pragma promise_pure(undefined/0).
:- pragma promise_pure(undefined2/0).
e12 :- impure (\+ impure imp).
e13 :- semipure (\+ semipure semi).
More information about the developers
mailing list