https://issues.dlang.org/show_bug.cgi?id=19125
Steven Schveighoffer <schvei...@yahoo.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |schvei...@yahoo.com --- Comment #1 from Steven Schveighoffer <schvei...@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 ). --