[m-rev.] for review: allow pragmas to accept pred() and func() wrappers around symname/arity

Julien Fischer jfischer at opturion.com
Wed May 5 21:02:17 AEST 2021


Hi Zoltan,

On Wed, 5 May 2021, Zoltan Somogyi wrote:

> This implements what we discussed last week on m-dev.
> For review by anyone. I would particularly like a quick
> response to the change to prog_data.m, since any proposals
> for better names for the notions described there would require
> updating the rest of this diff.

They're fine; I can't think of anything obviously better.

> I intend to add new test cases to invalid to test errors in the
> newly allowed pragma forms, but will do this while this diff
> is being reviewed.
>
> I intend to document and announce the new functionality
> only after we have used it ourselves without hitch for a
> week or two.
>
> After that, we can discuss whether to change how we treat
> ambiguous pragmas, i.e. pragmas in which a symname/arity pair
> can refer to either a predicate or a function. Currently, we
> apply the pragma to both, which I think is unsafe, but we could
> change it to generate an error in that case. I think Peter agrees,
> since I am paraphrasing his suggestion, but maybe I am wrong.

...

> Allow pred pragmas to specify pred_or_func.
> 
> Pragmas that apply to a pred_info have traditionally specified that
> pred_info by a symname/arity pair. However, this can be ambiguous
> if there is both a predicate and a function with that symname/arity pair.
> This diff therefore allows pragmas that previously took "symname/arity"
> to also take "pred(symname/arity)" and "func(symname/arity").
> If e.g. there is both a pred foo/2 and a func foo/2 accessible from
> the current module, the old form applied to both, while the new forms
> apply to just one.
> 
> Later, we could change the behavior of the old form to insist on a
> unique match, but before we do, we should have a mechanism that allows
> programmers to resolve the ambiguity. (They could rename either the
> pred or the func, but it is less intrusive for the compiler not to
> insist on that.) This is that mechanism.
> 
> In the process of implementing this change, I had to update lots of code
> that dealt with arities, since one main difference between predicates
> and functions is that for the latter, the user visible arity and
> the internal compiler arity are different, in that the former does not
> count the return value, and the latter does. The existing "arity" type
> is an equivalence to int, and thus does indicate which notion is meant.
> I therefore added two notag types, user_arity and pred_form_arity,
> for the two notions above respectively, and made a start on using them,
> though for now, only in the code sections affected by the main change above.
> 
> compiler/prog_item.m:
>     Change the types that represent the specifications of predicates
>     (in the sense of pred_infos) and functions to allow the representation
>     of not just "symname/arity," but also "pred(symname/arity)" and
>     "func(symname/arity"). There is one exception: for the oisu (order
>     independent state update) pragma, require the presence of either
>     a pred() vs func() wrapper. This is not a breaking change, since oisu
>     pragmas are neither publicly documented or really implemented.

require_tail_recursion is not publicly documented either.

>     Pragmas that allow the representation of argument modes implicitly
>     specify pred vs func by taking the mode list either as
>     (m1, m2, ... mn) or as (m1, m2, ...) = mn. Encode this invariant
>     in the representation type. Make this type also include an arity
>     only in the absence of a mode list, to make unrepresentable
>     any inconsistent state in which the stated arity and the length
>     of the mode list disagree.
>
>     Give the new types used for these updated representations names
>     that state whether they specify a pred_info or a proc_info
>     (or in one case that we should later fix, that they can specify either).
>
>     Put the pred or func indication before the symname and arity
>     both in these new types, and in some old types. Do this both because
>     the pred or func indication comes before the name in Mercury declarations,
>     and to help the compiler find all the places where code using the old
>     forms had to be revisited and checked for any needed updates.
>
>     Provide utility operations on the new types involved in the
>     updated representations.

...

> diff --git a/compiler/prog_data.m b/compiler/prog_data.m
> index 7ac83717a..d80234be9 100644
> --- a/compiler/prog_data.m
> +++ b/compiler/prog_data.m
> @@ -1945,7 +1945,44 @@ valid_trace_grade_name(GradeName) :-
>  :- type pf_sym_name_arity
>      --->    pf_sym_name_arity(pred_or_func, sym_name, arity).
> 
> +    % This type is part of a family of related types, the rest of which are
> +    % in prog_item.m. Its name fits in with those types.
> +    %
> +:- type pred_pf_name_arity
> +    --->    pred_pf_name_arity(pred_or_func, sym_name, user_arity).
> +
> +    % XXX ARITY While the concept of arity seems simple, it is not, because
> +    % the compiler has to juggle several different notions of arity.
> +    %
> +    % Consider a function declaration as simple as
> +    %
> +    %   :- func length(list(T)) = int.
> +    %
> +    % This function has three different arities for three different purposes.
> +    %
> +    % - It has one user visible argument, so if arity counts these, then
> +    %   its arity is 1.
> +    %
> +    % - Its initial form in the compiler adds the return value to the argument
> +    %   list, so if arity counts these, then its arity is 2.
> +    %
> +    % - The polymorphism transformation then adds a typeinfo arg for T,
> +    %   so if arity counts these as well, then its arity is 3.
> +    %
> +    % We might call these different kinds arities something like
> +    % "user arity", "pred form arity" and "extended arity" respectively.
> +    % (Better names welcome.)
> +    %
> +    % We should replace this single equivalence type with three separate
> +    % notag types, one for each of these kinds of arities, and all uses
> +    % of the plain just "arity" type should be replaced by these.
> +    % The user_arity and pred_form_arity types below are a start on this.
> +    %
>  :- type arity == int.
> +:- type user_arity
> +    --->    user_arity(int).
> +:- type pred_form_arity
> +    --->    pred_form_arity(int).

It might also be worth replacing int with uint at some point, since arities
cannot be negative.  (Actually, given the documented limitations on the
arities of predicates, uint16 might be a better choice since that may also
result in opportunities for argument packing in some of the compiler data
structures.)

The diff looks ok.

Julien.


More information about the reviews mailing list