[m-rev.] for review: warn about unneeded initial and final state vars

Peter Wang novalazy at gmail.com
Tue May 20 13:01:11 AEST 2025


On Fri, 16 May 2025 03:46:37 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> For review by anyone. I will update the user guide once
> the new documentation in options.m is approved.
> 
> Much of the diff consists of me acting on the new warnings,
> so you can see how useful they are. I have not yet acted on
> *all* such warnings, because this diff is large enough already;
> that will come later.
> 
> Zoltan

> Add options to warn about unused state vars.
> 
> The new --warn-unneeded-initial-statevar option asks the compiler to warn about
> code such as
> 
>     pred_a(!.X, ...) :-
>         ... code that uses !.X, but does not update it ...
> 
> In this case, the preferred fix is to just replace all occurrences
> of !.X with X.
> 
> The new --warn-unneeded-final-statevar option asks the compiler to warn about
> code such as
> 
>     pred_a(!X, ...) :-
>         ... code that maybe uses !.X, but does not update it ...
> 
> In this case, the preferred fix also involves replacing all occurrences
> of !.X with X, but it also involves either deleting the argument
> containing !:X (the best option), or, if there is some reason why
> the predicate's signature must stay unchanged, to replace !:X with X as well.
> And if the clause body does not actually refer to either !.X or !:X, then
> *both* arguments represented by !X should be deleted.
> 

I've had a chance to try this change on the Prince codebase now.
A common pattern is a predicate that takes the I/O state as unique input
in order to read the "global state", but the I/O state needs to be
threaded through its caller (for whatever reason).

For example:

    :- pred p(int::in, io::di, io::uo) is det.

    p(_, !IO) :-
	read_global_state(!.IO).

    :- pred read_global_state(io::ui) is det.

    read_global_state(IO) :- ...

The unneeded final statevars warning suggests that !:IO could be deleted
in p/3, but it cannot be written like so:

    p(_, IO, IO) :-
	read_global_state(IO).

as the modechecker will complain that IO has instantiatedness `ground'.

To avoid the warning, it is necessary to write out the unification
previously implied by state variable notation:

    p(_, IO0, IO) :-
	read_global_state(IO0),
	IO = IO0.

I guess, ideally, the compiler would recognise that a final statevar is
not "unneeded" if the statevar occurs as a unique-input argument in a
call (or some generalisation of that).

Peter
-------------- next part --------------
:- module unique_input.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

%-----------------------------------------------------------------------------%

:- implementation.

:- import_module list.

main(!IO) :-
    foldl(p, [], !IO),
    foldl(q, [], !IO).

:- pred p(int::in, io::di, io::uo) is det.

p(_, !IO) :-
    read_global_state(!.IO),
    read_global_state(!.IO).

:- pred q(int::in, io::di, io::uo) is det.

q(_, IO0, IO) :-
    read_global_state(IO0),
    read_global_state(IO0),
    IO = IO0.

:- pred read_global_state(io::ui) is det.

read_global_state(_).


More information about the reviews mailing list