June 20, 2023
https://issues.dlang.org/show_bug.cgi?id=24003

          Issue ID: 24003
           Summary: return/scope inference does not end up in type to some
                    degree
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: qs.il.paperinik@gmail.com

When function attributes are inferred, they end up in the type:
```d
auto f() {}
static assert(is(typeof(&f) == void function() @safe nothrow @nogc pure));
```

However, when parameters’ `scope` and `return` attributes are inferred, they are not displayed in error messages or `pragma(msg)`.

They might not be displayed, but could still (silently) be part of the type; but in a Schrödinger fashion, they are and they are not:

```d
auto f(int[] xs) @safe
{
    static int ctr;
    ctr++; // force impure
    return xs;
}

void tplTypeInfer(F)(ref F fp1, ref F fp2)
{
    int[3] xs;
    fp1(xs);
    fp2(xs);
}

//void nonTpl(ref int[] function(int[] xs) nothrow @nogc @safe fp) @safe
//{
//    //int[3] xs;
//    //fp(xs);
//}

void main() @safe
{
    int[3] xs;
    f(xs);   // good: `xs` binds to parameter inferred `return scope`.

    static assert(typeof(&f).stringof ==
                      "int[] function(int[] xs) nothrow @nogc @safe");
    alias F1 = int[] function(int[] xs) nothrow @nogc @safe;
    alias F2 = typeof(&f);
    static assert(is(F1 == F2)); // PASSES!
    F1 fp1 = &f; // This and …
    F2 fp2 = &f; // … this should behave the same, right?
    fp1(xs); // error: reference to local variable `xs` assigned to non-scope
parameter `xs`
    fp2(xs); // good (apparently, the parameter is scope here)

    tplTypeInfer(fp1, fp2);    // good/error depending on if nonTpl is
commented-in
    tplTypeInfer(fp2, fp1);    // good/error (same)
    tplTypeInfer!F1(fp1, fp2); // good/error (same)
    tplTypeInfer!F1(fp2, fp1); // good/error (same)
    tplTypeInfer!F2(fp1, fp2); // good/error (same)
    tplTypeInfer!F2(fp2, fp1); // good/error (same)
}
```
It seems that if you *use* the function pointer, it remembers somehow that the
parameter is inferred scope.
Also, there’s some Schrödinger action going on with template type inference.

--