FTL: Downcast to Optional<T> implicitly

The expression `ftl::Optional(std::optional(T()))` should not have type
`ftl::Optional<std::optional<T>>`.

Bug: 185536303
Test: ftl_test
Change-Id: I931cc58b985e7c41037ed50bc68abdc8028c4bdd
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index a0a95c4..626507f 100644
--- a/include/ftl/optional.h
+++ b/include/ftl/optional.h
@@ -32,6 +32,9 @@
 struct Optional final : std::optional<T> {
   using std::optional<T>::optional;
 
+  // Implicit downcast.
+  Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
+
   using std::optional<T>::has_value;
   using std::optional<T>::value;
 
@@ -94,8 +97,11 @@
   }
 };
 
-// Deduction guide.
+// Deduction guides.
 template <typename T>
 Optional(T) -> Optional<T>;
 
+template <typename T>
+Optional(std::optional<T>) -> Optional<T>;
+
 }  // namespace android::ftl
diff --git a/libs/ftl/optional_test.cpp b/libs/ftl/optional_test.cpp
index ad8d3cf..f7410c2 100644
--- a/libs/ftl/optional_test.cpp
+++ b/libs/ftl/optional_test.cpp
@@ -33,6 +33,29 @@
 using ftl::Optional;
 using ftl::StaticVector;
 
+TEST(Optional, Construct) {
+  // Empty.
+  EXPECT_EQ(std::nullopt, Optional<int>());
+  EXPECT_EQ(std::nullopt, Optional<std::string>(std::nullopt));
+
+  // Value.
+  EXPECT_EQ('?', Optional('?'));
+  EXPECT_EQ(""s, Optional(std::string()));
+
+  // In place.
+  EXPECT_EQ("???"s, Optional<std::string>(std::in_place, 3u, '?'));
+  EXPECT_EQ("abc"s, Optional<std::string>(std::in_place, {'a', 'b', 'c'}));
+
+  // Implicit downcast.
+  {
+    Optional opt = std::optional("test"s);
+    static_assert(std::is_same_v<decltype(opt), Optional<std::string>>);
+
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(opt.value(), "test"s);
+  }
+}
+
 TEST(Optional, Transform) {
   // Empty.
   EXPECT_EQ(std::nullopt, Optional<int>().transform([](int) { return 0; }));