Skip to content

Commit 56b5ee1

Browse files
author
Github Executorch
committed
Update
[ghstack-poisoned]
2 parents 36e811f + 4237e55 commit 56b5ee1

2 files changed

Lines changed: 107 additions & 194 deletions

File tree

runtime/core/evalue.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
namespace executorch {
1212
namespace runtime {
13+
14+
// Specialize for list of optional tensors, as nullptr is a valid std::nullopt.
15+
// For non-optional types, nullptr is invalid.
16+
1317
template <>
1418
executorch::aten::ArrayRef<std::optional<executorch::aten::Tensor>>
1519
BoxedEvalueList<std::optional<executorch::aten::Tensor>>::get() const {
@@ -28,10 +32,6 @@ BoxedEvalueList<std::optional<executorch::aten::Tensor>>::get() const {
2832
unwrapped_vals_, wrapped_vals_.size()};
2933
}
3034

31-
// Specialization note: unlike the generic tryGet, a null wrapped_vals_[i]
32-
// here is a valid encoding of None (matching the get() specialization above,
33-
// which mirrors parseListOptionalType's "absent index" convention). Only an
34-
// element whose tag is neither None nor Tensor is treated as an error.
3535
template <>
3636
Result<executorch::aten::ArrayRef<std::optional<executorch::aten::Tensor>>>
3737
BoxedEvalueList<std::optional<executorch::aten::Tensor>>::tryGet() const {

runtime/core/test/evalue_test.cpp

Lines changed: 103 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
using namespace ::testing;
1818

19+
using executorch::aten::DeviceType;
20+
using executorch::aten::Layout;
21+
using executorch::aten::MemoryFormat;
1922
using executorch::aten::ScalarType;
2023
using executorch::runtime::BoxedEvalueList;
24+
using executorch::runtime::Error;
2125
using executorch::runtime::EValue;
2226
using executorch::runtime::Tag;
2327
using executorch::runtime::testing::TensorFactory;
@@ -239,8 +243,7 @@ TEST_F(EValueTest, BoxedEvalueListTryGetWrongElementTag) {
239243
}
240244

241245
TEST_F(EValueTest, BoxedEvalueListTryGetNullElement) {
242-
// A null wrapped pointer is a malformed program for non-optional lists;
243-
// tryGet reports InvalidState rather than aborting inside ET_CHECK.
246+
// A null value is a malformed program for non-optional lists.
244247
EValue a((int64_t)1);
245248
EValue c((int64_t)3);
246249
EValue* values_p[3] = {&a, nullptr, &c};
@@ -251,8 +254,7 @@ TEST_F(EValueTest, BoxedEvalueListTryGetNullElement) {
251254
}
252255

253256
TEST_F(EValueTest, BoxedEvalueListTryGetOptionalTensorNullIsNone) {
254-
// For the optional<Tensor> specialization, a null wrapped pointer is a
255-
// valid None encoding (matches parseListOptionalType), not an error.
257+
// For optional<Tensor>, null value is valid.
256258
EValue a;
257259
EValue* values_p[2] = {&a, nullptr};
258260
std::optional<executorch::aten::Tensor> storage[2];
@@ -469,204 +471,115 @@ TEST_F(EValueTest, toListOptionalTensorNullPointerCheck) {
469471
ET_EXPECT_DEATH({ e.toListOptionalTensor(); }, "pointer is null");
470472
}
471473

472-
TEST_F(EValueTest, TryToTensorSuccess) {
473-
TensorFactory<ScalarType::Float> tf;
474-
EValue e(tf.ones({3, 2}));
475-
auto result = e.tryToTensor();
476-
EXPECT_TRUE(result.ok());
477-
EXPECT_EQ(result->dim(), 2);
478-
EXPECT_EQ(result->numel(), 6);
479-
}
480-
481-
TEST_F(EValueTest, TryToTensorTypeMismatch) {
482-
EValue e(static_cast<int64_t>(42));
483-
auto result = e.tryToTensor();
484-
EXPECT_FALSE(result.ok());
485-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
486-
}
487-
488-
TEST_F(EValueTest, TryToOptionalTensorSuccess) {
489-
TensorFactory<ScalarType::Float> tf;
490-
EValue e(tf.ones({3, 2}));
491-
auto result = e.tryToOptional<executorch::aten::Tensor>();
492-
EXPECT_TRUE(result.ok());
493-
EXPECT_TRUE(result->has_value());
494-
EXPECT_EQ(result->value().dim(), 2);
495-
}
496-
497-
TEST_F(EValueTest, TryToOptionalTensorNone) {
498-
EValue e;
499-
auto result = e.tryToOptional<executorch::aten::Tensor>();
500-
EXPECT_TRUE(result.ok());
501-
EXPECT_FALSE(result->has_value());
502-
}
503-
504-
TEST_F(EValueTest, TryToOptionalTensorTypeMismatch) {
505-
EValue e(static_cast<int64_t>(42));
506-
auto result = e.tryToOptional<executorch::aten::Tensor>();
507-
EXPECT_FALSE(result.ok());
508-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
509-
}
510-
511-
// Scalar/primitive tryTo* coverage. The Success+TypeMismatch pair is
512-
// identical per-type modulo the method name, so the macro below generates
513-
// both tests. `match_value` should satisfy the isX() tag check; `mismatch_ev`
514-
// must construct an EValue whose tag differs.
515-
#define TRY_TO_PRIMITIVE_TEST(Name, Type, match_value, mismatch_ev) \
516-
TEST_F(EValueTest, TryTo##Name##Success) { \
517-
EValue e(static_cast<Type>(match_value)); \
518-
auto result = e.tryTo##Name(); \
519-
EXPECT_TRUE(result.ok()); \
520-
EXPECT_EQ(result.get(), static_cast<Type>(match_value)); \
521-
} \
522-
TEST_F(EValueTest, TryTo##Name##TypeMismatch) { \
523-
EValue e(mismatch_ev); \
524-
auto result = e.tryTo##Name(); \
525-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType); \
526-
}
527-
528-
TRY_TO_PRIMITIVE_TEST(Int, int64_t, 42, 3.14)
529-
TRY_TO_PRIMITIVE_TEST(Double, double, 3.14, static_cast<int64_t>(42))
530-
TRY_TO_PRIMITIVE_TEST(Bool, bool, true, static_cast<int64_t>(42))
531-
532-
#undef TRY_TO_PRIMITIVE_TEST
533-
534-
TEST_F(EValueTest, TryToScalarFromInt) {
535-
EValue e(static_cast<int64_t>(7));
536-
auto result = e.tryToScalar();
537-
EXPECT_TRUE(result.ok());
538-
EXPECT_EQ(result->to<int64_t>(), 7);
539-
}
540-
541-
TEST_F(EValueTest, TryToScalarFromDouble) {
542-
EValue e(2.5);
543-
auto result = e.tryToScalar();
544-
EXPECT_TRUE(result.ok());
545-
EXPECT_DOUBLE_EQ(result->to<double>(), 2.5);
546-
}
547-
548-
TEST_F(EValueTest, TryToScalarFromBool) {
549-
EValue e(true);
550-
auto result = e.tryToScalar();
551-
EXPECT_TRUE(result.ok());
552-
EXPECT_EQ(result->to<bool>(), true);
553-
}
554-
555-
TEST_F(EValueTest, TryToScalarNoneTag) {
556-
// None is neither Int/Double/Bool, so tryToScalar must reject it.
557-
EValue e;
558-
auto result = e.tryToScalar();
559-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
560-
}
561-
562-
TEST_F(EValueTest, TryToScalarTypeTagReturnsScalarType) {
563-
// ScalarType/MemoryFormat/Layout/Device share the Int tag; exercise each.
564-
EValue e(static_cast<int64_t>(static_cast<int>(ScalarType::Float)));
565-
auto st = e.tryToScalarType();
566-
EXPECT_TRUE(st.ok());
567-
EXPECT_EQ(st.get(), ScalarType::Float);
568-
}
474+
// Per-type tryTo* coverage.
475+
// For each type:
476+
// - success and failure for named method tryTo[Int/Double/Bool/Tensor/..]
477+
// - success and failure for templated tryTo<T>() specialization
569478

570-
TEST_F(EValueTest, TryToScalarTypeTypeMismatch) {
571-
EValue e(3.14);
572-
auto result = e.tryToScalarType();
573-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
574-
}
575-
576-
TEST_F(EValueTest, TryToMemoryFormatTypeMismatch) {
577-
EValue e(3.14);
578-
auto result = e.tryToMemoryFormat();
579-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
580-
}
581-
582-
TEST_F(EValueTest, TryToLayoutTypeMismatch) {
583-
EValue e(3.14);
584-
auto result = e.tryToLayout();
585-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
586-
}
587-
588-
TEST_F(EValueTest, TryToDeviceTypeMismatch) {
589-
EValue e(3.14);
590-
auto result = e.tryToDevice();
591-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
592-
}
593-
594-
// List tryTo* — only cover TensorList and ListOptionalTensor. The other
595-
// list/string variants share the same `if (!isX()) return Error::InvalidType`
596-
// pattern exercised by the primitive mismatch tests above. Tensor-family
597-
// lists are the highest-risk attack surface (pointer-holding), so keep
598-
// explicit coverage.
599-
600-
TEST_F(EValueTest, TryToTensorListTypeMismatch) {
601-
EValue e(static_cast<int64_t>(42));
602-
auto result = e.tryToTensorList();
603-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
604-
}
605-
606-
TEST_F(EValueTest, TryToListOptionalTensorTypeMismatch) {
607-
EValue e(static_cast<int64_t>(42));
608-
auto result = e.tryToListOptionalTensor();
609-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
479+
TEST_F(EValueTest, TryToInt) {
480+
EValue e_int(static_cast<int64_t>(42));
481+
EValue e_mismatch(3.14);
482+
EXPECT_EQ(e_int.tryToInt().get(), 42);
483+
EXPECT_EQ(e_mismatch.tryToInt().error(), Error::InvalidType);
484+
EXPECT_EQ(e_int.tryTo<int64_t>().get(), 42);
485+
EXPECT_EQ(e_mismatch.tryTo<int64_t>().error(), Error::InvalidType);
610486
}
611487

612-
// Templated tryTo<T>() dispatcher. Matches and mismatches should behave
613-
// identically to the named tryToX methods.
614-
615-
TEST_F(EValueTest, TryToTemplateIntSuccess) {
616-
EValue e(static_cast<int64_t>(42));
617-
auto result = e.tryTo<int64_t>();
618-
EXPECT_TRUE(result.ok());
619-
EXPECT_EQ(result.get(), 42);
488+
TEST_F(EValueTest, TryToDouble) {
489+
EValue e_double(3.14);
490+
EValue e_mismatch(static_cast<int64_t>(42));
491+
EXPECT_DOUBLE_EQ(e_double.tryToDouble().get(), 3.14);
492+
EXPECT_EQ(e_mismatch.tryToDouble().error(), Error::InvalidType);
493+
EXPECT_DOUBLE_EQ(e_double.tryTo<double>().get(), 3.14);
494+
EXPECT_EQ(e_mismatch.tryTo<double>().error(), Error::InvalidType);
620495
}
621496

622-
TEST_F(EValueTest, TryToTemplateIntMismatch) {
623-
EValue e(3.14);
624-
auto result = e.tryTo<int64_t>();
625-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
497+
TEST_F(EValueTest, TryToBool) {
498+
EValue e_bool(true);
499+
EValue e_mismatch(static_cast<int64_t>(42));
500+
EXPECT_EQ(e_bool.tryToBool().get(), true);
501+
EXPECT_EQ(e_mismatch.tryToBool().error(), Error::InvalidType);
502+
EXPECT_EQ(e_bool.tryTo<bool>().get(), true);
503+
EXPECT_EQ(e_mismatch.tryTo<bool>().error(), Error::InvalidType);
626504
}
627505

628-
TEST_F(EValueTest, TryToTemplateTensorSuccess) {
506+
TEST_F(EValueTest, TryToTensor) {
629507
TensorFactory<ScalarType::Float> tf;
630-
EValue e(tf.ones({3, 2}));
631-
auto result = e.tryTo<executorch::aten::Tensor>();
632-
EXPECT_TRUE(result.ok());
633-
EXPECT_EQ(result->numel(), 6);
508+
EValue e_tensor(tf.ones({3, 2}));
509+
EValue e_mismatch(static_cast<int64_t>(42));
510+
EXPECT_EQ(e_tensor.tryToTensor()->numel(), 6);
511+
EXPECT_EQ(e_mismatch.tryToTensor().error(), Error::InvalidType);
512+
EXPECT_EQ(e_tensor.tryTo<executorch::aten::Tensor>()->numel(), 6);
513+
EXPECT_EQ(
514+
e_mismatch.tryTo<executorch::aten::Tensor>().error(), Error::InvalidType);
634515
}
635516

636-
TEST_F(EValueTest, TryToOptionalIntSuccess) {
517+
TEST_F(EValueTest, TryToOptionalTensor) {
518+
TensorFactory<ScalarType::Float> tf;
519+
EValue e_tensor(tf.ones({3, 2}));
520+
EValue e_none;
521+
EValue e_mismatch(static_cast<int64_t>(42));
522+
// Named tryToOptional<Tensor>: value, None, mismatch.
523+
auto r_val = e_tensor.tryToOptional<executorch::aten::Tensor>();
524+
EXPECT_TRUE(r_val->has_value());
525+
EXPECT_EQ(r_val->value().numel(), 6);
526+
EXPECT_FALSE(e_none.tryToOptional<executorch::aten::Tensor>()->has_value());
527+
EXPECT_EQ(
528+
e_mismatch.tryToOptional<executorch::aten::Tensor>().error(),
529+
Error::InvalidType);
530+
// Templated tryTo<std::optional<Tensor>>: None path.
531+
EXPECT_FALSE(
532+
e_none.tryTo<std::optional<executorch::aten::Tensor>>()->has_value());
533+
}
534+
535+
TEST_F(EValueTest, TryToScalar) {
536+
EValue e_int(static_cast<int64_t>(7));
537+
EValue e_double(2.5);
538+
EValue e_bool(true);
539+
EValue e_none;
540+
EXPECT_EQ(e_int.tryToScalar()->to<int64_t>(), 7);
541+
EXPECT_DOUBLE_EQ(e_double.tryToScalar()->to<double>(), 2.5);
542+
EXPECT_EQ(e_bool.tryToScalar()->to<bool>(), true);
543+
// None is neither Int/Double/Bool.
544+
EXPECT_EQ(e_none.tryToScalar().error(), Error::InvalidType);
545+
}
546+
547+
TEST_F(EValueTest, TryToScalarType) {
548+
EValue e(static_cast<int64_t>(ScalarType::Float));
549+
EValue e_mismatch(3.14);
550+
EXPECT_EQ(e.tryToScalarType().get(), ScalarType::Float);
551+
EXPECT_EQ(e_mismatch.tryToScalarType().error(), Error::InvalidType);
552+
EXPECT_EQ(e.tryTo<ScalarType>().get(), ScalarType::Float);
553+
EXPECT_EQ(e_mismatch.tryTo<ScalarType>().error(), Error::InvalidType);
554+
}
555+
556+
TEST_F(EValueTest, TryToMemoryFormat) {
557+
EValue e(static_cast<int64_t>(MemoryFormat::Contiguous));
558+
EValue e_mismatch(3.14);
559+
EXPECT_EQ(e.tryToMemoryFormat().get(), MemoryFormat::Contiguous);
560+
EXPECT_EQ(e_mismatch.tryToMemoryFormat().error(), Error::InvalidType);
561+
}
562+
563+
TEST_F(EValueTest, TryToLayout) {
564+
EValue e(static_cast<int64_t>(Layout::Strided));
565+
EValue e_mismatch(3.14);
566+
EXPECT_EQ(e.tryToLayout().get(), Layout::Strided);
567+
EXPECT_EQ(e_mismatch.tryToLayout().error(), Error::InvalidType);
568+
}
569+
570+
TEST_F(EValueTest, TryToDevice) {
571+
EValue e(static_cast<int64_t>(DeviceType::CPU));
572+
EValue e_mismatch(3.14);
573+
EXPECT_EQ(e.tryToDevice().get().type(), DeviceType::CPU);
574+
EXPECT_EQ(e_mismatch.tryToDevice().error(), Error::InvalidType);
575+
}
576+
577+
TEST_F(EValueTest, TryToTensorList) {
637578
EValue e(static_cast<int64_t>(42));
638-
auto result = e.tryToOptional<int64_t>();
639-
EXPECT_TRUE(result.ok());
640-
EXPECT_TRUE(result->has_value());
641-
EXPECT_EQ(result->value(), 42);
579+
EXPECT_EQ(e.tryToTensorList().error(), Error::InvalidType);
642580
}
643581

644-
TEST_F(EValueTest, TryToOptionalIntNone) {
645-
EValue e;
646-
auto result = e.tryToOptional<int64_t>();
647-
EXPECT_TRUE(result.ok());
648-
EXPECT_FALSE(result->has_value());
649-
}
650-
651-
TEST_F(EValueTest, TryToOptionalIntTypeMismatch) {
652-
EValue e(3.14);
653-
auto result = e.tryToOptional<int64_t>();
654-
EXPECT_EQ(result.error(), executorch::runtime::Error::InvalidType);
655-
}
656-
657-
// Verify tryTo<std::optional<T>>() specializations match tryToOptional<T>()
658-
// semantics, mirroring the to<std::optional<T>>() specializations of to<T>().
659-
TEST_F(EValueTest, TryToTemplateOptionalIntSuccess) {
582+
TEST_F(EValueTest, TryToListOptionalTensor) {
660583
EValue e(static_cast<int64_t>(42));
661-
auto result = e.tryTo<std::optional<int64_t>>();
662-
EXPECT_TRUE(result.ok());
663-
EXPECT_TRUE(result->has_value());
664-
EXPECT_EQ(result->value(), 42);
665-
}
666-
667-
TEST_F(EValueTest, TryToTemplateOptionalTensorNone) {
668-
EValue e;
669-
auto result = e.tryTo<std::optional<executorch::aten::Tensor>>();
670-
EXPECT_TRUE(result.ok());
671-
EXPECT_FALSE(result->has_value());
584+
EXPECT_EQ(e.tryToListOptionalTensor().error(), Error::InvalidType);
672585
}

0 commit comments

Comments
 (0)