Search code examples
templatescompiler-errorsddmd

DMD refuses to instantiate template: not a template declaration


I have a templated class in D that takes another template as a parameter, and it begins thus:

class RuleVars(alias RuleType, RuleRange, SubstitutionRange)
if (__traits(isTemplate, RuleType)) {

     import std.range.primitives;
     import std.traits;

     import Capsicum.PatternMatching.Engine;

     private {
        static if (isAssociativeArray!RuleRange) {
            alias RuleType = ElementType!(typeof(ruleRange.values));
         } else {
            alias RuleType = ElementType!RuleRange;
         }

        static if (isAssociativeArray!SubstitutionRange) {
            alias SubstitutionType = ElementType!(typeof(ruleRange.values));
        } else {
            alias RuleType = ElementType!RuleRange;
        }

        alias MatchingPolicy = RuleType!(Element, RuleElement);
...

The important thing to note is that if RuleType was not a template, the class would fail to instantiate. As a necessity, I have a function which creates an instance of this class:

RuleVars!(RuleType, RuleRange, SubstitutionRange) CreateRuleVars(alias  RuleType, RuleRange, SubstitutionRange)(RuleRange leftHandSide, SubstitutionRange rightHandSide) {
    return new RuleVars!(RuleType, RuleRange, SubstitutionRange)(leftHandSide, rightHandSide);
}

However, when I attempt to instatiate the class like this:

CreateRuleVars!UnboundRules([0 : 'a', 2 : 'b', 4 : 'a', 6 : 'b'],
            [1 :'a', 3 : 'a', 4 : 'b', 6 : 'b'])

I get the following error:

source\Capsicum\PatternMatching\RuleSet.d(25,26): Error: template instance RuleType!(Element, RuleElement) RuleType is not a template declaration, it is a alias
source\Capsicum\PatternMatching\RuleSet.d(73,1): Error: template instance Capsicum.PatternMatching.RuleSet.RuleVars!(UnboundRules, char[int], char[int]) error instantiating
source\Capsicum\PatternMatching\RuleSet.d(127,31):        instantiated from here: CreateRuleVars!(UnboundRules, char[int], char[int])

It's complaining about this specific line:

    alias MatchingPolicy = RuleType!(Element, RuleElement);

The specific template passed here is proven to work when used and instantiated by themselves, so it should not be a problem. It is also obviously a template, otherwise the template parameter matching would have failed. The official D article shows that templates can be passed as template parameters like this:

class Foo(T, alias C)
{
    C!(T) x;
}

As far as I can see, I was doing it correctly. Any ideas?


Solution

  • The problem are these lines:

    alias RuleType = ElementType!(typeof(ruleRange.values));
    

    You redefine a local symbol RuleType which hides the parameter, so subsequent lines are referring to that local alias instead of to the parameter you wanted to use.

    Now, interestingly, this might be a diagnostics bug in the compiler. If you did the analogous thing with regular params:

        void main(string[] args) {
                int args;
        }
    

    The compiler will flag it:

    Error: variable args is shadowing variable aa.sub.main.args
    

    Since that's almost certainly a mistake; you surely intended to use two separate names so you can still reference the argument (otherwise you can ONLY reference the local variable!). But it seems the compiler doesn't perform such a test on template parameters.