[m-rev.] for post-commit review: better diagnostic for missing higher order insts
Peter Wang
novalazy at gmail.com
Thu Jul 20 17:08:47 AEST 2023
On Wed, 19 Jul 2023 20:28:12 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
>
> On 2023-07-19 04:56 +02:00 CEST, "Peter Wang" <novalazy at gmail.com> wrote:
> >> +no_ho_inst.m:044: In clause for `run_loop(in, in, out, di, uo)':
> >> +no_ho_inst.m:044: in argument 1 (i.e. the predicate term) of higher-order
> >> +no_ho_inst.m:044: predicate call:
> >> +no_ho_inst.m:044: mode error: context requires a predicate of arity 4, and
> >> +no_ho_inst.m:044: the type of AppHandler does match that expectation, but to
> >> +no_ho_inst.m:044: check the correctness of the call, the compiler also needs
> >> +no_ho_inst.m:044: to know the modes of the arguments and the determinism of
> >> +no_ho_inst.m:044: the predicate that AppHandler represents, and AppHandler's
> >> +no_ho_inst.m:044: inst does not contain that information.
> >
> > My attempt:
> >
> > In clause for `run_loop(in, in, out, di, uo)':
> > in argument 1 (i.e. the predicate term) of higher-order
> > predicate call:
> > mode error: the context requires a predicate of arity 4.
> > The type of AppHandler matches that expectation, but the inst of
> > AppHandler at this point is `ground', which lacks the higher-order
> > inst information required to make the call.
>
> I like most aspects of that, except one.
>
> > in which I think the improvements are:
> >
> > - removes an interpretation where the reader might think the mode
> > error is due to a compiler limitation
>
> Actually, it IS due to a compiler limitation. The limitation is that
> even if you include the higher order inst info in the type, the
> compiler won't pay attention to it. But I agree that there is no point
> in emphasizing that fact.
As far as I'm aware, the language only allows higher order inst info in
the argument type of a du type definition. I don't think it's completely
obvious to allow higher order inst info elsewhere, so I wouldn't call
it a compiler limitation but a question of language design. Anyway.
>
> > - keeps the part which says that it's (probably) not a type error.
> > That seems like a good idea.
> >
> > - prints out the problematic inst
>
> Agree with both.
>
> > - tells the user that "higher-order inst information" is required to
> > make a higher-order call, using those exact words so they can be
> > searched for in the reference manual
>
> I agree that giving that search terms is useful. But your text also *requires*
> a search term for novices, because it does not say itself what "higher order
> inst information" *is*: the modes of the args, and the determinism.
> I would strongly prefer to provide that info in this error message.
Ok.
>
> > - removes the line about the "usual fix" which is vague
> > (although that might have been intended as a heading to the next part)
>
> It was intended to be such a heading. It seems a blank line
> would have helped here.
>
> >> +no_ho_inst.m:044: The usual fix for this error is to add this information.
> >> +no_ho_inst.m:044: Given a higher order type such as
> >> +no_ho_inst.m:044: :- type callback_t == (pred(world, world, io, io).
> >> +no_ho_inst.m:044: you would define a corresponding inst, such as
> >> +no_ho_inst.m:044: :- inst callback_i == (pred(in, out, di, uo) is det).
> >> +no_ho_inst.m:044: This inst specifies the modes of the arguments and the
> >> +no_ho_inst.m:044: determinism of a predicate. You can then tell the compiler
> >> +no_ho_inst.m:044: that a value of type callback_t has inst callback_i by
> >> +no_ho_inst.m:044: specifying either the mode `in(callback_i)' (when taking a
> >> +no_ho_inst.m:044: value of type callback_t as input) or the mode
> >> +no_ho_inst.m:044: `out(callback_i)' (when returning a value of type
> >> +no_ho_inst.m:044: callback_t as output).
> >> +For more information, recompile with `-E'.
> >
> > I personally prefer not to see things like this in error messages.
> > Once you learn what's going on, it's tiring to be told the same long
> > piece of (non-specific) advice over and over.
>
> Yes, we *could* make everything from the "usual fix" reference onward
> a verbose-only part of the message. The reason I did not do so is that
> the very people who need the info in that part are the people who may not
> pay attention to the "recompile with -E" at the bottom of the output,
> partly because it may not follow the error message to which it applies
> *immediately*.
>
Fair enough.
> > A common situation where the error would arise is when someone tries to
> > take a higher-order term out of a container and tries to call it, then
> > the advice would not apply.
>
> The four possible sources of a higher order term are:
>
> - an input arg in the clause head
> - an output arg in a call in the clause body
> - a lambda expression (possibly implicit) in a construct unification
> the clause body
> - a deconstruct unification in the clause body.
>
> The third is not a problem, since in that case, the higher order inst
> is present by construction. The "usual fix" message covers the first two.
> The fourth is, in my experience, much rarer than the other three,
> precisely because there *is* no good way to preserve the higher order
> inst info of whatever closure was put into the data structure. There is
> a way, consisting of always specifying an inst for the whole data structure
> that includes the higher order inst of the higher order value, but
> I wouldn't call it "good". In that case, the good solution would be
> to include the higher order value's inst in its type, but this needs the compiler
> to be able to use that info.
I consider the solution of keeping the higher order value within a term
of a bespoke du type "pretty good". We don't have to mention it in the
error message though.
Peter
More information about the reviews
mailing list