[fidlc] Use std::optional for optional handle types

Clearer than using unique_ptr, and makes copying easier, which we need
for templates.

Change-Id: Ie851ab3c461d8b4c3b58c08c7837685e2865f96c
diff --git a/zircon/system/host/fidl/BUILD.gn b/zircon/system/host/fidl/BUILD.gn
index f78b3f6..9e1a511 100644
--- a/zircon/system/host/fidl/BUILD.gn
+++ b/zircon/system/host/fidl/BUILD.gn
@@ -32,7 +32,6 @@
       "lib/virtual_source_file.cpp",
     ]
     public_deps = [
-      # <fidl/flat_ast.h> has #include <lib/fit/function.h>.
       "$zx/system/ulib/fit:headers",
     ]
     deps = [
diff --git a/zircon/system/host/fidl/include/fidl/flat_ast.h b/zircon/system/host/fidl/include/fidl/flat_ast.h
index 38dda94..b8e9abb 100644
--- a/zircon/system/host/fidl/include/fidl/flat_ast.h
+++ b/zircon/system/host/fidl/include/fidl/flat_ast.h
@@ -13,6 +13,7 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <optional>
 #include <type_traits>
 #include <variant>
 #include <vector>
@@ -651,16 +652,16 @@
 
 struct TypeConstructor {
     TypeConstructor(Name name, std::unique_ptr<TypeConstructor> maybe_arg_type_ctor,
-               std::unique_ptr<types::HandleSubtype> maybe_handle_subtype,
+               std::optional<types::HandleSubtype> handle_subtype,
                std::unique_ptr<Constant> maybe_size, types::Nullability nullability)
         : name(std::move(name)), maybe_arg_type_ctor(std::move(maybe_arg_type_ctor)),
-          maybe_handle_subtype(std::move(maybe_handle_subtype)),
+          handle_subtype(handle_subtype),
           maybe_size(std::move(maybe_size)), nullability(nullability) {}
 
     // Set during construction.
     const Name name;
     const std::unique_ptr<TypeConstructor> maybe_arg_type_ctor;
-    const std::unique_ptr<types::HandleSubtype> maybe_handle_subtype;
+    const std::optional<types::HandleSubtype> handle_subtype;
     const std::unique_ptr<Constant> maybe_size;
     const types::Nullability nullability;
 
@@ -898,7 +899,7 @@
 
     virtual bool Create(const SourceLocation* maybe_location,
                         const Type* arg_type,
-                        const types::HandleSubtype* handle_subtype,
+                        const std::optional<types::HandleSubtype>& handle_subtype,
                         const Size* size,
                         types::Nullability nullability,
                         std::unique_ptr<Type>* out_type) const = 0;
@@ -940,7 +941,7 @@
 
     bool Create(const flat::Name& name,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 const Type** out_type);
@@ -957,7 +958,7 @@
 
     bool CreateNotOwned(const flat::Name& name,
                         const Type* arg_type,
-                        const types::HandleSubtype* handle_subtype,
+                        const std::optional<types::HandleSubtype>& handle_subtype,
                         const Size* size,
                         types::Nullability nullability,
                         std::unique_ptr<Type>* out_type);
diff --git a/zircon/system/host/fidl/include/fidl/parser.h b/zircon/system/host/fidl/include/fidl/parser.h
index de7bb7f..4eb1a97 100644
--- a/zircon/system/host/fidl/include/fidl/parser.h
+++ b/zircon/system/host/fidl/include/fidl/parser.h
@@ -6,6 +6,7 @@
 #define ZIRCON_SYSTEM_HOST_FIDL_INCLUDE_FIDL_PARSER_H_
 
 #include <memory>
+#include <optional>
 
 #include "error_reporter.h"
 #include "lexer.h"
@@ -168,7 +169,7 @@
     }
 
     bool LookupHandleSubtype(const raw::Identifier* identifier,
-                             std::unique_ptr<types::HandleSubtype>* out_handle_subtype);
+                             std::optional<types::HandleSubtype>* out_handle_subtype);
 
     decltype(nullptr) Fail();
     decltype(nullptr) Fail(StringView message);
