From 1428901018b69bd84357a5c5573dcab9663d2985 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Wed, 8 Oct 2025 20:47:22 +0300 Subject: [PATCH 1/3] Fix scoped static array equality error when compiling with `DIP1000` --- druntime/src/core/internal/array/equality.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/druntime/src/core/internal/array/equality.d b/druntime/src/core/internal/array/equality.d index e0a811bf0722..4ab337e6eae5 100644 --- a/druntime/src/core/internal/array/equality.d +++ b/druntime/src/core/internal/array/equality.d @@ -14,7 +14,7 @@ module core.internal.array.equality; // * dynamic arrays, // * (most) arrays of different (unqualified) element types, and // * arrays of structs with custom opEquals. -bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) @trusted +bool __equals(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 rhs) @trusted { if (lhs.length != rhs.length) return false; @@ -22,9 +22,9 @@ bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) @trusted if (lhs.length == 0) return true; - alias PureType = bool function(scope T1[], scope T2[], size_t) @safe pure nothrow @nogc; + alias PureType = bool function(scope TArr1, scope TArr2, size_t) @safe pure nothrow @nogc; - return (cast(PureType)&isEqual!(T1,T2))(lhs, rhs, lhs.length); + return (cast(PureType)&isEqual!(TArr1,TArr2))(lhs[], rhs[], lhs.length); } /****************************** @@ -32,7 +32,7 @@ bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) @trusted * Outlined to enable __equals() to be inlined, as dmd cannot inline loops. */ private -bool isEqual(T1, T2)(scope T1[] lhs, scope T2[] rhs, size_t length) +bool isEqual(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 rhs, size_t length) { // Returns a reference to an array element, eliding bounds check and // casting void to ubyte. From 9b623303c2202e6bfb2c130c23c0b03488763329 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Wed, 8 Oct 2025 20:49:04 +0300 Subject: [PATCH 2/3] Add scoped static array equality test --- compiler/test/compilable/fix21945.d | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 compiler/test/compilable/fix21945.d diff --git a/compiler/test/compilable/fix21945.d b/compiler/test/compilable/fix21945.d new file mode 100644 index 000000000000..cbd6dcb21002 --- /dev/null +++ b/compiler/test/compilable/fix21945.d @@ -0,0 +1,6 @@ +// REQUIRED_ARGS: -preview=dip1000 + +void assertEq(scope int[][3] x) @safe +{ + bool b = x == x; +} From 01f9fdbf665d7451ad4da8f096191c42735db535 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Thu, 9 Oct 2025 22:04:27 +0300 Subject: [PATCH 3/3] Add `__equals` overrides for static arrays to avoid copies --- druntime/src/core/internal/array/equality.d | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/druntime/src/core/internal/array/equality.d b/druntime/src/core/internal/array/equality.d index 4ab337e6eae5..7a7dc5ceb26b 100644 --- a/druntime/src/core/internal/array/equality.d +++ b/druntime/src/core/internal/array/equality.d @@ -14,7 +14,7 @@ module core.internal.array.equality; // * dynamic arrays, // * (most) arrays of different (unqualified) element types, and // * arrays of structs with custom opEquals. -bool __equals(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 rhs) @trusted +bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) @trusted { if (lhs.length != rhs.length) return false; @@ -22,9 +22,24 @@ bool __equals(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 r if (lhs.length == 0) return true; - alias PureType = bool function(scope TArr1, scope TArr2, size_t) @safe pure nothrow @nogc; + alias PureType = bool function(scope T1[], scope T2[], size_t) @safe pure nothrow @nogc; - return (cast(PureType)&isEqual!(TArr1,TArr2))(lhs[], rhs[], lhs.length); + return (cast(PureType)&isEqual!(T1,T2))(lhs, rhs, lhs.length); +} + +pragma(inline, true) +bool __equals(T1, T2, size_t N)(scope ref T1[N] lhs, scope T2[] rhs) @trusted { + return __equals(lhs[], rhs); +} + +pragma(inline, true) +bool __equals(T1, T2, size_t N)(scope T1[] lhs, scope ref T2[N] rhs) @trusted { + return __equals(lhs, rhs[]); +} + +pragma(inline, true) +bool __equals(T1, T2, size_t N, size_t M)(scope ref T1[N] lhs, scope ref T2[M] rhs) @trusted { + return __equals(lhs[], rhs[]); } /****************************** @@ -32,7 +47,7 @@ bool __equals(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 r * Outlined to enable __equals() to be inlined, as dmd cannot inline loops. */ private -bool isEqual(TArr1 : T1[], TArr2 : T2[], T1, T2)(scope TArr1 lhs, scope TArr2 rhs, size_t length) +bool isEqual(T1, T2)(scope T1[] lhs, scope T2[] rhs, size_t length) { // Returns a reference to an array element, eliding bounds check and // casting void to ubyte.