GabrielDosReis/ipr

Partial and Explicit Template Specialization representation

Opened this issue · 0 comments

This is a request to revisit how we represent partial and explicit template specializations in IPR.
Specifically how secondary templates and entities that resulted from explicit specializations indicate what is their primary template and an argument list and where specializations are stored (in the scope and subject to name+type lookup or in the specializations list).

  1. Prior to commit Simplify ipr::Decl a bit, every declaration would carry an information whether it was produced by a specialization of a template and if so what were the arguments:
virtual const Template& generating_map() const = 0;
virtual const Sequence<Substitution>& substitutions() const = 0;

this was used to by some users of IPR to figure out whether a given declaration is an explicit specialization of a template or non-templated declaration (by checking if the substitution.size() > 0) or to distinguish between the primary or secondary template using the same technique for ipr::Template declaration.

We no longer have this mechanism.

  1. There is an args field in struct Template : impl::Decl<ipr::Template>
    impl::Expr_list args;
    .

IPR user-guide gives an example of how to create primary and secondary templates and in that example it populates the args array with template args referring to the parameters in the mapping that is the body of that particular template i.e. a different mechanism than ipr::Substitution that are used to indicate template arguments in ipr::Decl where they would always refer to the parameters of the primary template.

However the existing args field of ipr::impl::Template is not exposed via ipr::Template and therefore not available to ipr consumers.

  1. There is no way to indicate what is the primary template when defining a secondary template. There is an FIXME in the implementation of make_secondary_template

ipr/src/impl.cxx

Lines 1295 to 1313 in 9e60541

impl::Template*
Scope::make_secondary_template(const ipr::Name& n, const ipr::Forall& t)
{
impl::Overload* ovl = overloads.insert(n, node_compare());
overload_entry* master = ovl->lookup(t);
if (master == 0) {
impl::Template* decl = secondary_maps.declare(ovl, t);
// FXIME: record this a secondary map and set its primary.
add_member(decl);
return decl;
}
else {
impl::Template* decl = secondary_maps.redeclare(master);
// FIXME: set primary info.
add_member(decl);
return decl;
}
}

which makes me think that the intention was to capture a reference to a primary_template which leads to

  1. Do arguments to make_secondary template make sense?

Should they be, for example, make_secondary(ipr::Template& primary, Expr_list& args, const ipr::Forall& t) for example and not what we currently have make_secondary_template(const ipr::Name& n, const ipr::Forall& t).

  1. Should we be adding secondary templates to the overload set?

In the code fragment mentioned earlier, we can see that we are adding the secondary template to an overload set for the name n and adding the declaration to that scope, whereas I believe the intention was to link all specializations to the specs field of the master declaration of the primary template struct master_decl_data<ipr::Template>:

ipr/include/ipr/impl

Lines 552 to 553 in 9e60541

// Sequence of specializations
decl_sequence specs;