Allow ResultOrError to downcast from backend to frontend types

More concretely this makes Result<T*, E*> able to be move-constructed
from Result<ChildClassOfT*, E*> for free.

BUG=dawn:19

Change-Id: Iea2b8997079ac3bfcf270d6b73a79cf5cac2c06f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11860
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2019-10-08 07:36:03 +00:00 committed by Commit Bot service account
parent 5f53d5302f
commit bd481fc199
2 changed files with 40 additions and 4 deletions

View File

@ -20,6 +20,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <type_traits>
#include <utility> #include <utility>
// Result<T, E> is the following sum type (Haskell notation): // Result<T, E> is the following sum type (Haskell notation):
@ -117,8 +118,11 @@ class DAWN_NO_DISCARD Result<T*, E*> {
Result(T* success); Result(T* success);
Result(E* error); Result(E* error);
Result(Result<T*, E*>&& other); // Support returning a Result<T*, E*> from a Result<TChild*, E*>
Result<T*, E*>& operator=(Result<T*, E>&& other); template <typename TChild>
Result(Result<TChild*, E*>&& other);
template <typename TChild>
Result<T*, E*>& operator=(Result<TChild*, E>&& other);
~Result(); ~Result();
@ -129,6 +133,9 @@ class DAWN_NO_DISCARD Result<T*, E*> {
E* AcquireError(); E* AcquireError();
private: private:
template <typename T2, typename E2>
friend class Result;
intptr_t mPayload = detail::kEmptyPayload; intptr_t mPayload = detail::kEmptyPayload;
}; };
@ -265,13 +272,17 @@ Result<T*, E*>::Result(E* error) : mPayload(detail::MakePayload(error, detail::E
} }
template <typename T, typename E> template <typename T, typename E>
Result<T*, E*>::Result(Result<T*, E*>&& other) : mPayload(other.mPayload) { template <typename TChild>
Result<T*, E*>::Result(Result<TChild*, E*>&& other) : mPayload(other.mPayload) {
other.mPayload = detail::kEmptyPayload; other.mPayload = detail::kEmptyPayload;
static_assert(std::is_same<T, TChild>::value || std::is_base_of<T, TChild>::value, "");
} }
template <typename T, typename E> template <typename T, typename E>
Result<T*, E*>& Result<T*, E*>::operator=(Result<T*, E>&& other) { template <typename TChild>
Result<T*, E*>& Result<T*, E*>::operator=(Result<TChild*, E>&& other) {
ASSERT(mPayload == detail::kEmptyPayload); ASSERT(mPayload == detail::kEmptyPayload);
static_assert(std::is_same<T, TChild>::value || std::is_base_of<T, TChild>::value, "");
mPayload = other.mPayload; mPayload = other.mPayload;
other.mPayload = detail::kEmptyPayload; other.mPayload = detail::kEmptyPayload;
return *this; return *this;

View File

@ -139,6 +139,31 @@ TEST(ResultBothPointer, ReturningSuccess) {
TestSuccess(&result, &dummySuccess); TestSuccess(&result, &dummySuccess);
} }
// Tests converting from a Result<TChild*, E*>
TEST(ResultBothPointer, ConversionFromChildClass) {
struct T {
int a;
};
struct TChild : T {};
TChild child;
T* childAsT = &child;
{
Result<T*, int*> result(&child);
TestSuccess(&result, childAsT);
}
{
Result<TChild*, int*> resultChild(&child);
Result<T*, int*> result(std::move(resultChild));
TestSuccess(&result, childAsT);
}
{
Result<TChild*, int*> resultChild(&child);
Result<T*, int*> result = std::move(resultChild);
TestSuccess(&result, childAsT);
}
}
// Result<const T*, E*> // Result<const T*, E*>
// Test constructing an error Result<const T*, E*> // Test constructing an error Result<const T*, E*>