gemini-code-assist[bot] commented on code in PR #399:
URL: https://github.com/apache/tvm-ffi/pull/399#discussion_r2760396052


##########
include/tvm/ffi/expected.h:
##########
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file tvm/ffi/expected.h
+ * \brief Runtime Expected container type for exception-free error handling.
+ */
+#ifndef TVM_FFI_EXPECTED_H_
+#define TVM_FFI_EXPECTED_H_
+
+#include <tvm/ffi/any.h>
+#include <tvm/ffi/error.h>
+
+#include <type_traits>
+#include <utility>
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Wrapper to explicitly construct an Expected in the error state.
+ * \tparam E The error type, must derive from Error.
+ */
+template <typename E = Error>
+class Unexpected {
+  static_assert(std::is_base_of_v<Error, std::remove_cv_t<E>>,
+                "Unexpected<E> requires E to be Error or a subclass of 
Error.");
+
+ public:
+  /*! \brief Construct from an error value. */
+  explicit Unexpected(E error) : error_(std::move(error)) {}
+
+  /*! \brief Access the stored error. */
+  const E& error() const& noexcept { return error_; }
+  /*! \brief Access the stored error. */
+  E& error() & noexcept { return error_; }
+  /*! \brief Access the stored error (rvalue). */
+  const E&& error() const&& noexcept { return std::move(error_); }
+  /*! \brief Access the stored error (rvalue). */
+  E&& error() && noexcept { return std::move(error_); }
+
+ private:
+  E error_;
+};
+
+#ifndef TVM_FFI_DOXYGEN_MODE
+template <typename E>
+Unexpected(E) -> Unexpected<E>;
+#endif
+
+/*!
+ * \brief Expected<T> provides exception-free error handling for FFI functions.
+ *
+ * Expected<T> is similar to Rust's Result<T, Error> or C++23's std::expected.
+ * It can hold either a success value of type T or an error of type Error.
+ *
+ * \tparam T The success type. Must be Any-compatible and cannot be Error.
+ *
+ * Usage:
+ * \code
+ * Expected<int> divide(int a, int b) {
+ *   if (b == 0) {
+ *     return Error("ValueError", "Division by zero");
+ *   }
+ *   return a / b;
+ * }
+ *
+ * Expected<int> result = divide(10, 2);
+ * if (result.is_ok()) {
+ *   int value = result.value();
+ * } else {
+ *   Error err = result.error();
+ * }
+ * \endcode
+ */
+template <typename T>
+class Expected {
+ public:
+  static_assert(!std::is_same_v<T, Error>, "Expected<Error> is not allowed. 
Use Error directly.");
+
+  /*!
+   * \brief Implicit constructor from a success value.
+   * \param value The success value.
+   */
+  // NOLINTNEXTLINE(google-explicit-constructor,runtime/explicit)
+  Expected(T value) : data_(Any(std::move(value))) {}
+
+  /*!
+   * \brief Implicit constructor from an error.
+   * \param error The error value.
+   */
+  // NOLINTNEXTLINE(google-explicit-constructor,runtime/explicit)
+  Expected(Error error) : data_(Any(std::move(error))) {}
+
+  /*! \brief Implicit constructor from an Unexpected wrapper. */
+  template <typename E, typename = std::enable_if_t<std::is_base_of_v<Error, 
std::remove_cv_t<E>>>>
+  // NOLINTNEXTLINE(google-explicit-constructor,runtime/explicit)
+  Expected(Unexpected<E> unexpected) : 
data_(Any(Error(std::move(unexpected).error()))) {}

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   The constructor for `Expected` from `Unexpected<E>` currently wraps the 
error in an `Error()` constructor call. This can lead to object slicing if `E` 
is a custom error type that derives from `tvm::ffi::Error`. When sliced, the 
specific type information of the custom error is lost, and it becomes a base 
`Error` object. This prevents callers from downcasting the error to its 
original derived type to handle specific error conditions.
   
   By removing the `Error()` wrapper, the `Any` container will correctly store 
the derived error type, preserving its full information and allowing for proper 
polymorphic error handling.
   
   ```c
     Expected(Unexpected<E> unexpected) : 
data_(Any(std::move(unexpected).error())) {}
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to