Default values for fixed-size arrays

AidlConstantValue::ValueString() works with nested array values for
fixed-size arrays.

Bug: 207087196
Test: aidl_unittests
Change-Id: I420c23c791edd7578ebe76b5809be08c6b194e30
diff --git a/aidl_const_expressions.cpp b/aidl_const_expressions.cpp
index 6c4b177..14afa12 100644
--- a/aidl_const_expressions.cpp
+++ b/aidl_const_expressions.cpp
@@ -279,6 +279,11 @@
 
 bool AidlBinaryConstExpression::AreCompatibleTypes(Type t1, Type t2) {
   switch (t1) {
+    case Type::ARRAY:
+      if (t2 == Type::ARRAY) {
+        return true;
+      }
+      break;
     case Type::STRING:
       if (t2 == Type::STRING) {
         return true;
@@ -329,6 +334,12 @@
 AidlConstantValue* AidlConstantValue::Default(const AidlTypeSpecifier& specifier) {
   AidlLocation location = specifier.GetLocation();
 
+  // Initialize non-nullable fixed-size arrays with {}("empty list").
+  // Each backend will handle it differently. For example, in Rust, it can be mapped to
+  // "Default::default()".
+  if (specifier.IsFixedSizeArray() && !specifier.IsNullable()) {
+    return Array(location, std::make_unique<std::vector<std::unique_ptr<AidlConstantValue>>>());
+  }
   // allocation of int[0] is a bit wasteful in Java
   if (specifier.IsArray()) {
     return nullptr;
@@ -582,6 +593,16 @@
         err = -1;
         break;
       }
+      if (type.IsFixedSizeArray()) {
+        auto size =
+            std::get<FixedSizeArray>(type.GetArray()).dimensions.front()->EvaluatedValue<int32_t>();
+        if (values_.size() > static_cast<size_t>(size)) {
+          AIDL_ERROR(this) << "Expected an array of " << size << " elements, but found one with "
+                           << values_.size() << " elements";
+          err = -1;
+          break;
+        }
+      }
       return decorator(type, value_strings);
     }
     case Type::FLOATING: {
diff --git a/aidl_language.cpp b/aidl_language.cpp
index d09c7c9..426fad8 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -551,10 +551,18 @@
   // Declaring array of generic type cannot happen, it is grammar error.
   AIDL_FATAL_IF(IsGeneric(), this);
 
-  ArrayType array_type = std::move(array_.value());
-  array_ = std::nullopt;
-  func(*this);
-  array_ = std::move(array_type);
+  if (IsFixedSizeArray() && std::get<FixedSizeArray>(*array_).dimensions.size() > 1) {
+    auto& dimensions = std::get<FixedSizeArray>(*array_).dimensions;
+    auto dim = std::move(dimensions.front());
+    dimensions.erase(dimensions.begin());
+    func(*this);
+    dimensions.insert(dimensions.begin(), std::move(dim));
+  } else {
+    ArrayType array_type = std::move(array_.value());
+    array_ = std::nullopt;
+    func(*this);
+    array_ = std::move(array_type);
+  }
 }
 
 bool AidlTypeSpecifier::MakeArray(ArrayType array_type) {
diff --git a/aidl_language.h b/aidl_language.h
index 266f473..1eb2737 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -401,7 +401,8 @@
                     vector<unique_ptr<AidlTypeSpecifier>>* type_params, const Comments& comments);
   virtual ~AidlTypeSpecifier() = default;
 
-  // View of this type which is not an array.
+  // View of this type which has one-less dimension(s).
+  // e.g.) T[] => T, T[N][M] => T[M]
   void ViewAsArrayBase(std::function<void(const AidlTypeSpecifier&)> func) const;
 
   // Returns the full-qualified name of the base type.
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index cb8fcf2..b36efcd 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -4475,6 +4475,46 @@
               testing::HasSubstr("Annotations for type arguments are not supported."));
 }
 
+TEST_F(AidlTest, DefaultShouldMatchWithFixedSizeArray) {
+  io_delegate_.SetFileContents("a/Bar.aidl",
+                               "package a;\n"
+                               "parcelable Bar {\n"
+                               "  int[2][3] a = {{1,2,3}, {4,5,6}};\n"
+                               "}");
+
+  Options options = Options::From("aidl a/Bar.aidl -I . -o out --lang=java");
+  CaptureStderr();
+  EXPECT_TRUE(compile_aidl(options, io_delegate_));
+  EXPECT_EQ("", GetCapturedStderr());
+}
+
+TEST_F(AidlTest, FixedSizeArrayWithWrongTypeDefaultValue) {
+  io_delegate_.SetFileContents("a/Bar.aidl",
+                               "package a;\n"
+                               "parcelable Bar {\n"
+                               "  int[2][3] a = {{\"1\",\"2\",\"3\"}, {4,5,6}};\n"
+                               "}");
+
+  Options options = Options::From("aidl a/Bar.aidl -I . -o out --lang=java");
+  CaptureStderr();
+  EXPECT_FALSE(compile_aidl(options, io_delegate_));
+  EXPECT_THAT(GetCapturedStderr(), HasSubstr("Invalid type specifier for a literal string: int"));
+}
+
+TEST_F(AidlTest, FixedSizeArrayWithWrongSizeDefaultValue) {
+  io_delegate_.SetFileContents("a/Bar.aidl",
+                               "package a;\n"
+                               "parcelable Bar {\n"
+                               "  int[2][3] a = {{1,2,3,4}, {4,5,6}};\n"
+                               "}");
+
+  Options options = Options::From("aidl a/Bar.aidl -I . -o out --lang=java");
+  CaptureStderr();
+  EXPECT_FALSE(compile_aidl(options, io_delegate_));
+  EXPECT_THAT(GetCapturedStderr(),
+              HasSubstr("Expected an array of 3 elements, but found one with 4 elements"));
+}
+
 struct GenericAidlTest : ::testing::Test {
   FakeIoDelegate io_delegate_;
   void Compile(string cmd) {