[m-dev.] for review: allow impurity on class methods

Tyson Dowd trd at cs.mu.OZ.AU
Sun Mar 26 14:11:29 AEST 2000


On 25-Mar-2000, David Glen JEFFERY <dgj at ender.cs.mu.oz.au> wrote:
> Hi,
> 
> This is for Tyson to review.
> 
> -----------------------------------------------------------------------------
> 
> Estimated hours taken: 6
> 
> Allow class methods to be impure or semipure. Previously any purity annotation
> on a class method was ignored, and the method assumed to be pure. (We have
> for some time caught the case of providing an impure implementation for
> a (pure) class method, though).
> 
> compiler/prog_data.m:
> 	Add purity to the information we store about each method.
> compiler/prog_io_typeclass.m:
> 	Record the declared purity of each method.
> compiler/make_hlds.m:
> 	For the predicate we generate corresponding to a method, add any
> 	purity annotations that the method has.
> compiler/check_typeclass.m:
> 	Add the appropriate impurity marker to the predicate we generate for
> 	each instance method.
> compiler/purity.m:
> 	Be careful not to spit out spurious purity warnings:
> 		- Never warn about excessive impurity for a class methods.
> 		  (The body of the method is just class_method_call, which
> 		  never looks impure as far as it is concerned).
> 		- Never warn about excessive impurity for class instance
> 		  method. The fact that a method is impure doesn't mean that
> 		  its instances need to be impure, and it would be excessive
> 		  to warn about it, seeing that there is no way for the user
> 		  to avoid it (other than actually making their implementation
> 		  impure...).
> compiler/mercury_to_mercury.m:
> 	Print out method purity in interface files.
> compiler/module_qual.m:
> compiler/equiv_type.m:
> 	Handle the fact that we now store purity info for class methods.
> 
> tests/hard_coded/typeclasses/impure_methods.{m,exp}:
> 	A test case for this change.
> tests/hard_coded/typeclasses/Mmakefile:
> 	Turn this change on.

