[Issue 4028] New: delegates with differing default arguments lead to same template instantiation

d-bugmail at puremagic.com d-bugmail at puremagic.com
Mon Mar 29 16:02:32 PDT 2010


http://d.puremagic.com/issues/show_bug.cgi?id=4028

           Summary: delegates with differing default arguments lead to
                    same template instantiation
           Product: D
           Version: 1.057
          Platform: Other
        OS/Version: All
            Status: NEW
          Keywords: wrong-code
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: nobody at puremagic.com
        ReportedBy: nfxjfg at gmail.com


--- Comment #0 from nfxjfg at gmail.com 2010-03-29 16:02:30 PDT ---
Look at these two delegates:

void delegate(int x = 123) D_A;
void delegate(int x) D_B;

They have the same type, but they behave differently. E.g. you can call D_A(),
but not D_B().

They lead to the same template instantiation:

void foo(T)(T del) {
}

foo(D_A) and foo(D_B) will be the same template instantiations.

This is a bug, because foo(D_B) will think that del has a default parameter,
which is obviously not the case. dmd should instantiate two different templates
for it. Maybe make delegates with different default args have different types.

Here's a test case, which demonstrates how this can lead to trouble in real
world programs. The code is ripped out from a scripting wrapper, which tries to
support default arguments. (The reason why doMethod is templated on a delegate
and not on the class/method is to drastically reduce the number of template
instantiations.)

import std.stdio;

template ParameterTupleOf( Fn )
{
    static if( is( Fn Params == function ) )
        alias Params ParameterTupleOf;
    else static if( is( Fn Params == delegate ) )
        alias ParameterTupleOf!(Params) ParameterTupleOf;
    else static if( is( Fn Params == Params* ) )
        alias ParameterTupleOf!(Params) ParameterTupleOf;
    else
        static assert( false, "Argument has no parameters." );
}

int requiredArgCount(alias Fn)() {
    alias ParameterTupleOf!(typeof(Fn)) Params;
    Params p;
    static if (is(typeof(Fn())))
        return 0;
    foreach (int idx, x; p) {
        static if (is(typeof(Fn(p[0..idx+1]))))
            return idx+1;
    }
    assert(false);
}

class Foo {
    void moo1() {}
    void moo2(short x) {}
    void moo3(int x = 123) {}
    void moo4(int x) {}
}

void doMethod(T)(T del, char[] name, char[] expect) {
    writefln("method %s, required arg count: got %s, expected %s", name,
requiredArgCount!(del)(), expect);
}

void method(Class, char[] name)(char[] expect) {
    auto fn = mixin("&Class." ~ name);
    doMethod(fn, name, expect);
}

void main() {
    //just to prove that the other code works
    method!(Foo, "moo1")("0");
    method!(Foo, "moo2")("1");
    //here starts the problem
    //moo3 instantiates doMethod!(void delegate(int x = 123))
    method!(Foo, "moo3")("0");
    //moo4 _should_ instantiate doMethod!(void delegate(int x))
    //but it really insantiates the same as moo3:
    //  doMethod!(void delegate(int x = 123))
    //this is obviously wrong!
    //doMethod() will think that moo4 has a default argument, when it
    //really hasn't (you can see that in the runtime output of this program)
    method!(Foo, "moo4")("1");
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list