Thread overview
[Issue 16528] @safe inference does not work for mutually recursive functions
Sep 23, 2016
John Colvin
Sep 23, 2016
Lodovico Giaretta
Sep 24, 2016
Lodovico Giaretta
Sep 25, 2016
Walter Bright
Mar 11, 2018
Walter Bright
Jun 21, 2020
John Hall
Oct 03, 2022
Dennis
Oct 14, 2022
Dennis
September 23, 2016
https://issues.dlang.org/show_bug.cgi?id=16528

John Colvin <john.loughran.colvin@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |john.loughran.colvin@gmail.
                   |                            |com

--- Comment #1 from John Colvin <john.loughran.colvin@gmail.com> ---
Ok so this is absolutely hideous and there is definitely something weird going on with the compiler in this region, but I *think* the following works as expected. There is probably an adaption of this that can be made simpler, but I don't have time to find it right now.

template fun1Wrap(T)
{
    enum foo = q{
    void impl(T value) %s
    {
        if (value) fun2%s(value - 1);
    }
    };
    import std.format : format;
    static if(__traits(compiles, { mixin(format(foo, `@safe`, `Safe`)); }))
        mixin(format(foo, `@safe`, `Safe`));
    else
        mixin(foo);
}

void fun1Safe(T)(T t) @safe
{
    fun1Wrap!T.impl(t);
}

void fun1(T)(T t)
{
    static if (__traits(compiles, fun1Safe(t) ))
        fun1Safe(t);
    else
        fun1Wrap!T.impl(t);
}

template fun2Wrap(T)
{
    enum foo = q{%s void impl(T value)
{
    if (value) fun1%s(value - 1);
}
};
    import std.format : format;
    static if(__traits(compiles, { mixin(format(foo, `@safe`, `Safe`)); }))
        mixin(format(foo, `@safe`, `Safe`));
    else
        mixin(foo);
}

void fun2Safe(T)(T t) @safe
{
    fun2Wrap!T.impl(t);
}

void fun2(T)(T t)
{
    static if (__traits(compiles, fun1Safe(t) ))
        fun2Safe(t);
    else
        fun2Wrap!T.impl(t);
}

@safe void main()
{
    fun1(4);
}

--
September 23, 2016
https://issues.dlang.org/show_bug.cgi?id=16528

Lodovico Giaretta <lodovico@giaretart.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |lodovico@giaretart.net

--- Comment #2 from Lodovico Giaretta <lodovico@giaretart.net> ---
Disclaimer: I don't know anything about DMD internals.

It looks like currently, in case of mutual recursion, the compiler takes the pessimistic approach and does not infer any attribute. This is too conservative. It is possible to devise an inference algorithm that optimistically assumes functions to have all attributes, and progressively removes them as needed.

Cycles due to mutual recursion can be arbitrarily complex, with many functions, but the informations gathered during instantiation are enough to identify the entire set of those functions. Then the compiler infers the safety of each of those function separately, without taking into account call instructions to other functions of the same recursion set. If this process identifies a function that does not have a specific attribute, than no function in the set has that attribute. Otherwise, all functions in the set have it.

I didn't reason that much about the above algorithm, but I'm under the impression that it works in all cases and is also quite easy to understand and implement.

--
September 24, 2016
https://issues.dlang.org/show_bug.cgi?id=16528

Lodovico Giaretta <lodovico@giaretart.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Hardware|x86_64                      |All

--
September 25, 2016
https://issues.dlang.org/show_bug.cgi?id=16528

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |safe
                 CC|                            |bugzilla@digitalmars.com

--
March 11, 2018
https://issues.dlang.org/show_bug.cgi?id=16528

--- Comment #3 from Walter Bright <bugzilla@digitalmars.com> ---
A minimal test case:

void fun1()()
{
    fun2();
}

void fun2()()
{
    fun1();
}

@safe void test()
{
    fun1();
}

--
January 01, 2019
https://issues.dlang.org/show_bug.cgi?id=16528

hsteoh@quickfur.ath.cx changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hsteoh@quickfur.ath.cx

--
June 21, 2020
https://issues.dlang.org/show_bug.cgi?id=16528

John Hall <john.michael.hall@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |john.michael.hall@gmail.com

--- Comment #4 from John Hall <john.michael.hall@gmail.com> ---
The title of this could be adjusted so that it makes clear that this applies to all attribute inference. If you change Walter's example from @safe to nothrow, @nogc, or pure, then you get the same errors.

--
October 03, 2022
https://issues.dlang.org/show_bug.cgi?id=16528

Dennis <dkorpel@live.nl> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kinke@gmx.net

--- Comment #5 from Dennis <dkorpel@live.nl> ---
*** Issue 23128 has been marked as a duplicate of this issue. ***

--
October 14, 2022
https://issues.dlang.org/show_bug.cgi?id=16528

Dennis <dkorpel@live.nl> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |dkorpel@live.nl
         Resolution|---                         |DUPLICATE

--- Comment #6 from Dennis <dkorpel@live.nl> ---


*** This issue has been marked as a duplicate of issue 7205 ***

--