[m-rev.] for tryout: type_spec_constrained_preds

Julien Fischer jfischer at opturion.com
Thu Feb 1 01:06:33 AEDT 2024


On Thu, 1 Feb 2024, Zoltan Somogyi wrote:

> On 2024-01-31 20:08 +11:00 AEDT, "Julien Fischer" <jfischer at opturion.com> wrote:
>> Compiling with the pragma above
>> results in the following error:
>>
>>     Making Mercury/asm_fast.gc/x86_64-pc-linux-gnu/Mercury/opts/csv.typed_reader.opt
>>     In `:- pragma type_spec' declaration for function `csv.make_error_message'/1:
>>       error: variables `V_1, V_2' do not occur in the `:- func' declaration.
>>
>> Changing apply_to_superclasses to do_not_apply_to_superclasses, gives
>> the following error:
>>
>>     In `:- pragma type_spec' declaration for function
>>       `csv.record_parser.get_client_quotation_mark_in_unquoted_field'/1:
>>        error: variable `V_3' does not occur in the `:- func' declaration.
>
> Thanks for the tryout; I will look into these.

I will post something regarding the JSON library tomorrow or Friday;
it's the more interesting of the two.

> Would you mind if I copied some parts of your csv and/or json libraries
> to the test case for this diff?

Feel free to, they're released under a BSD-style license anyway.

> I am aware that the existing test case only
> scratches the surface, and needs to be significantly expanded.
>
>> That said, I'm not convinced that most of them are actually called,
>> since there are number of class method calls remaining in the HLDS
>> dumps.
>
> That may or may not be a problem.

Yes, I need to look into what's going on there further.

> The higher order specialization pass,
> which should replace non-type-specialized calls with type-specialized calls,
> does not itself delete any predicates that have become dead as a result,
> and until dead pred/proc elimination is called, those will remain in HLDS dumps.
> Also, exported unspecialized versions cannot be deleted.
>
>> (In the case of read_from_file/6, the call to the get/4
>> method is still present and that would presuambly call the unspecialised
>> versions.)
>
> The pred id on the call should tell you which version is being called.
> ( don't think the code that redirects the call to the specialized version
> changes the *name* of the callee in the plain_call goal_expr, since the
> name is not used by any of the later passes, but it has to change the pred_id.
>
> To make HLDS dumps easier to read, I will look into making this code
> update the name field as well, as a separate change.

...

>>> I would prefer approach four, though I could also live with approach one.
>>> I view approach two as violating the law of least astonishment. As for
>>> approach three, it could work, but any documentation of its semantics
>>> would be signicantly more complicated than a documentation of the
>>> semantics of approach four, and its use in practice would require
>>> more attention as well. With approach four, the compiler can help
>>> diagnose e.g. unintentional spelling mismatches between the first arg
>>> and the later args; with approach three, it cannot.
>>
>> I am struggling to see the use case for approaches (3) and (4).
>> Is it that they also allow you to specialise unconstrained type
>> variables?
>
> Yes. The problem I am trying to address is this: if a predicate
> has three type vars in its signature, say A, B, and C, then having three
> type_spec pragmas, each specializing exactly one of these type vars,
> will generate three specialized versions of the predicate, but there
> will be no version that specializes any two or all three type vars.
> In this sense, type_spec pragmas don't *compose*.
>
> The motivation for the "ignore if not applicable" rule is this:
>
> - Say the constraints in a type_spec_constrained_preds pragma's
>  first arg may include type var A, but not B or C.
>
> - Some predicate we want to specialize includes all of A, B and C
>  in its type signature, with A occurring in a position that matches
>  the type_spec_constrained_preds pragma's constraints.
>  In this case, we want B and C to be specialized alongside A.
>
> - Some other predicates are like that one, but they have only
>  one of B and C. We want those to be specialized on either
>  both A and B, or both A and C, depending on which they have,
>  but we don't want an error message about the other one
>  not being there.
>
> Another possible solution, which would go with approach one
> above but which would be more complicated to implement,
> would be to redefine type_spec pragmas to MAKE them compose.
> We have never needed this before, because *if you know which pred
> you want to type-specialize*, then you know what type vars occur in it,
> and it is simpler to list them all in a single type_spec pragma than
> to write e.g. one type_spec pragma for each type variable.
> The issue arises now because type_spec_constrained_preds
> can apply to many different predicates, which may have different
> sets of type vars in their signatures.
>
> Composition is also complicated by the question of what we should do
> when two type_spec pragmas specify that the same type var should be
> specialized when it has two distinct but unifiable shapes? For example,
> if one says "specialize if A = map(int, _)", and another says "specialize
> if A = map(_, string)". Do you generate just those two versions, or
> do you also specialize separately for A = map(int, string)?

Ok, I see where you're going with that. I'll need to have a think about
it.

...

>>> - The second args of two type_spec pragmas differ if and only if they differ
>>>  after
>>>
>>>  - sorting the type var substitutions of which they consist
>>>    on the name of the LHS variable, and
>>>
>>>  - replacing all type variables that occur in the types on the RHSs
>>>    of those type var substitutions with distinct anonymous type vars.
>>>    (In fact, we should consider whether we should allow ANY non-anonymous
>>>    type variables to occur in the RHS types.)
>>
>> Looking at what the standard library and compiler do, the RHS are nearly
>> always ground types.
>
> Which is why I though this proposal was worth looking into.
>
>> (The one exception is var(_) in the standard
>> library.)  In practice, we do use non-anonymous type variables in the RHS types.)

Sorry, I meant to type we *do not* use non-anonymous type variables there.

Julien.


More information about the reviews mailing list