Thread overview
[Issue 19125] IFTI and inout removes head mutability qualifier on by-val parameters
Jul 18, 2019
Ali Ak
Jul 18, 2019
Ali Ak
July 30, 2018
https://issues.dlang.org/show_bug.cgi?id=19125

Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com

--- Comment #1 from Steven Schveighoffer <schveiguy@yahoo.com> ---
The issue here is that IFTI applies inout to the head when it shouldn't

If you have a function like this:

struct S(T)
{
   T t;
}

inout(S!T) makeS(T)(inout(T) t)
{
   return inout S!T(t);
}

One expects the type parameter of S to match the type parameter passed in. inout is just saying "I'm not going to change anything"

However, in the case of types that have tail-mutability modifier capability (pointers, arrays), IFTI is pulling the mutability OUT from the tail and applying it to the entire parameter:

auto s1 = makeS("hello");
assert(is(typeof(s1) == immutable(S!(char[])));
auto s2 = makeS("hello".ptr);
assert(is(typeof(s2) == immutable(S!(char *));

But tail-modified values are distinctly more capable in terms of mutability than fully modified values. So IFTI I believe should NOT perform this adjustment, and just match T as string (and therefore the type of t should be inout(string)).

If one wishes to actually match inout to the modifier of the tail, one can do so with a specialization:

auto makeS(T)(inout(T)[] t)
{
   return inout S!(T[])(t);
}

Note that the use of auto ref in the original code is affecting what is
inferred, because of the double-indirection rule. This makes it doubly
confusing (see the cases for wrap0("foo") and wrap0(s0), which one might expect
to be identical ).

--
July 17, 2019
https://issues.dlang.org/show_bug.cgi?id=19125

Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Hardware|x86                         |All
                 OS|Mac OS X                    |All
           Severity|enhancement                 |regression

--- Comment #2 from Steven Schveighoffer <schveiguy@yahoo.com> ---
I have another simpler case which is absolutely unacceptable:

Nullable!string s;

string x = s.get(""); // error

This is because Nullable.get is taking the above input as an inout(char[])!

It should be inout(string).

Checking all versions, looks like this worked in 2.065 and prior. Well, the concept worked anyway, since I don't think that form of get was added to Nullable until later.

An equivalent test:

struct S
{
    string boo;
    auto get(U)(inout(U) u) inout
    {
        return boo.length == 0 ? u : boo;
    }
}
void main()
{
    S s;
    string x = s.get("");
}

This fails from 2.066 on. Changing to regression.

--
July 18, 2019
https://issues.dlang.org/show_bug.cgi?id=19125

--- Comment #3 from Ali Ak <ali.akhtarzada@gmail.com> ---
*** Issue 19749 has been marked as a duplicate of this issue. ***

--
July 18, 2019
https://issues.dlang.org/show_bug.cgi?id=19125

--- Comment #4 from Ali Ak <ali.akhtarzada@gmail.com> ---
Yes. This is super annoying.

It also messes up type inference where you need the types to be inferred properly:

struct S(T) {
    T value = T.init;
}

auto ref make(T)(inout auto ref T value) {
    // T == char[] when infact it's string
    return inout(S!T)(value);
}

auto ref f(T)(inout auto ref S!T s) {
    return make(s.value);
}

auto a = [make("hello"), S!string("hello")];

(plucked from duplicate issue)

--
December 13
https://issues.dlang.org/show_bug.cgi?id=19125

--- Comment #5 from dlangBugzillaToGithub <robert.schadek@posteo.de> ---
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/19469

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB

--