Bug 22633 – Associative array require and update don't work if the value type can't be reassigned or copied.

Status
NEW
Severity
normal
Priority
P3
Component
druntime
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2021-12-28T09:59:18Z
Last change time
2024-12-07T13:41:39Z
Keywords
rejects-valid
Assigned to
No Owner
Creator
thomas.bockman
Moved to GitHub: dmd#17434 →

Comments

Comment #0 by thomas.bockman — 2021-12-28T09:59:18Z
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/[email protected]
Comment #1 by robert.schadek — 2024-12-07T13:41:39Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17434 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB