Version 2.16.0-31.0.dev

Merge commit '00ea62f71368306b01f593d055af011bc0d57f1b' into 'dev'
diff --git a/pkg/vm/lib/transformations/ffi/common.dart b/pkg/vm/lib/transformations/ffi/common.dart
index 4d242a7..7627a59 100644
--- a/pkg/vm/lib/transformations/ffi/common.dart
+++ b/pkg/vm/lib/transformations/ffi/common.dart
@@ -725,10 +725,16 @@
   /// Returns the single element type nested type argument of `Array`.
   ///
   /// `Array<Array<Array<Int8>>>` -> `Int8`.
+  ///
+  /// `Array<Array<Array<Unknown>>>` -> [InvalidType].
   DartType arraySingleElementType(DartType dartType) {
     InterfaceType elementType = dartType as InterfaceType;
     while (elementType.classNode == arrayClass) {
-      elementType = elementType.typeArguments[0] as InterfaceType;
+      final elementTypeAny = elementType.typeArguments[0];
+      if (elementTypeAny is InvalidType) {
+        return elementTypeAny;
+      }
+      elementType = elementTypeAny as InterfaceType;
     }
     return elementType;
   }
@@ -736,11 +742,14 @@
   /// Returns the number of dimensions of `Array`.
   ///
   /// `Array<Array<Array<Int8>>>` -> 3.
