[FFI] Add ref-qualified strict ObjectRef casts#639
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces as_or_throw() methods for both Any and ObjectRef classes to strictly reinterpret types or throw a TypeError upon failure. It also updates ObjectRef::as() to support rvalue and lvalue overloads with strict type checking, and refines the TVM_FFI_UNSAFE_ASSUME macro for GCC to use __builtin_unreachable(). The reviewer suggests simplifying the ObjectRef::as_or_throw() implementations by delegating directly to as() to eliminate duplicated low-level logic and improve maintainability.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
5d556f1 to
f5bdcc8
Compare
Refactor ObjectRef::as<T>() and as_or_throw<T>() to support const and rvalue ObjectRef paths. Reuse Any TypeTraits checks through inline TVMFFIAny views for richer ObjectRef compatibility checks and mismatch messages, while keeping null handling explicit. Add focused tests for const and move variants of as<T>() and as_or_throw<T>().
f5bdcc8 to
39bd5e2
Compare
This PR refactors strict ObjectRef casting to use the Any TypeTraits strict-check path and adds strict throwing APIs.
Main benefit:
AnyandObjectRefnow have consistent strictas/as_or_throwAPIs: both rely on the sameTypeTraitsstrict-check semantics, both return optional values for probe-styleas<T>(), and both provide throwingas_or_throw<T>()variants for required casts.TypeTraits<ObjectRefType>::CheckAnyStrict, instead of being limited to the target ref's canonicalContainerTypeinstance check.ObjectRefType::ContainerTypenow has an explicit_type_container_is_exactinvariant. Ordinary refs inherittruefromObjectRef, while richer parameterized refs such asArray<T>,Map<K,V>,Tuple<...>, and object-backedVariant<...>opt out because their accepted values are determined byTypeTraits, not only by the backing container.GetRefis guarded to only work for exact-container refs.API behavior:
ObjectRef::as<ObjectRefType>() const&returnsstd::optional<ObjectRefType>. For a non-null source, it succeeds only whenTypeTraits<ObjectRefType>::CheckAnyStrictaccepts the object through a compact temporaryTVMFFIAnyview. On success, it returns a ref that shares the original object pointer. On type mismatch, it returnsstd::nullopt.ObjectRef::as<ObjectRefType>() &&has the same strict-check andstd::nulloptbehavior, but moves the object pointer into the returned ref on success and clears the source ref.ObjectRefsources,ObjectRef::as<ObjectRefType>()returns a successful null ref when the target ref type is nullable, and returnsstd::nulloptfor non-nullable target refs. The null path is explicit and is not treated as a globally cold failure path.ObjectRef::as_or_throw<ObjectRefType>() const&and&&are the throwing forms of the same strict ObjectRef cast. They returnObjectRefTypeon success, preserve/move the object pointer according to the receiver qualifier, return a null ref for nullable null targets, and throwTypeErrorfor non-nullable null or type-mismatch cases.Any::as_or_throw<T>() const&and&&are strict reinterpretation helpers forAny. They call the corresponding strictas<T>()path, returnTon success, and throwTypeErroron mismatch. They do not run fallback conversions; usecast<T>()when conversion is intended.asAPIs intentionally do not use success/failure prediction annotations becausestd::nulloptcan be a normal probe result. Throwing APIs mark only the final failure/throw path as cold, andObjectRef::as_or_throwmarks the strict-check success path as likely because mismatch throws.Implementation notes:
ObjectRef::as<T>()no longer relies onT::ContainerTypeas the complete runtime compatibility test. It piggy-backs on AnyTypeTraitsstrict checks, so ref types with richer strict compatibility rules work consistently withAny.TVMFFIAnysetup is deliberately kept inline in the non-null ObjectRef paths. This preserves explicit null behavior and letsas_or_throwcallTypeTraits<T>::GetMismatchTypeInfofor richer diagnostics instead of reducing toas<T>()and losing the synthesized Any view.Changes:
ObjectRef::as<T>()andObjectRef::as_or_throw<T>()overloads for const and rvalue receivers.Any::as_or_throw<T>()const/rvalue helpers.TVMFFIAnyviews for richTypeTraitschecks and mismatch messages._type_container_is_exactand guardGetRefso it is only used for refs whoseContainerTypeis an exact acceptance predicate.as<T>()andas_or_throw<T>(), plus compile-time coverage for exact/non-exact container-ref flags.TVM_FFI_UNSAFE_ASSUMElowering to be more robust for GCC.