Thread overview
[Issue 22159] "==" causeses error for array of classes in safe method
Jul 30, 2021
RazvanN
Jul 30, 2021
RazvanN
Jul 30, 2021
RazvanN
Aug 04, 2021
RazvanN
Mar 15, 2023
Simon Naarmann
Mar 15, 2023
Dlang Bot
Mar 15, 2023
Adam D. Ruppe
July 30, 2021
https://issues.dlang.org/show_bug.cgi?id=22159

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |safe
                 CC|                            |razvan.nitu1305@gmail.com

--
July 30, 2021
https://issues.dlang.org/show_bug.cgi?id=22159

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |regression

--- Comment #1 from RazvanN <razvan.nitu1305@gmail.com> ---
Looks like this is a regression from 2.078.1 . Apparently, the object.__equals!(C, C).__equals function was not @safe. However, since 2.094.1 this error has changed to: Error: incompatible types for array comparison: `C[]` and `C[3]`. I suspect that the fix will require 2 parts: 1 change dmd to not wrongfully error about incompatible types; 1 change to druntime to make the comparison safe.

--
July 30, 2021
https://issues.dlang.org/show_bug.cgi?id=22159

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|dmd                         |druntime

--- Comment #2 from RazvanN <razvan.nitu1305@gmail.com> ---
It turns out this is a druntime bug.

--
August 04, 2021
https://issues.dlang.org/show_bug.cgi?id=22159

--- Comment #3 from RazvanN <razvan.nitu1305@gmail.com> ---
It's not a compiler bug. Here is where the error is emitted [1]. You can see
that the druntime call is constructed and then semantic is tried.
If there are any errors, the compiler simply assumes that the types are not
compatible. This was introduced by kinke in [2] so that the user
will not get errors pointing to druntime code. If in [2] we use
`expressionSemantic` instead of `trySemantic` we would get an error stating
that `core.object.opEquals` [3] is not @safe and cannot be @safe because it
calls `Object.opEquals`. In fact, just comparing 2 classes with no user-defined
opEquals - `assert (c == c)` - will issue an error in @safe code: "`@safe`
function `D main` cannot call `@system` function `object.opEquals`".

Therefore, the underlying issue is that `object.opEquals` is unsafe and cannot
be made @safe because then any class is constrained
to have a @safe opEquals. (I wonder if we can get around this by changing the
attribute inheritance rule - point 6 in [4])

[1] https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d#L11416
[2]
https://github.com/dlang/dmd/pull/11212/files#diff-f0a120d764c7fab59bd3210b19fe685d2f106e4a1b9a33266804ae99dd3bbd4eR11135
[3] https://github.com/dlang/druntime/blob/master/src/object.d#L240
[4] https://dlang.org/spec/function.html#function-inheritance

--
March 15, 2023
https://issues.dlang.org/show_bug.cgi?id=22159

Simon Naarmann <eiderdaus@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |eiderdaus@gmail.com

--- Comment #4 from Simon Naarmann <eiderdaus@gmail.com> ---
I just ran into this in 2.102.1. In my case, the error message was even more eyebrow-raising:

    incompatible types for array comparison: `X[]` and `X[]`

This already helped me guess that the culprit was the @system Object.opEquals.

But the entire issue, regardless of `C[3]` or `X[]`, has newbie-confusing potential. They follow best practices with @safe, compare arrays by the book, and run into the error that they can't compare an array even with itself.

--
March 15, 2023
https://issues.dlang.org/show_bug.cgi?id=22159

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull

--- Comment #5 from Dlang Bot <dlang-bot@dlang.rocks> ---
@RazvanN7 created dlang/dmd pull request #14988 "Fix Issue 22159 - == causes error for array of classes in safe method" fixing this issue:

- Fix Issue 22159 - == causeses error for array of classes in safe method

https://github.com/dlang/dmd/pull/14988

--
March 15, 2023
https://issues.dlang.org/show_bug.cgi?id=22159

Adam D. Ruppe <destructionator@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |destructionator@gmail.com

--- Comment #6 from Adam D. Ruppe <destructionator@gmail.com> ---
Consider the following:

---
class C { int a; this(int) @safe {} }
class D : C {
        this(int a) @safe { super(a); }
        override bool opEquals(Object rhs) const {
                // obviously not safe
                *(cast(int*) 0x5afe) = 0xdead5afe;
                return true;
        }
}

@safe void main()
{
    C c = new D(1);
    C[] a = [c, c, c];
    assert(a == [c, c, c]);
}
---


The compiler error message should tell you to make a `@safe` override for opEquals in your child class, though doing this still issues an error


---
class C {
        int a; this(int) @safe {}

        override bool opEquals(Object rhs) @safe {
                return this is rhs;
        }
}

@safe void main()
{
    C c = new C(1);
    C[] a = [c, c, c];
    assert(a == [c, c, c]);
}
---

So it should really allow this latter thing and the error message should tell you to write it, while still prohibiting the earlier example.

--