diff --git a/zircon/system/host/fidl/include/fidl/raw_ast.h b/zircon/system/host/fidl/include/fidl/raw_ast.h
index ab66c0c..2187214 100644
--- a/zircon/system/host/fidl/include/fidl/raw_ast.h
+++ b/zircon/system/host/fidl/include/fidl/raw_ast.h
@@ -6,6 +6,7 @@
 #define ZIRCON_SYSTEM_HOST_FIDL_INCLUDE_FIDL_RAW_AST_H_
 
 #include <memory>
+#include <optional>
 #include <utility>
 #include <vector>
 
@@ -220,13 +221,13 @@
     TypeConstructor(SourceElement const& element,
                     std::unique_ptr<CompoundIdentifier> identifier,
                     std::unique_ptr<TypeConstructor> maybe_arg_type_ctor,
-                    std::unique_ptr<types::HandleSubtype> maybe_handle_subtype,
+                    std::optional<types::HandleSubtype> handle_subtype,
                     std::unique_ptr<Constant> maybe_size,
                     types::Nullability nullability)
         : SourceElement(element.start_, element.end_),
           identifier(std::move(identifier)),
           maybe_arg_type_ctor(std::move(maybe_arg_type_ctor)),
-          maybe_handle_subtype(std::move(maybe_handle_subtype)),
+          handle_subtype(handle_subtype),
           maybe_size(std::move(maybe_size)),
           nullability(nullability) {}
 
@@ -234,7 +235,7 @@
 
     std::unique_ptr<CompoundIdentifier> identifier;
     std::unique_ptr<TypeConstructor> maybe_arg_type_ctor;
-    std::unique_ptr<types::HandleSubtype> maybe_handle_subtype;
+    std::optional<types::HandleSubtype> handle_subtype;
     std::unique_ptr<Constant> maybe_size;
     types::Nullability nullability;
 };
diff --git a/zircon/system/host/fidl/lib/flat_ast.cpp b/zircon/system/host/fidl/lib/flat_ast.cpp
index 9ce526a9..e011547 100644
--- a/zircon/system/host/fidl/lib/flat_ast.cpp
+++ b/zircon/system/host/fidl/lib/flat_ast.cpp
@@ -378,7 +378,7 @@
 
 bool Typespace::Create(const flat::Name& name,
                        const Type* arg_type,
-                       const types::HandleSubtype* handle_subtype,
+                       const std::optional<types::HandleSubtype>& handle_subtype,
                        const Size* size,
                        types::Nullability nullability,
                        const Type** out_type) {
@@ -392,7 +392,7 @@
 
 bool Typespace::CreateNotOwned(const flat::Name& name,
                        const Type* arg_type,
-                       const types::HandleSubtype* handle_subtype,
+                       const std::optional<types::HandleSubtype>& handle_subtype,
                        const Size* size,
                        types::Nullability nullability,
                        std::unique_ptr<Type>* out_type) {
@@ -447,10 +447,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* maybe_arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* maybe_size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (maybe_arg_type != nullptr)
             return CannotBeParameterized(maybe_location);
         if (maybe_size != nullptr)
@@ -474,10 +476,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* maybe_arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (maybe_arg_type != nullptr)
             return CannotBeParameterized(maybe_location);
         if (size == nullptr)
@@ -499,10 +503,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (arg_type == nullptr)
             return MustBeParameterized(maybe_location);
         if (size == nullptr)
@@ -522,10 +528,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (arg_type == nullptr)
             return MustBeParameterized(maybe_location);
         if (size == nullptr)
@@ -546,10 +554,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (arg_type != nullptr)
             return CannotBeParameterized(maybe_location);
         if (size == nullptr)
@@ -570,7 +580,7 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* maybe_arg_type,
-                const types::HandleSubtype* maybe_handle_subtype,
+                const std::optional<types::HandleSubtype>& handle_subtype,
                 const Size* maybe_size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
@@ -579,11 +589,11 @@
         if (maybe_size != nullptr)
             return CannotHaveSize(maybe_location);
 
-        auto handle_subtype = types::HandleSubtype::kHandle;
-        if (maybe_handle_subtype != nullptr)
-            handle_subtype = *maybe_handle_subtype;
-
-        *out_type = std::make_unique<HandleType>(handle_subtype, nullability);
+        *out_type = std::make_unique<HandleType>(
+            handle_subtype.has_value() ?
+                handle_subtype.value() :
+                types::HandleSubtype::kHandle,
+            nullability);
         return true;
     }
 };
