[m-rev.] for review: emit errors about purity mismatches with foreign clauses

Julien Fischer juliensf at csse.unimelb.edu.au
Thu Jul 6 12:13:59 AEST 2006


On Thu, 6 Jul 2006, Ian MacLarty wrote:

> On Wed, Jul 05, 2006 at 05:54:08PM +1000, Julien Fischer wrote:
> >
> > For review by anyone.
> >
> > Estimated hours taken: 4
> > Branches: main, release
> >
> > Make it an error for the (promised) purity of a foreign clause to disagree
> > with the declared purity of the corresponding predicate or function
> > declaration.  We only perform this check in the absence of a
> > promise_{pure,semipure} pragma for the predicate or function.
> >
>
> What happens if the predicate is declared impure, but there is a pragma
> promise_pure on the predicate?  Is that allowed?

No.  AFAIK the compiler's handling of purity pragmas is correct.  This
diff is dealing with purity foreign code attributes which is (currently)
not.

> If so what does it mean?

It's an error.

> > Previously this situation was sometimes picked up by purity analysis but not
> > in all cases.  For example, if a predicate was declared impure but the
> > foreign_proc was promised pure it wasn't reported.  In that particular case
> > it was a problem because if the foreign_proc did not have any outputs, then
> > simplify.m might have optimised its body away (which is how I noticed this).
> >
> > compiler/add_pramga.m:
> > 	In the absence of promise_{pure,semipure} pragmas emit error messages
> > 	about mismatches between the declared purity of a procedure and the
> > 	(promised) purity of a foreign clause for it.
> >
> > library/private_builtin.m:
> > library/solutions.m:
> > 	Delete bogus purity promises from foreign_proc attributes reported by
> > 	the new error.
> >
> > tests/invalid/Mmakefile:
> > tests/invalid/foreign_purity_mismatch.{m,err_exp}:
> > 	Test case for the new error.
> >
> > compiler/simplify.m:
> > compiler/prog_io_pragma.m:
> > 	Fix some formatting.
> >
> > Julien.
> >
> > Index: compiler/add_pragma.m
> > ===================================================================
> > RCS file: /home/mercury1/repository/mercury/compiler/add_pragma.m,v
> > retrieving revision 1.35
> > diff -u -r1.35 add_pragma.m
> > --- compiler/add_pragma.m	15 Jun 2006 19:36:57 -0000	1.35
> > +++ compiler/add_pragma.m	5 Jul 2006 07:15:37 -0000
> > @@ -1422,11 +1422,12 @@
> >      PredModule = pred_info_module(!.PredInfo),
> >      pred_info_clauses_info(!.PredInfo, Clauses0),
> >      pred_info_get_purity(!.PredInfo, Purity),
> > +    pred_info_get_markers(!.PredInfo, Markers),
> >
> >      % Add the code for this `pragma import' to the clauses_info.
> >      clauses_info_add_pragma_foreign_proc(Purity, Attributes, PredId, ProcId,
> >          VarSet, PragmaVars, ArgTypes, PragmaImpl, Context, PredOrFunc,
> > -        qualified(PredModule, PredName), Arity, Clauses0, Clauses,
> > +        qualified(PredModule, PredName), Arity, Markers, Clauses0, Clauses,
> >          !ModuleInfo, !IO),
> >
> >      % Store the clauses_info etc. back into the pred_info.
> > @@ -1573,10 +1574,11 @@
> >                  pred_info_clauses_info(!.PredInfo, Clauses0),
> >                  pred_info_get_arg_types(!.PredInfo, ArgTypes),
> >                  pred_info_get_purity(!.PredInfo, Purity),
> > +                pred_info_get_markers(!.PredInfo, Markers),
> >                  clauses_info_add_pragma_foreign_proc(Purity, Attributes,
> >                      PredId, ProcId, ProgVarSet, PVars, ArgTypes, PragmaImpl,
> > -                    Context, PredOrFunc, PredName, Arity, Clauses0, Clauses,
> > -                    !ModuleInfo, !IO),
> > +                    Context, PredOrFunc, PredName, Arity, Markers,
> > +                    Clauses0, Clauses, !ModuleInfo, !IO),
> >                  pred_info_set_clauses_info(Clauses, !PredInfo),
> >                  pred_info_update_goal_type(pragmas, !PredInfo),
> >                  map.det_update(Preds0, PredId, !.PredInfo, Preds),
> > @@ -2364,12 +2366,13 @@
> >      pragma_foreign_proc_attributes::in, pred_id::in, proc_id::in,
> >      prog_varset::in, list(pragma_var)::in, list(mer_type)::in,
> >      pragma_foreign_code_impl::in, prog_context::in, pred_or_func::in,
> > -    sym_name::in, arity::in, clauses_info::in, clauses_info::out,
> > -    module_info::in, module_info::out, io::di, io::uo) is det.
> > +    sym_name::in, arity::in, pred_markers::in,
> > +    clauses_info::in, clauses_info::out, module_info::in, module_info::out,
> > +    io::di, io::uo) is det.
> >
> >  clauses_info_add_pragma_foreign_proc(Purity, Attributes0, PredId, ProcId,
> >          PVarSet, PVars, OrigArgTypes, PragmaImpl0, Context, PredOrFunc,
> > -        PredName, Arity, !ClausesInfo, !ModuleInfo, !IO) :-
> > +        PredName, Arity, Markers, !ClausesInfo, !ModuleInfo, !IO) :-
> >
> >      !.ClausesInfo = clauses_info(VarSet0, ExplicitVarTypes, TVarNameMap,
> >          InferredVarTypes, HeadVars, ClauseRep, RttiVarMaps,
> > @@ -2434,7 +2437,43 @@
> >          % Build the foreign_proc.
> >          goal_info_init(GoalInfo0),
> >          goal_info_set_context(Context, GoalInfo0, GoalInfo1),
> > +        %
> > +        % Check that the purity of the predicate/function declaration agrees
> > +        % with the (promised) purity of the foreign_proc.  It is only okay for
> > +        % them to disagree if there is a `:- pragma promise_pure' or
> > +        % `:- pramga promise_semipure' declaration for the predicate or
> > +        % function.
> > +        %
>
> Could you explain why it's okay for them to disagree in this case?

That's badly explained on my part.  What I was getting at is that a pragma
promise_{semipure,pure} sets the purity of a foreign proc if the purity of the
foreign proc does not have its purity explicitly set via an attribute.

	:- pragma promise_semipure(foo/0).
	:- pragma foreign_proc("C",
		foo,
		[will_not_call_mercury],
	" ... ").


e.g. the above foreign_proc is semipure not impure.

I'll re-write that comment.

> In fact I did a test and the compiler issues a warning if the pred is
> declared impure, but there is a pragma promise_pure.

It's supposed to.

> Actually there seems to be another bug because while the compiler reports a
> warning, it doesn't generate an executable and a non-zero exit status is
> returned (even with --no-halt-at-warn).  Try compiling the following program
> to see what I mean:
>
> :- module pure.
>
> :- interface.
>
> :- import_module io.
>
> :- pred main(io::di, io::uo) is det.
>
> :- implementation.
>
> main(!IO) :-
>         nl(!IO).
>
> :- pragma promise_pure(p/0).
>
> :- impure pred p is det.
>
> :- pragma foreign_proc("C",
>         p,
>         [will_not_call_mercury],
> "
>         printf(\"hello\");
> ").

That is a purity error.

Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list