This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new e8a5516f [CORE] Invert object/type_traits dependency layering (#638)
e8a5516f is described below
commit e8a5516fa1e0e02d087d4efd7e6e9ba2244cf28a
Author: Tianqi Chen <[email protected]>
AuthorDate: Fri Jun 19 21:58:39 2026 -0400
[CORE] Invert object/type_traits dependency layering (#638)
## Summary
- invert the header dependency so `object.h` includes `type_traits.h`,
and move shared type metadata/helpers like `StaticTypeKey`,
`TypeIndexToTypeKey`, and `details::type_contains_v` into
`type_traits.h`
- move object and `Optional` trait specializations into their owning
headers, move `DLTensor*` traits into `tensor.h`, and keep the
`uint64_t` overflow-checked specialization near the end of `any.h`
- add a narrow ASF header checker skip for `.agents/skills/**/SKILL.md`
so skill files can keep frontmatter at byte 0
---
.agents/skills/devtools/SKILL.md | 17 -
include/tvm/ffi/any.h | 17 +
include/tvm/ffi/container/container_details.h | 14 -
include/tvm/ffi/container/tensor.h | 44 +++
include/tvm/ffi/object.h | 262 ++++++++++-----
include/tvm/ffi/optional.h | 62 ++++
include/tvm/ffi/type_traits.h | 461 +++++++-------------------
tests/cpp/test_any.cc | 1 +
tests/cpp/test_function.cc | 1 +
tests/lint/check_asf_header.py | 6 +-
10 files changed, 426 insertions(+), 459 deletions(-)
diff --git a/.agents/skills/devtools/SKILL.md b/.agents/skills/devtools/SKILL.md
index b1ef105f..92841f19 100644
--- a/.agents/skills/devtools/SKILL.md
+++ b/.agents/skills/devtools/SKILL.md
@@ -1,20 +1,3 @@
-<!--- 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. -->
-
---
name: devtools
description: Developer reference for Apache TVM-FFI.
diff --git a/include/tvm/ffi/any.h b/include/tvm/ffi/any.h
index 9d7ccee5..5d754f7d 100644
--- a/include/tvm/ffi/any.h
+++ b/include/tvm/ffi/any.h
@@ -823,6 +823,23 @@ struct AnyEqual {
}
}
};
+
+// Placed near the end because this specialization depends on error handling.
+template <>
+struct TypeTraits<uint64_t> : public TypeTraitsIntBase<uint64_t> {
+ TVM_FFI_INLINE static void CopyToAnyView(const uint64_t& src, TVMFFIAny*
result) {
+ if (src > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+ TVM_FFI_THROW(OverflowError)
+ << "Integer value " << src << " is too large to fit in int64_t. "
+ << "Consider explicitly casting to int64_t first if this is
intentional.";
+ }
+ TypeTraitsIntBase<uint64_t>::CopyInt64ToAnyView(static_cast<int64_t>(src),
result);
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(uint64_t src, TVMFFIAny* result) {
+ CopyToAnyView(src, result);
+ }
+};
} // namespace ffi
// Expose to the tvm namespace for usability
diff --git a/include/tvm/ffi/container/container_details.h
b/include/tvm/ffi/container/container_details.h
index 37277a6a..b0c5317e 100644
--- a/include/tvm/ffi/container/container_details.h
+++ b/include/tvm/ffi/container/container_details.h
@@ -178,20 +178,6 @@ inline constexpr bool all_storage_enabled_v =
(storage_enabled_v<T> && ...);
*/
template <typename... T>
inline constexpr bool all_object_ref_v = (std::is_base_of_v<ObjectRef, T> &&
...);
-/**
- * \brief Check if Any storage of Derived can always be directly used as Base.
- *
- * \tparam Base The base type.
- * \tparam Derived The derived type.
- * \return True if Derived's storage can be used as Base's storage, false
otherwise.
- */
-template <typename Base, typename Derived>
-inline constexpr bool type_contains_v =
- std::is_base_of_v<Base, Derived> || std::is_same_v<Base, Derived>;
-// special case for Any
-template <typename Derived>
-inline constexpr bool type_contains_v<Any, Derived> = true;
-
/*!
* \brief Create a string of the container type.
* \tparam V The types of the elements in the container.
diff --git a/include/tvm/ffi/container/tensor.h
b/include/tvm/ffi/container/tensor.h
index d08e23a9..4f6e108b 100644
--- a/include/tvm/ffi/container/tensor.h
+++ b/include/tvm/ffi/container/tensor.h
@@ -884,6 +884,50 @@ inline size_t GetDataSize(const TensorView& tensor) {
return GetDataSize(tensor.numel(), tensor.dtype());
}
+// DLTensor* support lives with Tensor/TensorView because the conversion path
+// is tensor-specific and can reuse the FFI error layer.
+template <>
+struct TypeTraits<DLTensor*> : public TypeTraitsBase {
+ static constexpr bool storage_enabled = false;
+ static constexpr int32_t field_static_type_index =
TypeIndex::kTVMFFIDLTensorPtr;
+
+ TVM_FFI_INLINE static void CopyToAnyView(DLTensor* src, TVMFFIAny* result) {
+ TVM_FFI_ICHECK_NOTNULL(src);
+ result->type_index = TypeIndex::kTVMFFIDLTensorPtr;
+ result->zero_padding = 0;
+ TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
+ result->v_ptr = src;
+ }
+
+ TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+ return src->type_index == TypeIndex::kTVMFFIDLTensorPtr;
+ }
+
+ TVM_FFI_INLINE static DLTensor* CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
+ TVM_FFI_UNSAFE_ASSUME(src->type_index == TypeIndex::kTVMFFIDLTensorPtr);
+ return static_cast<DLTensor*>(src->v_ptr);
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(DLTensor*, TVMFFIAny*) {
+ TVM_FFI_THROW(RuntimeError)
+ << "DLTensor* cannot be held in Any as it does not retain ownership,
use Tensor instead";
+ }
+
+ TVM_FFI_INLINE static std::optional<DLTensor*> TryCastFromAnyView(const
TVMFFIAny* src) {
+ if (src->type_index == TypeIndex::kTVMFFIDLTensorPtr) {
+ return static_cast<DLTensor*>(src->v_ptr);
+ } else if (src->type_index == TypeIndex::kTVMFFITensor) {
+ return TVMFFITensorGetDLTensorPtr(src->v_obj);
+ }
+ return std::nullopt;
+ }
+
+ TVM_FFI_INLINE static std::string TypeStr() { return
StaticTypeKey::kTVMFFIDLTensorPtr; }
+ TVM_FFI_INLINE static std::string TypeSchema() {
+ return R"({"type":")" + std::string(StaticTypeKey::kTVMFFIDLTensorPtr) +
R"("})";
+ }
+};
+
// TensorView type, allow implicit casting from DLTensor*
// NOTE: we deliberately do not support MoveToAny and MoveFromAny since it
does not retain ownership
template <>
diff --git a/include/tvm/ffi/object.h b/include/tvm/ffi/object.h
index 0150c0ab..2048cc5b 100644
--- a/include/tvm/ffi/object.h
+++ b/include/tvm/ffi/object.h
@@ -25,6 +25,7 @@
#include <tvm/ffi/base_details.h>
#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/type_traits.h>
#include <optional>
#include <string>
@@ -34,16 +35,6 @@
namespace tvm {
namespace ffi {
-/*!
- * \brief TypeIndex enum, alias of TVMFFITypeIndex.
- */
-using TypeIndex = TVMFFITypeIndex;
-
-/*!
- * \brief TypeInfo, alias of TVMFFITypeInfo.
- */
-using TypeInfo = TVMFFITypeInfo;
-
/*!
* \brief Helper tag to explicitly request unsafe initialization.
*
@@ -62,78 +53,6 @@ using TypeInfo = TVMFFITypeInfo;
*/
struct UnsafeInit {};
-/*!
- * \brief Known type keys for pre-defined types.
- */
-struct StaticTypeKey {
- /*! \brief The type key for Any */
- static constexpr const char* kTVMFFIAny = "Any";
- /*! \brief The type key for None */
- static constexpr const char* kTVMFFINone = "None";
- /*! \brief The type key for bool */
- static constexpr const char* kTVMFFIBool = "bool";
- /*! \brief The type key for int */
- static constexpr const char* kTVMFFIInt = "int";
- /*! \brief The type key for float */
- static constexpr const char* kTVMFFIFloat = "float";
- /*! \brief The type key for void* */
- static constexpr const char* kTVMFFIOpaquePtr = "void*";
- /*! \brief The type key for DataType */
- static constexpr const char* kTVMFFIDataType = "DataType";
- /*! \brief The type key for Device */
- static constexpr const char* kTVMFFIDevice = "Device";
- /*! \brief The type key for DLTensor* */
- static constexpr const char* kTVMFFIDLTensorPtr = "DLTensor*";
- /*! \brief The type key for const char* */
- static constexpr const char* kTVMFFIRawStr = "const char*";
- /*! \brief The type key for TVMFFIByteArray* */
- static constexpr const char* kTVMFFIByteArrayPtr = "TVMFFIByteArray*";
- /*! \brief The type key for ObjectRValueRef */
- static constexpr const char* kTVMFFIObjectRValueRef = "ObjectRValueRef";
- /*! \brief The type key for SmallStr */
- static constexpr const char* kTVMFFISmallStr = "ffi.SmallStr";
- /*! \brief The type key for SmallBytes */
- static constexpr const char* kTVMFFISmallBytes = "ffi.SmallBytes";
- /*! \brief The type key for Error */
- static constexpr const char* kTVMFFIError = "ffi.Error";
- /*! \brief The type key for Bytes */
- static constexpr const char* kTVMFFIBytes = "ffi.Bytes";
- /*! \brief The type key for String */
- static constexpr const char* kTVMFFIStr = "ffi.String";
- /*! \brief The type key for Shape */
- static constexpr const char* kTVMFFIShape = "ffi.Shape";
- /*! \brief The type key for Tensor */
- static constexpr const char* kTVMFFITensor = "ffi.Tensor";
- /*! \brief The type key for Object */
- static constexpr const char* kTVMFFIObject = "ffi.Object";
- /*! \brief The type key for Function */
- static constexpr const char* kTVMFFIFunction = "ffi.Function";
- /*! \brief The type key for Array */
- static constexpr const char* kTVMFFIArray = "ffi.Array";
- /*! \brief The type key for List */
- static constexpr const char* kTVMFFIList = "ffi.List";
- /*! \brief The type key for Map */
- static constexpr const char* kTVMFFIMap = "ffi.Map";
- /*! \brief The type key for Module */
- static constexpr const char* kTVMFFIModule = "ffi.Module";
- /*! \brief The type key for Dict */
- static constexpr const char* kTVMFFIDict = "ffi.Dict";
- /*! \brief The type key for VisitInterrupt */
- static constexpr const char* kTVMFFIVisitInterrupt = "ffi.VisitInterrupt";
- /*! \brief The type key for OpaquePyObject */
- static constexpr const char* kTVMFFIOpaquePyObject = "ffi.OpaquePyObject";
-};
-
-/*!
- * \brief Get type key from type index
- * \param type_index The input type index
- * \return the type key
- */
-inline std::string TypeIndexToTypeKey(int32_t type_index) {
- const TypeInfo* type_info = TVMFFIGetTypeInfo(type_index);
- return std::string(type_info->type_key.data, type_info->type_key.size);
-}
-
namespace details {
// Helper to perform
// unsafe operations related to object
@@ -1257,7 +1176,186 @@ struct ObjectUnsafe {
return GetHeader(obj_ptr);
}
};
+
} // namespace details
+
+template <typename T>
+struct TypeToRuntimeTypeIndex<T, std::enable_if_t<std::is_base_of_v<ObjectRef,
T>>> {
+ static int32_t v() { return T::ContainerType::RuntimeTypeIndex(); }
+};
+
+template <typename TObjRef>
+struct ObjectRefTypeTraitsBase : public TypeTraitsBase {
+ static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIObject;
+ using ContainerType = typename TObjRef::ContainerType;
+
+ TVM_FFI_INLINE static void CopyToAnyView(const TObjRef& src, TVMFFIAny*
result) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (!src.defined()) {
+ TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
+ return;
+ }
+ }
+ TVMFFIObject* obj_ptr =
details::ObjectUnsafe::TVMFFIObjectPtrFromObjectRef(src);
+ result->type_index = obj_ptr->type_index;
+ result->zero_padding = 0;
+ TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
+ result->v_obj = obj_ptr;
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(TObjRef src, TVMFFIAny* result) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (!src.defined()) {
+ TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
+ return;
+ }
+ }
+ TVMFFIObject* obj_ptr =
details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(src));
+ result->type_index = obj_ptr->type_index;
+ result->zero_padding = 0;
+ TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
+ result->v_obj = obj_ptr;
+ }
+
+ TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (src->type_index == TypeIndex::kTVMFFINone) return true;
+ }
+ return src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
+ details::IsObjectInstance<ContainerType>(src->type_index);
+ }
+
+ TVM_FFI_INLINE static TObjRef CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (src->type_index == TypeIndex::kTVMFFINone) {
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
+ }
+ }
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(
+ details::ObjectUnsafe::ObjectPtrFromUnowned<Object>(src->v_obj));
+ }
+
+ TVM_FFI_INLINE static TObjRef MoveFromAnyAfterCheck(TVMFFIAny* src) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (src->type_index == TypeIndex::kTVMFFINone) {
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
+ }
+ }
+ ObjectPtr<ContainerType> obj_ptr =
+ details::ObjectUnsafe::ObjectPtrFromOwned<ContainerType>(src->v_obj);
+ TypeTraits<std::nullptr_t>::MoveToAny(nullptr, src);
+ return
details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(std::move(obj_ptr));
+ }
+
+ TVM_FFI_INLINE static std::optional<TObjRef> TryCastFromAnyView(const
TVMFFIAny* src) {
+ if constexpr (TObjRef::_type_is_nullable) {
+ if (src->type_index == TypeIndex::kTVMFFINone) {
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
+ }
+ }
+ if (src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
+ details::IsObjectInstance<ContainerType>(src->type_index)) {
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(
+
details::ObjectUnsafe::ObjectPtrFromUnowned<ContainerType>(src->v_obj));
+ }
+ return std::nullopt;
+ }
+
+ TVM_FFI_INLINE static std::string TypeStr() { return
ContainerType::_type_key; }
+ TVM_FFI_INLINE static std::string TypeSchema() {
+ return R"({"type":")" + std::string(ContainerType::_type_key) + R"("})";
+ }
+};
+
+template <typename TObjRef>
+struct TypeTraits<TObjRef, std::enable_if_t<std::is_base_of_v<ObjectRef,
TObjRef> &&
+
use_default_type_traits_v<TObjRef>>>
+ : public ObjectRefTypeTraitsBase<TObjRef> {};
+
+/*!
+ * \brief Helper class to define ObjectRef that can be auto-converted from a
+ * fallback type, the Traits<ObjectRefType> must be derived from it
+ * and define a static methods named ConvertFallbackValue for each
+ * FallbackType
+ *
+ * The conversion will go through the FallbackTypes in the order
+ * specified in the template parameter.
+ * \tparam ObjectRefType The type of the ObjectRef.
+ * \tparam FallbackTypes The type of the fallback value.
+ */
+template <typename ObjectRefType, typename... FallbackTypes>
+struct ObjectRefWithFallbackTraitsBase : public
ObjectRefTypeTraitsBase<ObjectRefType> {
+ /// \cond Doxygen_Suppress
+ TVM_FFI_INLINE static std::optional<ObjectRefType> TryCastFromAnyView(const
TVMFFIAny* src) {
+ if (auto opt_obj =
ObjectRefTypeTraitsBase<ObjectRefType>::TryCastFromAnyView(src)) {
+ return opt_obj;
+ }
+ return TryFallbackTypes<FallbackTypes...>(src);
+ }
+
+ template <typename FallbackType, typename... Rest>
+ TVM_FFI_INLINE static std::optional<ObjectRefType> TryFallbackTypes(const
TVMFFIAny* src) {
+ static_assert(!std::is_same_v<bool, FallbackType>,
+ "Using bool as FallbackType can cause bug because int will
be detected as bool, "
+ "use tvm::ffi::StrictBool instead");
+ if (auto opt_fallback = TypeTraits<FallbackType>::TryCastFromAnyView(src))
{
+ return
TypeTraits<ObjectRefType>::ConvertFallbackValue(*std::move(opt_fallback));
+ }
+ if constexpr (sizeof...(Rest) > 0) {
+ return TryFallbackTypes<Rest...>(src);
+ }
+ return std::nullopt;
+ }
+ /// \endcond
+};
+
+template <typename TObject>
+struct TypeTraits<TObject*, std::enable_if_t<std::is_base_of_v<Object,
TObject>>>
+ : public TypeTraitsBase {
+ TVM_FFI_INLINE static void CopyToAnyView(TObject* src, TVMFFIAny* result) {
+ TVMFFIObject* obj_ptr = details::ObjectUnsafe::GetHeader(src);
+ result->type_index = obj_ptr->type_index;
+ result->zero_padding = 0;
+ TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
+ result->v_obj = obj_ptr;
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(TObject* src, TVMFFIAny* result) {
+ TVMFFIObject* obj_ptr = details::ObjectUnsafe::GetHeader(src);
+ result->type_index = obj_ptr->type_index;
+ result->zero_padding = 0;
+ TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
+ result->v_obj = obj_ptr;
+ details::ObjectUnsafe::IncRefObjectHandle(result->v_obj);
+ }
+
+ TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+ return src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
+ details::IsObjectInstance<TObject>(src->type_index);
+ }
+
+ TVM_FFI_INLINE static TObject* CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
+ if constexpr (!std::is_const_v<TObject>) {
+ static_assert(TObject::_type_mutable, "TObject must be mutable to enable
cast from Any");
+ }
+ return details::ObjectUnsafe::RawObjectPtrFromUnowned<TObject>(src->v_obj);
+ }
+
+ TVM_FFI_INLINE static std::optional<TObject*> TryCastFromAnyView(const
TVMFFIAny* src) {
+ if constexpr (!std::is_const_v<TObject>) {
+ static_assert(TObject::_type_mutable, "TObject must be mutable to enable
cast from Any");
+ }
+ if (CheckAnyStrict(src)) return CopyFromAnyViewAfterCheck(src);
+ return std::nullopt;
+ }
+
+ TVM_FFI_INLINE static std::string TypeStr() { return TObject::_type_key; }
+ TVM_FFI_INLINE static std::string TypeSchema() {
+ return R"({"type":")" + std::string(TObject::_type_key) + R"("})";
+ }
+};
+
} // namespace ffi
} // namespace tvm
+
#endif // TVM_FFI_OBJECT_H_
diff --git a/include/tvm/ffi/optional.h b/include/tvm/ffi/optional.h
index f43a078f..b28f7105 100644
--- a/include/tvm/ffi/optional.h
+++ b/include/tvm/ffi/optional.h
@@ -413,6 +413,68 @@ class Optional<T,
std::enable_if_t<use_ptr_based_optional_v<T>>> : public Object
}
}
};
+
+template <typename T>
+inline constexpr bool use_default_type_traits_v<Optional<T>> = false;
+
+template <typename T>
+struct TypeTraits<Optional<T>> : public TypeTraitsBase {
+ TVM_FFI_INLINE static void CopyToAnyView(const Optional<T>& src, TVMFFIAny*
result) {
+ if (src.has_value()) {
+ TypeTraits<T>::CopyToAnyView(*src, result);
+ } else {
+ TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
+ }
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(Optional<T> src, TVMFFIAny* result) {
+ if (src.has_value()) {
+ TypeTraits<T>::MoveToAny(*std::move(src), result);
+ } else {
+ TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
+ }
+ }
+
+ TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+ if (src->type_index == TypeIndex::kTVMFFINone) return true;
+ return TypeTraits<T>::CheckAnyStrict(src);
+ }
+
+ TVM_FFI_INLINE static Optional<T> CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
+ if (src->type_index == TypeIndex::kTVMFFINone) {
+ return Optional<T>(std::nullopt);
+ }
+ return TypeTraits<T>::CopyFromAnyViewAfterCheck(src);
+ }
+
+ TVM_FFI_INLINE static Optional<T> MoveFromAnyAfterCheck(TVMFFIAny* src) {
+ if (src->type_index == TypeIndex::kTVMFFINone) {
+ return Optional<T>(std::nullopt);
+ }
+ return TypeTraits<T>::MoveFromAnyAfterCheck(src);
+ }
+
+ TVM_FFI_INLINE static std::optional<Optional<T>> TryCastFromAnyView(const
TVMFFIAny* src) {
+ if (src->type_index == TypeIndex::kTVMFFINone) return
Optional<T>(std::nullopt);
+ if (std::optional<T> opt = TypeTraits<T>::TryCastFromAnyView(src)) {
+ return Optional<T>(*std::move(opt));
+ }
+ // Important to be explicit here because nullopt can convert to
+ // std::optional<T>(nullopt), which would incorrectly signal success.
+ return std::optional<Optional<T>>(std::nullopt);
+ }
+
+ TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const TVMFFIAny* src) {
+ return TypeTraits<T>::GetMismatchTypeInfo(src);
+ }
+
+ TVM_FFI_INLINE static std::string TypeStr() {
+ return "Optional<" + TypeTraits<T>::TypeStr() + ">";
+ }
+ TVM_FFI_INLINE static std::string TypeSchema() {
+ return R"({"type":"Optional","args":[)" + details::TypeSchema<T>::v() +
"]}";
+ }
+};
} // namespace ffi
} // namespace tvm
#endif // TVM_FFI_OPTIONAL_H_
diff --git a/include/tvm/ffi/type_traits.h b/include/tvm/ffi/type_traits.h
index deb82474..2810e3fe 100644
--- a/include/tvm/ffi/type_traits.h
+++ b/include/tvm/ffi/type_traits.h
@@ -17,18 +17,17 @@
* under the License.
*/
/*!
- * \file tvm/ffi/object.h
- * \brief A managed object in the TVM FFI.
+ * \file tvm/ffi/type_traits.h
+ * \brief Type trait helpers for FFI values.
*/
#ifndef TVM_FFI_TYPE_TRAITS_H_
#define TVM_FFI_TYPE_TRAITS_H_
#include <tvm/ffi/base_details.h>
#include <tvm/ffi/c_api.h>
-#include <tvm/ffi/error.h>
-#include <tvm/ffi/object.h>
#include <limits>
+#include <optional>
#include <string>
#include <type_traits>
#include <utility>
@@ -38,6 +37,104 @@ namespace ffi {
class Any;
+/*!
+ * \brief TypeIndex enum, alias of TVMFFITypeIndex.
+ */
+using TypeIndex = TVMFFITypeIndex;
+/*!
+ * \brief TypeInfo, alias of TVMFFITypeInfo.
+ */
+using TypeInfo = TVMFFITypeInfo;
+
+/*!
+ * \brief Known type keys for pre-defined types.
+ */
+struct StaticTypeKey {
+ /*! \brief The type key for Any */
+ static constexpr const char* kTVMFFIAny = "Any";
+ /*! \brief The type key for None */
+ static constexpr const char* kTVMFFINone = "None";
+ /*! \brief The type key for bool */
+ static constexpr const char* kTVMFFIBool = "bool";
+ /*! \brief The type key for int */
+ static constexpr const char* kTVMFFIInt = "int";
+ /*! \brief The type key for float */
+ static constexpr const char* kTVMFFIFloat = "float";
+ /*! \brief The type key for void* */
+ static constexpr const char* kTVMFFIOpaquePtr = "void*";
+ /*! \brief The type key for DataType */
+ static constexpr const char* kTVMFFIDataType = "DataType";
+ /*! \brief The type key for Device */
+ static constexpr const char* kTVMFFIDevice = "Device";
+ /*! \brief The type key for DLTensor* */
+ static constexpr const char* kTVMFFIDLTensorPtr = "DLTensor*";
+ /*! \brief The type key for const char* */
+ static constexpr const char* kTVMFFIRawStr = "const char*";
+ /*! \brief The type key for TVMFFIByteArray* */
+ static constexpr const char* kTVMFFIByteArrayPtr = "TVMFFIByteArray*";
+ /*! \brief The type key for ObjectRValueRef */
+ static constexpr const char* kTVMFFIObjectRValueRef = "ObjectRValueRef";
+ /*! \brief The type key for SmallStr */
+ static constexpr const char* kTVMFFISmallStr = "ffi.SmallStr";
+ /*! \brief The type key for SmallBytes */
+ static constexpr const char* kTVMFFISmallBytes = "ffi.SmallBytes";
+ /*! \brief The type key for Error */
+ static constexpr const char* kTVMFFIError = "ffi.Error";
+ /*! \brief The type key for Bytes */
+ static constexpr const char* kTVMFFIBytes = "ffi.Bytes";
+ /*! \brief The type key for String */
+ static constexpr const char* kTVMFFIStr = "ffi.String";
+ /*! \brief The type key for Shape */
+ static constexpr const char* kTVMFFIShape = "ffi.Shape";
+ /*! \brief The type key for Tensor */
+ static constexpr const char* kTVMFFITensor = "ffi.Tensor";
+ /*! \brief The type key for Object */
+ static constexpr const char* kTVMFFIObject = "ffi.Object";
+ /*! \brief The type key for Function */
+ static constexpr const char* kTVMFFIFunction = "ffi.Function";
+ /*! \brief The type key for Array */
+ static constexpr const char* kTVMFFIArray = "ffi.Array";
+ /*! \brief The type key for List */
+ static constexpr const char* kTVMFFIList = "ffi.List";
+ /*! \brief The type key for Map */
+ static constexpr const char* kTVMFFIMap = "ffi.Map";
+ /*! \brief The type key for Module */
+ static constexpr const char* kTVMFFIModule = "ffi.Module";
+ /*! \brief The type key for Dict */
+ static constexpr const char* kTVMFFIDict = "ffi.Dict";
+ /*! \brief The type key for VisitInterrupt */
+ static constexpr const char* kTVMFFIVisitInterrupt = "ffi.VisitInterrupt";
+ /*! \brief The type key for OpaquePyObject */
+ static constexpr const char* kTVMFFIOpaquePyObject = "ffi.OpaquePyObject";
+};
+
+/*!
+ * \brief Get type key from type index
+ * \param type_index The input type index
+ * \return the type key
+ */
+inline std::string TypeIndexToTypeKey(int32_t type_index) {
+ const TypeInfo* type_info = TVMFFIGetTypeInfo(type_index);
+ return std::string(type_info->type_key.data, type_info->type_key.size);
+}
+
+namespace details {
+/*!
+ * \brief Check whether `Derived` can reuse `Base` storage directly.
+ *
+ * \tparam Base The base type.
+ * \tparam Derived The derived type.
+ * \return True if Derived's storage can be used as Base's storage, false
otherwise.
+ */
+template <typename Base, typename Derived>
+inline constexpr bool type_contains_v =
+ std::is_base_of_v<Base, Derived> || std::is_same_v<Base, Derived>;
+
+// Special case for Any, which can store any compatible value directly.
+template <typename Derived>
+inline constexpr bool type_contains_v<Any, Derived> = true;
+} // namespace details
+
/*!
* \brief TypeTraits that specifies the conversion behavior from/to FFI Any.
*
@@ -126,11 +223,6 @@ struct TypeToRuntimeTypeIndex {
static int32_t v() { return TypeToFieldStaticTypeIndex<T>::value; }
};
-template <typename T>
-struct TypeToRuntimeTypeIndex<T, std::enable_if_t<std::is_base_of_v<ObjectRef,
T>>> {
- static int32_t v() { return T::ContainerType::RuntimeTypeIndex(); }
-};
-
// None
template <>
struct TypeTraits<std::nullptr_t> : public TypeTraitsBase {
@@ -277,26 +369,16 @@ struct TypeTraits<bool> : public TypeTraitsBase {
}
};
-// Integer POD values
template <typename Int>
-struct TypeTraits<Int, std::enable_if_t<std::is_integral_v<Int>>> : public
TypeTraitsBase {
+struct TypeTraitsIntBase : public TypeTraitsBase {
static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIInt;
- TVM_FFI_INLINE static void CopyToAnyView(const Int& src, TVMFFIAny* result) {
- if constexpr (std::is_unsigned_v<Int> && sizeof(Int) >= sizeof(int64_t)) {
- if (src > static_cast<Int>(std::numeric_limits<int64_t>::max())) {
- TVM_FFI_THROW(OverflowError)
- << "Integer value " << src << " is too large to fit in int64_t. "
- << "Consider explicitly casting to int64_t first if this is
intentional.";
- }
- }
+ TVM_FFI_INLINE static void CopyInt64ToAnyView(int64_t src, TVMFFIAny*
result) {
result->type_index = TypeIndex::kTVMFFIInt;
result->zero_padding = 0;
- result->v_int64 = static_cast<int64_t>(src); //
NOLINT(bugprone-signed-char-misuse)
+ result->v_int64 = src;
}
- TVM_FFI_INLINE static void MoveToAny(Int src, TVMFFIAny* result) {
CopyToAnyView(src, result); }
-
TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
// NOTE: CheckAnyStrict is always strict and should be consistent with
MoveToAny
return src->type_index == TypeIndex::kTVMFFIInt;
@@ -325,6 +407,16 @@ struct TypeTraits<Int,
std::enable_if_t<std::is_integral_v<Int>>> : public TypeT
}
};
+// Integer POD values
+template <typename Int>
+struct TypeTraits<Int, std::enable_if_t<std::is_integral_v<Int>>> : public
TypeTraitsIntBase<Int> {
+ TVM_FFI_INLINE static void CopyToAnyView(const Int& src, TVMFFIAny* result) {
+ TypeTraitsIntBase<Int>::CopyInt64ToAnyView(static_cast<int64_t>(src),
result);
+ }
+
+ TVM_FFI_INLINE static void MoveToAny(Int src, TVMFFIAny* result) {
CopyToAnyView(src, result); }
+};
+
/// \cond Doxygen_Suppress
// trait to check if a type is an integeral enum
@@ -340,45 +432,15 @@ constexpr bool is_integeral_enum_v<T, true> =
std::is_integral_v<std::underlying
// Enum Integer POD values
template <typename IntEnum>
-struct TypeTraits<IntEnum, std::enable_if_t<is_integeral_enum_v<IntEnum>>> :
public TypeTraitsBase {
- static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIInt;
-
+struct TypeTraits<IntEnum, std::enable_if_t<is_integeral_enum_v<IntEnum>>>
+ : public TypeTraitsIntBase<IntEnum> {
TVM_FFI_INLINE static void CopyToAnyView(const IntEnum& src, TVMFFIAny*
result) {
- result->type_index = TypeIndex::kTVMFFIInt;
- result->zero_padding = 0;
- result->v_int64 = static_cast<int64_t>(src);
+ TypeTraitsIntBase<IntEnum>::CopyInt64ToAnyView(static_cast<int64_t>(src),
result);
}
TVM_FFI_INLINE static void MoveToAny(IntEnum src, TVMFFIAny* result) {
CopyToAnyView(src, result);
}
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- // NOTE: CheckAnyStrict is always strict and should be consistent with
MoveToAny
- return src->type_index == TypeIndex::kTVMFFIInt;
- }
-
- TVM_FFI_INLINE static IntEnum CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
- TVM_FFI_UNSAFE_ASSUME(src->type_index == TypeIndex::kTVMFFIInt);
- return static_cast<IntEnum>(src->v_int64);
- }
-
- TVM_FFI_INLINE static IntEnum MoveFromAnyAfterCheck(TVMFFIAny* src) {
- // POD type, we can just copy the value
- return CopyFromAnyViewAfterCheck(src);
- }
-
- TVM_FFI_INLINE static std::optional<IntEnum> TryCastFromAnyView(const
TVMFFIAny* src) {
- if (src->type_index == TypeIndex::kTVMFFIInt || src->type_index ==
TypeIndex::kTVMFFIBool) {
- return static_cast<IntEnum>(src->v_int64);
- }
- return std::nullopt;
- }
-
- TVM_FFI_INLINE static std::string TypeStr() { return
StaticTypeKey::kTVMFFIInt; }
- TVM_FFI_INLINE static std::string TypeSchema() {
- return R"({"type":")" + std::string(StaticTypeKey::kTVMFFIInt) + R"("})";
- }
};
// Float POD values
@@ -515,144 +577,6 @@ struct TypeTraits<DLDevice> : public TypeTraitsBase {
}
};
-// DLTensor*, requirement: not nullable, do not retain ownership
-template <>
-struct TypeTraits<DLTensor*> : public TypeTraitsBase {
- static constexpr bool storage_enabled = false;
- static constexpr int32_t field_static_type_index =
TypeIndex::kTVMFFIDLTensorPtr;
-
- TVM_FFI_INLINE static void CopyToAnyView(DLTensor* src, TVMFFIAny* result) {
- TVM_FFI_ICHECK_NOTNULL(src);
- result->type_index = TypeIndex::kTVMFFIDLTensorPtr;
- result->zero_padding = 0;
- TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
- result->v_ptr = src;
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- return src->type_index == TypeIndex::kTVMFFIDLTensorPtr;
- }
-
- TVM_FFI_INLINE static DLTensor* CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
- TVM_FFI_UNSAFE_ASSUME(src->type_index == TypeIndex::kTVMFFIDLTensorPtr);
- return static_cast<DLTensor*>(src->v_ptr);
- }
-
- TVM_FFI_INLINE static void MoveToAny(DLTensor*, TVMFFIAny*) {
- TVM_FFI_THROW(RuntimeError)
- << "DLTensor* cannot be held in Any as it does not retain ownership,
use Tensor instead";
- }
-
- TVM_FFI_INLINE static std::optional<DLTensor*> TryCastFromAnyView(const
TVMFFIAny* src) {
- if (src->type_index == TypeIndex::kTVMFFIDLTensorPtr) {
- return static_cast<DLTensor*>(src->v_ptr);
- } else if (src->type_index == TypeIndex::kTVMFFITensor) {
- // Conversion from Tensor pointer to DLTensor
- // based on the assumption that Tensor always follows the TVMFFIObject
header
- static_assert(sizeof(TVMFFIObject) == 24);
- return reinterpret_cast<DLTensor*>(reinterpret_cast<char*>(src->v_obj) +
- sizeof(TVMFFIObject));
- }
- return std::nullopt;
- }
-
- TVM_FFI_INLINE static std::string TypeStr() { return "DLTensor*"; }
- TVM_FFI_INLINE static std::string TypeSchema() { return
R"({"type":"DLTensor*"})"; }
-};
-
-// Traits for ObjectRef, None to ObjectRef will always fail.
-// use std::optional<ObjectRef> instead for nullable references.
-template <typename TObjRef>
-struct ObjectRefTypeTraitsBase : public TypeTraitsBase {
- static constexpr int32_t field_static_type_index = TypeIndex::kTVMFFIObject;
- using ContainerType = typename TObjRef::ContainerType;
-
- TVM_FFI_INLINE static void CopyToAnyView(const TObjRef& src, TVMFFIAny*
result) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (!src.defined()) {
- TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
- return;
- }
- }
- TVMFFIObject* obj_ptr =
details::ObjectUnsafe::TVMFFIObjectPtrFromObjectRef(src);
- result->type_index = obj_ptr->type_index;
- result->zero_padding = 0;
- TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
- result->v_obj = obj_ptr;
- }
-
- TVM_FFI_INLINE static void MoveToAny(TObjRef src, TVMFFIAny* result) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (!src.defined()) {
- TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
- return;
- }
- }
- TVMFFIObject* obj_ptr =
details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(src));
- result->type_index = obj_ptr->type_index;
- result->zero_padding = 0;
- TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
- result->v_obj = obj_ptr;
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (src->type_index == TypeIndex::kTVMFFINone) return true;
- }
- return (src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
- details::IsObjectInstance<ContainerType>(src->type_index));
- }
-
- TVM_FFI_INLINE static TObjRef CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (src->type_index == TypeIndex::kTVMFFINone) {
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
- }
- }
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(
- details::ObjectUnsafe::ObjectPtrFromUnowned<Object>(src->v_obj));
- }
-
- TVM_FFI_INLINE static TObjRef MoveFromAnyAfterCheck(TVMFFIAny* src) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (src->type_index == TypeIndex::kTVMFFINone) {
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
- }
- }
- // move out the object pointer
- ObjectPtr<ContainerType> obj_ptr =
- details::ObjectUnsafe::ObjectPtrFromOwned<ContainerType>(src->v_obj);
- // reset the src to nullptr
- TypeTraits<std::nullptr_t>::MoveToAny(nullptr, src);
- return
details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(std::move(obj_ptr));
- }
-
- TVM_FFI_INLINE static std::optional<TObjRef> TryCastFromAnyView(const
TVMFFIAny* src) {
- if constexpr (TObjRef::_type_is_nullable) {
- if (src->type_index == TypeIndex::kTVMFFINone) {
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(nullptr);
- }
- }
- if (src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin) {
- if (details::IsObjectInstance<ContainerType>(src->type_index)) {
- return details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(
-
details::ObjectUnsafe::ObjectPtrFromUnowned<ContainerType>(src->v_obj));
- }
- }
- return std::nullopt;
- }
-
- TVM_FFI_INLINE static std::string TypeStr() { return
ContainerType::_type_key; }
- TVM_FFI_INLINE static std::string TypeSchema() {
- return R"({"type":")" + std::string(ContainerType::_type_key) + R"("})";
- }
-};
-
-template <typename TObjRef>
-struct TypeTraits<TObjRef, std::enable_if_t<std::is_base_of_v<ObjectRef,
TObjRef> &&
-
use_default_type_traits_v<TObjRef>>>
- : public ObjectRefTypeTraitsBase<TObjRef> {};
-
/*!
* \brief Helper class that convert to T only via the FallbackTypes
*
@@ -689,157 +613,6 @@ struct FallbackOnlyTraitsBase : public TypeTraitsBase {
/// \endcond
};
-/*!
- * \brief Helper class to define ObjectRef that can be auto-converted from a
- * fallback type, the Traits<ObjectRefType> must be derived from it
- * and define a static methods named ConvertFallbackValue for each
- * FallbackType
- *
- * The conversion will go through the FallbackTypes in the order
- * specified in the template parameter.
- * \tparam ObjectRefType The type of the ObjectRef.
- * \tparam FallbackTypes The type of the fallback value.
- */
-template <typename ObjectRefType, typename... FallbackTypes>
-struct ObjectRefWithFallbackTraitsBase : public
ObjectRefTypeTraitsBase<ObjectRefType> {
- /// \cond Doxygen_Suppress
- TVM_FFI_INLINE static std::optional<ObjectRefType> TryCastFromAnyView(const
TVMFFIAny* src) {
- if (auto opt_obj =
ObjectRefTypeTraitsBase<ObjectRefType>::TryCastFromAnyView(src)) {
- return opt_obj;
- }
- // apply fallback types in TryCastFromAnyView
- return TryFallbackTypes<FallbackTypes...>(src);
- }
-
- template <typename FallbackType, typename... Rest>
- TVM_FFI_INLINE static std::optional<ObjectRefType> TryFallbackTypes(const
TVMFFIAny* src) {
- static_assert(!std::is_same_v<bool, FallbackType>,
- "Using bool as FallbackType can cause bug because int will
be detected as bool, "
- "use tvm::ffi::StrictBool instead");
- if (auto opt_fallback = TypeTraits<FallbackType>::TryCastFromAnyView(src))
{
- return
TypeTraits<ObjectRefType>::ConvertFallbackValue(*std::move(opt_fallback));
- }
- if constexpr (sizeof...(Rest) > 0) {
- return TryFallbackTypes<Rest...>(src);
- }
- return std::nullopt;
- }
- /// \endcond
-};
-
-// Traits for weak pointer of object
-// NOTE: we require the weak pointer cast from
-
-template <typename TObject>
-struct TypeTraits<TObject*, std::enable_if_t<std::is_base_of_v<Object,
TObject>>>
- : public TypeTraitsBase {
- TVM_FFI_INLINE static void CopyToAnyView(TObject* src, TVMFFIAny* result) {
- TVMFFIObject* obj_ptr = details::ObjectUnsafe::GetHeader(src);
- result->type_index = obj_ptr->type_index;
- result->zero_padding = 0;
- TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
- result->v_obj = obj_ptr;
- }
-
- TVM_FFI_INLINE static void MoveToAny(TObject* src, TVMFFIAny* result) {
- TVMFFIObject* obj_ptr = details::ObjectUnsafe::GetHeader(src);
- result->type_index = obj_ptr->type_index;
- result->zero_padding = 0;
- TVM_FFI_CLEAR_PTR_PADDING_IN_FFI_ANY(result);
- result->v_obj = obj_ptr;
- // needs to increase ref because original weak ptr do not own the code
- details::ObjectUnsafe::IncRefObjectHandle(result->v_obj);
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- return src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
- details::IsObjectInstance<TObject>(src->type_index);
- }
-
- TVM_FFI_INLINE static TObject* CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
- if constexpr (!std::is_const_v<TObject>) {
- static_assert(TObject::_type_mutable, "TObject must be mutable to enable
cast from Any");
- }
- return details::ObjectUnsafe::RawObjectPtrFromUnowned<TObject>(src->v_obj);
- }
-
- TVM_FFI_INLINE static std::optional<TObject*> TryCastFromAnyView(const
TVMFFIAny* src) {
- if constexpr (!std::is_const_v<TObject>) {
- static_assert(TObject::_type_mutable, "TObject must be mutable to enable
cast from Any");
- }
- if (CheckAnyStrict(src)) return CopyFromAnyViewAfterCheck(src);
- return std::nullopt;
- }
-
- TVM_FFI_INLINE static std::string TypeStr() { return TObject::_type_key; }
- TVM_FFI_INLINE static std::string TypeSchema() {
- return R"({"type":")" + std::string(TObject::_type_key) + R"("})";
- }
-};
-
-template <typename T>
-inline constexpr bool use_default_type_traits_v<Optional<T>> = false;
-
-template <typename T>
-struct TypeTraits<Optional<T>> : public TypeTraitsBase {
- TVM_FFI_INLINE static void CopyToAnyView(const Optional<T>& src, TVMFFIAny*
result) {
- if (src.has_value()) {
- TypeTraits<T>::CopyToAnyView(*src, result);
- } else {
- TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
- }
- }
-
- TVM_FFI_INLINE static void MoveToAny(Optional<T> src, TVMFFIAny* result) {
- if (src.has_value()) {
- TypeTraits<T>::MoveToAny(*std::move(src), result);
- } else {
- TypeTraits<std::nullptr_t>::CopyToAnyView(nullptr, result);
- }
- }
-
- TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
- if (src->type_index == TypeIndex::kTVMFFINone) return true;
- return TypeTraits<T>::CheckAnyStrict(src);
- }
-
- TVM_FFI_INLINE static Optional<T> CopyFromAnyViewAfterCheck(const TVMFFIAny*
src) {
- if (src->type_index == TypeIndex::kTVMFFINone) {
- return Optional<T>(std::nullopt);
- }
- return TypeTraits<T>::CopyFromAnyViewAfterCheck(src);
- }
-
- TVM_FFI_INLINE static Optional<T> MoveFromAnyAfterCheck(TVMFFIAny* src) {
- if (src->type_index == TypeIndex::kTVMFFINone) {
- return Optional<T>(std::nullopt);
- }
- return TypeTraits<T>::MoveFromAnyAfterCheck(src);
- }
-
- TVM_FFI_INLINE static std::optional<Optional<T>> TryCastFromAnyView(const
TVMFFIAny* src) {
- if (src->type_index == TypeIndex::kTVMFFINone) return
Optional<T>(std::nullopt);
- if (std::optional<T> opt = TypeTraits<T>::TryCastFromAnyView(src)) {
- return Optional<T>(*std::move(opt));
- } else {
- // important to be explicit here
- // because nullopt can convert to std::optional<T>(nullopt) which
indicate success
- // return std::optional<Optional<T>>(std::nullopt) to indicate failure
- return std::optional<Optional<T>>(std::nullopt);
- }
- }
-
- TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const TVMFFIAny* src) {
- return TypeTraits<T>::GetMismatchTypeInfo(src);
- }
-
- TVM_FFI_INLINE static std::string TypeStr() {
- return "Optional<" + TypeTraits<T>::TypeStr() + ">";
- }
- TVM_FFI_INLINE static std::string TypeSchema() {
- return R"({"type":"Optional","args":[)" + details::TypeSchema<T>::v() +
"]}";
- }
-};
} // namespace ffi
} // namespace tvm
#endif // TVM_FFI_TYPE_TRAITS_H_
diff --git a/tests/cpp/test_any.cc b/tests/cpp/test_any.cc
index 2686b7a8..bc8d36d6 100644
--- a/tests/cpp/test_any.cc
+++ b/tests/cpp/test_any.cc
@@ -18,6 +18,7 @@
*/
#include <gtest/gtest.h>
#include <tvm/ffi/any.h>
+#include <tvm/ffi/container/tensor.h>
#include <tvm/ffi/memory.h>
#include <limits>
diff --git a/tests/cpp/test_function.cc b/tests/cpp/test_function.cc
index fddb8fd8..1a915539 100644
--- a/tests/cpp/test_function.cc
+++ b/tests/cpp/test_function.cc
@@ -22,6 +22,7 @@
#include <tvm/ffi/any.h>
#include <tvm/ffi/container/array.h>
#include <tvm/ffi/container/map.h>
+#include <tvm/ffi/container/tensor.h>
#include <tvm/ffi/extra/json.h>
#include <tvm/ffi/function.h>
#include <tvm/ffi/memory.h>
diff --git a/tests/lint/check_asf_header.py b/tests/lint/check_asf_header.py
index efc35464..80e27f0d 100644
--- a/tests/lint/check_asf_header.py
+++ b/tests/lint/check_asf_header.py
@@ -170,8 +170,10 @@ FMT_MAP = {
"bat": header_cmdstyle,
}
-# Files and patterns to skip during header checking
-SKIP_LIST: list[str] = []
+# Files and patterns to skip during header checking.
+SKIP_LIST: list[str] = [
+ ".agents/skills/**/SKILL.md",
+]
def should_skip_file(filepath: str) -> bool: