unittest {
struct MyInt {
int _val;
auto opBinary(string op)(int other) {
return mixin("_val"~op~"other");
}
void opOpAssign(string op)(int other) {
_val = mixin("_val"~op~"other");
}
}
struct Foo {
int _i;
MyInt _mi;
auto i() { return _i; }
auto mi() { return _mi; }
auto i(int val) { return _i = val; }
auto mi(int val) { return _mi = MyInt(val); }
}
auto f = Foo(1, MyInt(1));
static assert(!__traits(compiles, f.i += 1)); // f.i is an rvalue
static assert(!__traits(compiles, f.mi += 1)); // f.mi should be an rvalue
}
The final assert fails.f.mi is not an lvalue, and therefore f.mi += 1 should not compile. It deceptively appears to increment `mi` while truly doing nothing. The compiler disallows this for builtin types (e.g. int) but somehow the use of opOpAssign bypasses this check.
Ideally, I'd love to have support for in-place property modification (https://issues.dlang.org/show_bug.cgi?id=8006), but failing that, I think this should be disallowed to avoid confusion.
P.S. not sure whether this belongs in DMD or druntime
Comment #1 by default_357-line — 2021-11-18T11:42:46Z