Bug 19749 – Inout causes wrong type inference

Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-03-18T10:38:32Z
Last change time
2019-07-18T10:24:29Z
Assigned to
No Owner
Creator
Ali Ak

Comments

Comment #0 by ali.akhtarzada — 2019-03-18T10:38:32Z
Using inout with type constructors causes the wrong type to be inferred. 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")]; Probably related to 19126.
Comment #1 by ali.akhtarzada — 2019-03-18T10:39:16Z
Forgot this: it causes "Error: incompatible types for (make("hello")) : (S("hello")): immutable(S!(char[])) and S!string"
Comment #2 by dfj1esp02 — 2019-03-18T12:36:41Z
Well, that's how inout works. Simple inference does what you want: struct S(T) { T value; } auto make(T)(ref T value) { return S!T(value); } auto f(T)(ref T s) { return make(s.value); } void f() { class C {} C c; auto s1 = S!C(c); const s2 = make!C(c); auto s3 = f(s2); }
Comment #3 by ali.akhtarzada — 2019-03-18T13:51:05Z
What do you mean that's how inout works? It works by changing your types? Why is it secretly changing my types? And try adding a function that takes an S!T instead of a catch all and simple inference doesn't work anymore. It's not scalable to have opaque types on every function: auto f(T)(auto ref S!T s) { return make(s); } Also, if inout changes the type that you expect then even more insanity ensues: struct S(T) { static if (is(T == char[])) { // implement 1 } else { // implement 2 } } auto a = make("hi"); // implementation 1 auto b = S!string("hi") // implementation 2
Comment #4 by dfj1esp02 — 2019-03-18T16:16:51Z
inout is a wildcard for const qualifiers, so instead of mutable, const and immutable you see inout. Inference provides you the qualifiers unchanged. To restrict types you can use static assert or template constraints.
Comment #5 by ali.akhtarzada — 2019-03-21T08:52:05Z
No it doesn't. It changes them by moving them around. struct S(T) { pragma(msg, T); } auto make(T)(inout T s) { return inout S!T(); } pragma(msg, typeof(make("hi"))); // prints // char[] // immutable(S!(char[]))
Comment #6 by dfj1esp02 — 2019-03-21T15:48:30Z
If you want to preserve types, use inference: struct S(T) { pragma(msg, T); } auto make(T)(T s) { return S!T(); } pragma(msg, typeof(make("hi"))); prints --- string S!string ---
Comment #7 by ali.akhtarzada — 2019-03-21T23:58:46Z
That can't be used by other inout functions. The whole point of inout is to be able to handle const/immutable/mutable without having to write 3 variations of a function.
Comment #8 by dfj1esp02 — 2019-03-22T09:12:39Z
But then you can't preserve qualifiers, because the results must be identical. If you want to preserve qualifiers, you need 3 different templates.
Comment #9 by dfj1esp02 — 2019-03-22T09:15:14Z
S!(char[]) S!(const char[]) S!string Can't be the same template, they are different types with distinct code generated for each of them. So they can't be handled by the same code.
Comment #10 by ali.akhtarzada — 2019-03-22T10:21:37Z
(In reply to anonymous4 from comment #9) > S!(char[]) > S!(const char[]) > S!string > Can't be the same template, they are different types with distinct code > generated for each of them. So they can't be handled by the same code. Exactly. And inout is generating the wrong one! Anyway, it seems I've filed this before -> https://issues.dlang.org/show_bug.cgi?id=19125
Comment #11 by ali.akhtarzada — 2019-07-18T10:24:29Z
*** This issue has been marked as a duplicate of issue 19125 ***