> Index: purity.m
> ===================================================================
> RCS file: /home/staff/zs/imp/mercury/compiler/purity.m,v
> retrieving revision 1.22
> diff -u -t -r1.22 purity.m
> --- purity.m	2000/01/13 06:17:02	1.22
> +++ purity.m	2000/03/25 06:47:17
> @@ -455,7 +455,8 @@
>                                                   ActualPurity),
>                  { NumErrors is NumErrors0 + 1 }
>          ;
> -                warn_unnecessary_body_impurity_decl(ModuleInfo, CalleePredInfo,
> +                warn_unnecessary_body_impurity_decl(ModuleInfo, PredInfo,
> +                                                    CalleePredInfo,
>                                                      PredId, CallContext,
>                                                      ActualPurity,
>                                                      DeclaredPurity),
> @@ -708,14 +709,28 @@
>  
>  warn_exaggerated_impurity_decl(ModuleInfo, PredInfo, PredId,
>                  DeclPurity, AcutalPurity) -->
> -        { pred_info_context(PredInfo, Context) },
> -        write_context_and_pred_id(ModuleInfo, PredInfo, PredId),
> -        prog_out__write_context(Context),
> -        report_warning("  warning: declared `"),
> -        write_purity(DeclPurity),
> -        io__write_string("' but actually "),
> -        write_purity(AcutalPurity),
> -        io__write_string(".\n").
> +        (
> +                        % A class method can't have exaggerated impurity...
> +                        % the impurity means that implementations are *allowed*
> +                        % to be impure.
> +                { pred_info_get_markers(PredInfo, Markers) },
> +                { 
> +                        check_marker(Markers, class_method) 
> +                ;
> +                        check_marker(Markers, class_instance_method) 
> +                }
> +        ->
> +                []
> +        ;
> +                { pred_info_context(PredInfo, Context) },
> +                write_context_and_pred_id(ModuleInfo, PredInfo, PredId),
> +                prog_out__write_context(Context),
> +                report_warning("  warning: declared `"),
> +                write_purity(DeclPurity),
> +                io__write_string("' but actually "),
> +                write_purity(AcutalPurity),
> +                io__write_string(".\n")
> +        ).
>  
>  :- pred warn_unnecessary_promise_pure(module_info, pred_info, pred_id,
>                                    io__state, io__state).
> @@ -786,28 +801,39 @@
>          io__write_string("' indicator.\n").
>  
>  
> -:- pred warn_unnecessary_body_impurity_decl(module_info, pred_info, pred_id,
> -        prog_context, purity, purity, io__state, io__state).
> -:- mode warn_unnecessary_body_impurity_decl(in, in, in, in, in, in, di, uo)
> +:- pred warn_unnecessary_body_impurity_decl(module_info, pred_info, pred_info, 
> +        pred_id, prog_context, purity, purity, io__state, io__state).
> +:- mode warn_unnecessary_body_impurity_decl(in, in, in, in, in, in, in, di, uo)
>          is det.
>  
> -warn_unnecessary_body_impurity_decl(ModuleInfo, _, PredId, Context,
> -                ActualPurity, DeclaredPurity) -->
> -        prog_out__write_context(Context),
> -        io__write_string("In call to "),
> -        hlds_out__write_pred_id(ModuleInfo, PredId),
> -        io__write_string(":\n"),
> -        prog_out__write_context(Context),
> -        io__write_string("  warning: unnecessary `"),
> -        write_purity(DeclaredPurity),
> -        io__write_string("' indicator.\n"),
> -        prog_out__write_context(Context),
> -        ( { ActualPurity = pure } ->
> -                io__write_string("  No purity indicator is necessary.\n")
> +warn_unnecessary_body_impurity_decl(ModuleInfo, CallerPredInfo, _PredInfo,
> +                PredId, Context, ActualPurity, DeclaredPurity) -->
> +        (
> +                        % We don't warn about exaggerated impurity decls in
> +                        % instance methods --- it just means that the predicate
> +                        % provided as an implementation was more pure than
> +                        % necessary.
> +                { pred_info_get_markers(CallerPredInfo, Markers) },
> +                { check_marker(Markers, class_instance_method) }
> +        ->
> +                []
>          ;
> -                io__write_string("  A purity indicator of `"),
> -                write_purity(ActualPurity),
> -                io__write_string("' is sufficient.\n")
> +                prog_out__write_context(Context),
> +                io__write_string("In call to "),
> +                hlds_out__write_pred_id(ModuleInfo, PredId),
> +                io__write_string(":\n"),
> +                prog_out__write_context(Context),
> +                io__write_string("  warning: unnecessary `"),
> +                write_purity(DeclaredPurity),
> +                io__write_string("' indicator.\n"),
> +                prog_out__write_context(Context),
> +                ( { ActualPurity = pure } ->
> +                        io__write_string("  No purity indicator is necessary.\n")
> +                ;
> +                        io__write_string("  A purity indicator of `"),
> +                        write_purity(ActualPurity),
> +                        io__write_string("' is sufficient.\n")
> +                )
>          ).

These tests are actually better performed near the other purity tests (e.g. is
it compiler-generated, are we inside a lambda) rather than in the body
of the error statement.  But in the existing code this isn't very well
done anyway.

However, my functional syntax change factors out the test code into
a separate predicate with an enumeration of possible return values,
so you should commit this version and I'll integrate it with the rest
of the tests.

> New file: impure_methods.m
> ===================================================================
> :- module impure_methods.
> :- interface.
> 
> :- import_module io.
> 
> :- pred main(io__state::di, io__state::uo) is det.
> 
> :- typeclass c(T) where [
> 	impure pred m1(T::in) is det,
> 	impure pred m2(T::in, int::out) is det
> ].
> 
> :- type foo ---> foo.
> 
> 	% impure implementations of impure methods
> :- instance c(foo) where [
> 	pred(m1/1) is foo_m1,
> 	pred(m2/2) is foo_m2
> ].
> 
> :- type goo ---> goo.
> 
> 	% pure implementations of impure methods
> :- instance c(goo) where [
> 	pred(m1/1) is goo_m1,
> 	pred(m2/2) is goo_m2
> ].
> 
> :- impure pred foo_m1(foo::in) is det.
> :- impure pred foo_m2(foo::in, int::out) is det.
> 
> :- pred goo_m1(goo::in) is det.
> :- pred goo_m2(goo::in, int::out) is det.
> 
> :- implementation.
> 
> :- pragma promise_pure(main/2). 
> 
> main -->
> 	{ impure m1(foo) },
> 	{ impure m1(foo) },
> 	{ impure m1(foo) },
> 	{ impure m1(foo) },
> 	{ impure m2(foo, X) },
> 	io__write_int(X),
> 	io__nl,
> 
> 	{ impure m1(goo) },
> 	{ impure m1(goo) },
> 	{ impure m1(goo) },
> 	{ impure m1(goo) },
> 	{ impure m2(goo, Y) },
> 	io__write_int(Y),
> 	io__nl.
> 
> :- pragma c_header_code("int foo_counter = 0;").
> 
> :- pragma c_code(foo_m1(_F::in), "foo_counter++;").
> :- pragma c_code(foo_m2(_F::in, Val::out), "Val = foo_counter;").
> 
> goo_m1(_).
> goo_m2(_, 42).
> 
> 
> New file: impure_methods.exp
> ===================================================================
> 4
> 42
> -----------------------------------------------------------------------------

A test case containing errors is very useful too.

-- 
The quantum sort: 
	while (!sorted) { do_nothing(); }
Tyson Dowd   <tyson at tyse.net>   http://tyse.net/
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list