@@ -595,10 +605,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* maybe_size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (arg_type == nullptr)
             return MustBeParameterized(maybe_location);
         if (arg_type->kind != Type::Kind::kIdentifier)
@@ -628,10 +640,12 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* arg_type,
-                const types::HandleSubtype* handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* size,
                 types::Nullability nullability,
                 std::unique_ptr<Type>* out_type) const {
+        assert(!no_handle_subtype.has_value());
+
         if (!type_decl_->compiled && type_decl_->kind != Decl::Kind::kInterface) {
             if (type_decl_->compiling) {
                 type_decl_->recursive = true;
@@ -687,7 +701,7 @@
 
     bool Create(const SourceLocation* maybe_location,
                 const Type* maybe_arg_type,
-                const types::HandleSubtype* no_handle_subtype,
+                const std::optional<types::HandleSubtype>& no_handle_subtype,
                 const Size* maybe_size,
                 types::Nullability maybe_nullability,
                 std::unique_ptr<Type>* out_type) const {
@@ -732,7 +746,7 @@
         }
 
         return typespace_->CreateNotOwned(partial_type_ctor_->name, arg_type,
-                                          nullptr /* handle_subtype */,
+                                          std::optional<types::HandleSubtype>(),
                                           size, nullability, out_type);
     }
 
@@ -1421,7 +1435,7 @@
     *out_type_ctor = std::make_unique<TypeConstructor>(
         std::move(name),
         std::move(maybe_arg_type_ctor),
-        std::move(raw_type_ctor->maybe_handle_subtype),
+        raw_type_ctor->handle_subtype,
         std::move(maybe_size),
         raw_type_ctor->nullability);
     return true;
@@ -1495,7 +1509,7 @@
         type_ctor = std::make_unique<TypeConstructor>(
             Name(nullptr, "uint32"),
             nullptr /* maybe_arg_type */,
-            nullptr /* maybe_handle_subtype */,
+            std::optional<types::HandleSubtype>(),
             nullptr /* maybe_size */,
             types::Nullability::kNonnullable);
     }
@@ -1552,7 +1566,7 @@
         type_ctor = std::make_unique<TypeConstructor>(
             Name(nullptr, "uint32"),
             nullptr /* maybe_arg_type */,
-            nullptr /* maybe_handle_subtype */,
+            std::optional<types::HandleSubtype>(),
             nullptr /* maybe_size */,
             types::Nullability::kNonnullable);
     }
@@ -1682,7 +1696,7 @@
     return std::make_unique<TypeConstructor>(
         Name(decl->name.library(), decl->name.name_part()),
         nullptr /* maybe_arg_type */,
-        nullptr /* maybe_handle_subtype */,
+        std::optional<types::HandleSubtype>(),
         nullptr /* maybe_size */,
         nullability);
 }
@@ -3131,7 +3145,7 @@
             return Fail(type_ctor->name.maybe_location(), "unable to parse size bound");
         size = static_cast<const Size*>(&type_ctor->maybe_size->Value());
     }