+  ///
+  /// `Array<Array<Array<Unknown>>>` -> 3.
   int arrayDimensions(DartType dartType) {
-    InterfaceType elementType = dartType as InterfaceType;
+    DartType elementType = dartType;
     int dimensions = 0;
-    while (elementType.classNode == arrayClass) {
-      elementType = elementType.typeArguments[0] as InterfaceType;
+    while (
+        elementType is InterfaceType && elementType.classNode == arrayClass) {
+      elementType = elementType.typeArguments[0];
       dimensions++;
     }
     return dimensions;
diff --git a/pkg/vm/lib/transformations/ffi/definitions.dart b/pkg/vm/lib/transformations/ffi/definitions.dart
index f87519e..c11b710 100644
--- a/pkg/vm/lib/transformations/ffi/definitions.dart
+++ b/pkg/vm/lib/transformations/ffi/definitions.dart
@@ -146,8 +146,9 @@
         final sizeAnnotations = _getArraySizeAnnotations(f);
         if (sizeAnnotations.length == 1) {
           final singleElementType = arraySingleElementType(type);
-          if (isCompoundSubtype(singleElementType)) {
-            final clazz = (singleElementType as InterfaceType).classNode;
+          if (singleElementType is InterfaceType &&
+              isCompoundSubtype(singleElementType)) {
+            final clazz = singleElementType.classNode;
             dependencies.add(clazz);
           }
         }
@@ -403,24 +404,31 @@
           final sizeAnnotations = _getArraySizeAnnotations(f);
           if (sizeAnnotations.length == 1) {
             final singleElementType = arraySingleElementType(type);
-            if (isCompoundSubtype(singleElementType)) {
-              final clazz = (singleElementType as InterfaceType).classNode;
-              _checkPacking(node, packing, clazz, f);
-            }
-            final dimensions = sizeAnnotations.single;
-            if (arrayDimensions(type) != dimensions.length) {
-              diagnosticReporter.report(
-                  templateFfiSizeAnnotationDimensions
-                      .withArguments(f.name.text),
-                  f.fileOffset,
-                  f.name.text.length,
-                  f.fileUri);
-            }
-            for (var dimension in dimensions) {
-              if (dimension < 0) {
-                diagnosticReporter.report(messageNonPositiveArrayDimensions,
-                    f.fileOffset, f.name.text.length, f.fileUri);
-                success = false;
+            if (singleElementType is! InterfaceType) {
+              assert(singleElementType is InvalidType);
+              // This class is invalid, but continue reporting other errors on it.
+              // An error on the type will already have been reported.
+              success = false;
+            } else {
+              if (isCompoundSubtype(singleElementType)) {
+                final clazz = singleElementType.classNode;
+                _checkPacking(node, packing, clazz, f);
+              }
+              final dimensions = sizeAnnotations.single;
+              if (arrayDimensions(type) != dimensions.length) {
+                diagnosticReporter.report(
+                    templateFfiSizeAnnotationDimensions
+                        .withArguments(f.name.text),
+                    f.fileOffset,
+                    f.name.text.length,
+                    f.fileUri);
+              }
+              for (var dimension in dimensions) {
+                if (dimension < 0) {
+                  diagnosticReporter.report(messageNonPositiveArrayDimensions,
+                      f.fileOffset, f.name.text.length, f.fileUri);
+                  success = false;
+                }
               }
             }
           } else {
@@ -568,8 +576,15 @@
         if (sizeAnnotations.length == 1) {
           final arrayDimensions = sizeAnnotations.single;
           if (this.arrayDimensions(dartType) == arrayDimensions.length) {
-            type = NativeTypeCfe(this, dartType,
-                compoundCache: compoundCache, arrayDimensions: arrayDimensions);
+            final elementType = arraySingleElementType(dartType);
+            if (elementType is! InterfaceType) {
+              assert(elementType is InvalidType);
+              type = InvalidNativeTypeCfe("Invalid element type.");
+            } else {
+              type = NativeTypeCfe(this, dartType,
+                  compoundCache: compoundCache,
+                  arrayDimensions: arrayDimensions);
+            }
           } else {
             type = InvalidNativeTypeCfe("Invalid array dimensions.");
           }
diff --git a/tests/ffi/regress_47673_2_test.dart b/tests/ffi/regress_47673_2_test.dart
new file mode 100644
index 0000000..9048521
--- /dev/null
+++ b/tests/ffi/regress_47673_2_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+
+class A extends Struct {
+  @Array.multi([16])
+  external Array<Int8> a;
+
+  // This should not crash the FFI transform.
+  @Array.multi([16]) //# 1: compile-time error
+  external Array<Unknown> b; //# 1: compile-time error
+}
+
+main() {}
diff --git a/tests/ffi/regress_47673_test.dart b/tests/ffi/regress_47673_test.dart
new file mode 100644
index 0000000..b372e09
--- /dev/null
+++ b/tests/ffi/regress_47673_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+
+typedef T = Int64;
+
+class A extends Struct {
+  @Array.multi([16])
+  external Array<T> b;
+}
+
+main() {}
diff --git a/tests/ffi_2/regress_47673_2_test.dart b/tests/ffi_2/regress_47673_2_test.dart
new file mode 100644
index 0000000..2258af8
--- /dev/null
+++ b/tests/ffi_2/regress_47673_2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+// @dart=2.9
+
+import 'dart:ffi';
+
+class A extends Struct {
+  @Array.multi([16])
+  Array<Int8> a;
+
+  // This should not crash the FFI transform.
+  @Array.multi([16]) //# 1: compile-time error
+  Array<Unknown> b; //# 1: compile-time error
+}
+
+main() {}
diff --git a/tests/ffi_2/regress_47673_test.dart b/tests/ffi_2/regress_47673_test.dart
new file mode 100644
index 0000000..9044ed5
--- /dev/null
+++ b/tests/ffi_2/regress_47673_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+// @dart=2.9
+
+import 'dart:ffi';
+
+typedef T = Int64; //# 1: compile-time error
+
+class A extends Struct {
+  @Array.multi([16])
+  Array<Int8> a;
+
+  // In language version 2.12 we do not support non-function typedefs.
+  // This should not crash the FFI transform.
+  @Array.multi([16]) //# 1: compile-time error
+  Array<T> b; //# 1: compile-time error
+}
+
+main() {}
diff --git a/tools/VERSION b/tools/VERSION
index 59d4a27..9203c16 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 30
+PRERELEASE 31
 PRERELEASE_PATCH 0
\ No newline at end of file