Skip to content

Commit

Permalink
Merge pull request #6370 from SimonN/issue18615
Browse files Browse the repository at this point in the history
Fix Issue 18615 - Rebindable!A calls A.opEquals
merged-on-behalf-of: Jack Stouffer <jack@jackstouffer.com>
  • Loading branch information
dlang-bot committed Apr 5, 2018
2 parents ca72c99 + 65b1f1a commit 9de2823
Showing 1 changed file with 67 additions and 0 deletions.
67 changes: 67 additions & 0 deletions std/typecons.d
Expand Up @@ -2128,6 +2128,18 @@ if (is(T == class) || is(T == interface) || isAssociativeArray!T)
}
}

bool opEquals()(auto ref const(typeof(this)) rhs) const
{
// Must forward explicitly because 'stripped' is part of a union.
// The necessary 'toHash' is forwarded to the class via alias this.
return stripped == rhs.stripped;
}

bool opEquals(const(U) rhs) const
{
return stripped == rhs;
}

alias get this;
}

Expand Down Expand Up @@ -2206,6 +2218,61 @@ if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArr
static assert(!__traits(compiles, &r.get()));
}

@safe unittest
{
class CustomToHash
{
override size_t toHash() const nothrow @trusted { return 42; }
}
Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
~ " by forwarding to A.toHash().");
}

@system unittest // issue 18615: Rebindable!A should use A.opEquals
{
class CustomOpEq
{
int x;
override bool opEquals(Object rhsObj)
{
if (auto rhs = cast(const(CustomOpEq)) rhsObj)
return this.x == rhs.x;
else
return false;
}
}
CustomOpEq a = new CustomOpEq();
CustomOpEq b = new CustomOpEq();
assert(a !is b);
assert(a == b, "a.x == b.x should be true (0 == 0).");

Rebindable!(const(CustomOpEq)) ra = a;
Rebindable!(const(CustomOpEq)) rb = b;
assert(ra !is rb);
assert(ra == rb, "Rebindable should use CustomOpEq's opEquals, not 'is'.");
assert(ra == b, "Rebindable!(someQualifier(A)) should be comparable"
~ " against const(A) via A.opEquals.");
assert(a == rb, "Rebindable!(someQualifier(A)) should be comparable"
~ " against const(A) via A.opEquals.");

b.x = 1;
assert(a != b);
assert(ra != b, "Rebindable!(someQualifier(A)) should be comparable"
~ " against const(A) via A.opEquals.");
assert(a != rb, "Rebindable!(someQualifier(A)) should be comparable"
~ " against const(A) via A.opEquals.");

Rebindable!(const(Object)) o1 = new Object();
Rebindable!(const(Object)) o2 = new Object();
assert(o1 !is o2);
assert(o1 == o1, "When the class doesn't provide its own opEquals,"
~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
assert(o1 != o2, "When the class doesn't provide its own opEquals,"
~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
assert(o1 != new Object(), "Rebindable!(const(Object)) should be"
~ " comparable against Object itself and use Object.opEquals.");
}
/**
Convenience function for creating a `Rebindable` using automatic type
inference.
Expand Down

0 comments on commit 9de2823

Please sign in to comment.