dmd icon indicating copy to clipboard operation
dmd copied to clipboard

Bug in template mixin

Open andrey-zherikov opened this issue 6 months ago • 3 comments

From https://forum.dlang.org/post/[email protected]:

import std;
mixin template f(int function(int) F){}
mixin template f(void function(int) F){unittest{"void".writeln;}}

//mixin f!((_){}); //FAILS


mixin template g(void function(int) F){unittest{"void".writeln;}}
mixin template g(int function(int) F){}

mixin g!((_){});  //works

Expected behavior: both cases work

andrey-zherikov avatar Jun 14 '25 11:06 andrey-zherikov

expected behavior is that both case should fail as this is what we can observe once we extract the lambda to an AliasDecl

mixin template g(void function(int) F) {}
mixin template g(int function(int) F){}

alias garg = (_){};
static assert(__traits(isTemplate, garg));
mixin g!garg;

mixin template f(int function(int) F) {}
mixin template f(void function(int) F) {}

alias farg = (_){};
static assert(__traits(isTemplate, farg));
mixin f!farg;

where both TemplateMixin fail with the same errors.

So it seems that there's some code in the compiler that allows to instantiate the arg but that is not made consistently.

ghost avatar Jun 15 '25 13:06 ghost

expected behavior is that both case should fail as this is what we can observe once we extract the lambda to an AliasDecl

mixin template g(void function(int) F) {} mixin template g(int function(int) F){}

alias garg = (_){}; static assert(__traits(isTemplate, garg)); mixin g!garg;

mixin template f(int function(int) F) {} mixin template f(void function(int) F) {}

alias farg = (_){}; static assert(__traits(isTemplate, farg)); mixin f!farg; where both TemplateMixin fail with the same errors.

So it seems that there's some code in the compiler that allows to instantiate the arg but that is not made consistently.

This is different thing because if I remove override, your code still doesn't compile:

mixin template g(void function(int) F) {}
//mixin template g(int function(int) F){}

alias garg = (_){};
static assert(__traits(isTemplate, garg));
mixin g!garg;
// Error: mixin `onlineapp.g!(__lambda_L6_C1)` does not match template declaration `g(void function(int) F)`
// mixin g!garg;
// ^

The original case fails when mixin is at top level. If mixin is placed inside a function - everything works:

mixin template f(int function(int) F){}
mixin template f(void function(int) F){}

mixin template g(void function(int) F){}
mixin template g(int function(int) F){}

//mixin f!((_){}); //fails here
mixin g!((_){}); //works

void main()
{
mixin f!((_){}); //works if placed inside a function
mixin g!((_){}); //works
}

andrey-zherikov avatar Jun 15 '25 14:06 andrey-zherikov

Note how that never works if you start using aliases, whether local or global:

mixin template f(int function(int) F){}
mixin template f(void function(int) F){}

mixin template g(void function(int) F){}
mixin template g(int function(int) F){}

alias global_garg = (_){};
mixin g!global_garg; //error

void main()
{
    alias local_farg = (_){};
    mixin f!local_farg; //error

    alias local_garg = (_){};
    mixin g!local_garg; //error
} 

ghost avatar Jun 16 '25 00:06 ghost