digitalmars.D.bugs - [Issue 22633] New: Associative array require and update don't work
- d-bugmail puremagic.com (111/111) Dec 28 2021 https://issues.dlang.org/show_bug.cgi?id=22633
https://issues.dlang.org/show_bug.cgi?id=22633 Issue ID: 22633 Summary: Associative array require and update don't work if the value type can't be reassigned or copied. Product: D Version: D2 Hardware: x86_64 OS: Linux Status: NEW Severity: normal Priority: P1 Component: druntime Assignee: nobody puremagic.com Reporter: thomas.bockman gmail.com The program below should work, but instead fails to compile with various errors of the form: Error: cannot modify struct instance `*p` of type `S` because it contains `const` or `immutable` members /////////////////////////////////////////////////// module app; import std.stdio : writeln; struct S { const(int) a; } void main() safe { S[string] aa; aa.require("x", S(1)); writeln(aa["x"]); aa.update("y", () => S(2), (ref const(S)) { }); writeln(aa["y"]); } /////////////////////////////////////////////////// The cause of the error is that object.require and object.update both use assignment for initialization, even though it is known at compile time that the target is new and has not yet been constructed. The fix is to use core.lifetime.moveEmplace for initialization, instead: /////////////////////////////////////////////////// ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init) { bool found; // if key is safe-ly copyable, `require` can infer safe static if (isSafeCopyable!K) { auto p = () trusted { return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found); } (); } else { auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found); } if (found) return *p; else { import core.internal.traits : hasElaborateMove; static if(hasElaborateMove!V) () system { } (); (V value) trusted { import core.lifetime : moveEmplace; moveEmplace(value, *p); } (value()); return *p; // this might not return a ref to the left-hand side. } } // ... void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update) if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void))) { bool found; // if key is safe-ly copyable, `update` may infer safe static if (isSafeCopyable!K) { auto p = () trusted { return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found); } (); } else { auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found); } if (!found) { import core.internal.traits : hasElaborateMove; static if(hasElaborateMove!V) () system { } (); (V value) trusted { import core.lifetime : moveEmplace; moveEmplace(value, *p); } (create()); } else { static if (is(typeof(update(*p)) == void)) update(*p); else *p = update(*p); } } /////////////////////////////////////////////////// Forum thread: https://forum.dlang.org/post/cmvdguqsiqebppwdvlly forum.dlang.org --
Dec 28 2021