D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 7483 - Can't recursively call function with auto return
Summary: Can't recursively call function with auto return
Status: RESOLVED WORKSFORME
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords: diagnostic, spec
Depends on:
Blocks:
 
Reported: 2012-02-11 10:59 UTC by Andrej Mitrovic
Modified: 2016-08-27 22:34 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Andrej Mitrovic 2012-02-11 10:59:16 UTC
module test;

auto test(int x)
{
    return test(1);
}

void main()
{
}

test.d(5): Error: forward reference to test

I was using tuple() returns and ran into this. Luckily I can work around it by explicitly setting the return type, e.g. "Tuple!(bool, string, string) foo()".
Comment 1 Martin Nowak 2012-02-11 12:14:25 UTC
Your example function is an infinite recursion. Both for determining the return type as well as hypothetically at runtime.
Comment 2 Andrej Mitrovic 2012-02-12 02:48:48 UTC
(In reply to comment #1)
> Your example function is an infinite recursion. Both for determining the return
> type as well as hypothetically at runtime.

I've rushed too quickly and posted a silly example.

My use-case was code like this:

auto foo(bool check)
{
    if (check)
    {
        check = false;
        return foo(check);
    }
    else
    {
        return 1;
    }
}

I don't know whether this would be too difficult for the compiler to figure out on its own. But the basic idea is: if there's at least one known type for a return expression then the function's return type becomes that type and there's no longer a forward reference error. If there are any other return expressions they all must have the same type (just like usual functions).

E.g. this would be legal:
auto foo(int state)
{
    if (state == 1)
    {
        state++;
        return foo(state);
    }
    else
    if (state == 2)
    {
        return tuple(0, 0);
    }
    else
    {
        return tuple(0, 0);
    }
}

The return type is std.typecons.Tuple!(int,int).Tuple for the last two return expressions, the first return is not taken into account since it's a recursive call, and all other return expression types match.

This one would be illegal since all the return types don't match:

auto foo(int state)
{
    if (state == 1)
    {
        state++;
        return foo(state);
    }
    else
    if (state == 2)
    {
        return tuple(0, 0);
    }
    else
    {
        return tuple(0, 0, 0);
    }
}

The OP sample would still be invalid since you can't figure out the return type at all in that case.
Comment 3 Stewart Gordon 2012-02-12 10:58:10 UTC
http://www.d-programming-language.org/function.html
"If there are multiple ReturnStatements, the types of them must match exactly. If there are no ReturnStatements, the return type is inferred to be void."

But it doesn't comment on whether this is meant to work.  But since it isn't a forward reference, the error message doesn't make sense in any case.
Comment 4 Martin Nowak 2012-02-12 11:09:38 UTC
Yeah, it should be possible to infer recursive return types.
Comment 5 Andrej Mitrovic 2016-08-27 22:34:34 UTC
The diagnostic is better these days and mentions the inferred return type.