-    if (!typespace_->Create(type_ctor->name, maybe_arg_type, type_ctor->maybe_handle_subtype.get(),
+    if (!typespace_->Create(type_ctor->name, maybe_arg_type, type_ctor->handle_subtype,
                             size, type_ctor->nullability,
                             &type_ctor->type))
         return false;
diff --git a/zircon/system/host/fidl/lib/parser.cpp b/zircon/system/host/fidl/lib/parser.cpp
index b395ce4..66f8d17 100644
--- a/zircon/system/host/fidl/lib/parser.cpp
+++ b/zircon/system/host/fidl/lib/parser.cpp
@@ -69,12 +69,12 @@
 }
 
 bool Parser::LookupHandleSubtype(const raw::Identifier* identifier,
-                                 std::unique_ptr<types::HandleSubtype>* out_handle_subtype) {
+                                 std::optional<types::HandleSubtype>* out_handle_subtype) {
     auto lookup = handle_subtype_table_.find(identifier->location().data());
     if (lookup == handle_subtype_table_.end()) {
         return false;
     }
-    *out_handle_subtype = std::make_unique<types::HandleSubtype>(lookup->second);
+    *out_handle_subtype = lookup->second;
     return true;
 }
 
@@ -354,7 +354,7 @@
     if (!Ok())
         return Fail();
     std::unique_ptr<raw::TypeConstructor> maybe_arg_type_ctor;
-    std::unique_ptr<types::HandleSubtype> maybe_handle_subtype;
+    std::optional<types::HandleSubtype> handle_subtype;
     if (MaybeConsumeToken(OfKind(Token::Kind::kLeftAngle))) {
         if (!Ok())
             return Fail();
@@ -364,7 +364,7 @@
             auto identifier = ParseIdentifier(true);
             if (!Ok())
                 return Fail();
-            if (!LookupHandleSubtype(identifier.get(), &maybe_handle_subtype))
+            if (!LookupHandleSubtype(identifier.get(), &handle_subtype))
                 return Fail();
         } else {
             maybe_arg_type_ctor = ParseTypeConstructor();
@@ -394,7 +394,7 @@
         scope.GetSourceElement(),
         std::move(identifier),
         std::move(maybe_arg_type_ctor),
-        std::move(maybe_handle_subtype),
+        handle_subtype,
         std::move(maybe_size),
         nullability);
 }
diff --git a/zircon/system/host/fidl/lib/raw_ast.cpp b/zircon/system/host/fidl/lib/raw_ast.cpp
index 63de402..2a69930 100644
--- a/zircon/system/host/fidl/lib/raw_ast.cpp
+++ b/zircon/system/host/fidl/lib/raw_ast.cpp
@@ -81,8 +81,8 @@
     visitor->OnCompoundIdentifier(identifier);
     if (maybe_arg_type_ctor != nullptr)
         visitor->OnTypeConstructor(maybe_arg_type_ctor);
-    if (maybe_handle_subtype != nullptr)
-        visitor->OnHandleSubtype(*maybe_handle_subtype);
+    if (handle_subtype.has_value())
+        visitor->OnHandleSubtype(handle_subtype.value());
     if (maybe_size != nullptr)
         visitor->OnConstant(maybe_size);
     visitor->OnNullability(nullability);
diff --git a/zircon/system/utest/fidl-compiler/types_tests.cpp b/zircon/system/utest/fidl-compiler/types_tests.cpp
index 2b0dd3e..485f018 100644
--- a/zircon/system/utest/fidl-compiler/types_tests.cpp
+++ b/zircon/system/utest/fidl-compiler/types_tests.cpp
@@ -18,7 +18,7 @@
         ASSERT_TRUE(typespace.Create(                                  \
             the_type_name,                                             \
             nullptr /* maybe_arg_type */,                              \
-            nullptr /* maybe_handle_subtype */,                        \
+            std::optional<types::HandleSubtype>(),                     \
             nullptr /* maybe_size */,                                  \
             types::Nullability::kNonnullable,                          \
             &the_type));                                               \