Version 2.14.0-202.0.dev

Merge commit 'b11e0de9f7515e4a8ff09abeb9d24340f73829ed' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 8ff653b..15cf6ef 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -94,6 +94,8 @@
       _addSuggestion(Keyword.ASYNC);
       _addSuggestion2(ASYNC_STAR);
       _addSuggestion2(SYNC_STAR);
+    } else if (identical(entity, node.type)) {
+      _addSuggestion(Keyword.DYNAMIC);
     }
   }
 
diff --git a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
index 939baea..3b762f6 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
@@ -10,6 +10,7 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ArgumentListCompletionTest);
+    defineReflectiveTests(AsExpressionTest);
     defineReflectiveTests(AssertStatementTest);
     defineReflectiveTests(ConstructorCompletionTest);
     defineReflectiveTests(ExpressionFunctionBodyTest);
@@ -54,6 +55,33 @@
     await getSuggestions();
     assertHasCompletion('g');
   }
+
+  Future<void> test_privateStaticField() async {
+    addTestFile('''
+extension on int {
+  static int _x = 0;
+
+  void g(String s) {
+    s.substring(^);
+  }
+}
+''');
+    await getSuggestions();
+    assertHasCompletion('_x');
+  }
+}
+
+@reflectiveTest
+class AsExpressionTest extends CompletionTestCase {
+  Future<void> test_type_dynamic() async {
+    addTestFile('''
+void f(Object o) {
+  var x = o as ^;
+}
+''');
+    await getSuggestions();
+    assertHasCompletion('dynamic');
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
index a7ea9aa..8181406 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
@@ -93,7 +93,7 @@
 
   @override
   void visitClassDeclaration(ClassDeclaration node) {
-    _visitClassOrMixinMembers(node);
+    _visitClassOrMixinMembers(node.members);
     visitNode(node);
   }
 
@@ -109,6 +109,12 @@
   }
 
   @override
+  void visitExtensionDeclaration(ExtensionDeclaration node) {
+    _visitClassOrMixinMembers(node.members);
+    visitNode(node);
+  }
+
+  @override
   void visitForElement(ForElement node) {
     var forLoopParts = node.forLoopParts;
     if (forLoopParts is ForEachPartsWithDeclaration) {
@@ -179,7 +185,7 @@
 
   @override
   void visitMixinDeclaration(MixinDeclaration node) {
-    _visitClassOrMixinMembers(node);
+    _visitClassOrMixinMembers(node.members);
     visitNode(node);
   }
 
@@ -211,8 +217,8 @@
     visitNode(node);
   }
 
-  void _visitClassOrMixinMembers(ClassOrMixinDeclaration node) {
-    for (var member in node.members) {
+  void _visitClassOrMixinMembers(List<ClassMember> members) {
+    for (var member in members) {
       if (member is FieldDeclaration) {
         member.fields.variables.forEach((VariableDeclaration varDecl) {
           declaredField(member, varDecl);
diff --git a/runtime/bin/ffi_test/clobber_arm64.S b/runtime/bin/ffi_test/clobber_arm64.S
index 111c8fa..38105d5 100644
--- a/runtime/bin/ffi_test/clobber_arm64.S
+++ b/runtime/bin/ffi_test/clobber_arm64.S
@@ -1,7 +1,13 @@
 .text
 
-.global ClobberAndCall
+#if defined(__linux__) || defined(__FreeBSD__) /* HOST_OS_LINUX */
+.globl ClobberAndCall
+.type ClobberAndCall, @function
 ClobberAndCall:
+#else /* HOST_OS_MACOS */
+.globl _ClobberAndCall
+_ClobberAndCall:
+#endif
 
 /* Save link register register and thread register. Keep stack aligned to 16 bytes. */
 stp lr, x26, [sp, #-16]!
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 3cf56b0..1784af3 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -170,8 +170,7 @@
             << static_cast<int>(d) << ", " << static_cast<int>(e) << ", "
             << static_cast<int>(f) << ", " << static_cast<int>(g) << ", "
             << static_cast<int>(h) << ", " << static_cast<int>(i) << ", "
-            << static_cast<int>(j) << ", "
-            << ")\n";
+            << static_cast<int>(j) << ")\n";
   return (a == 0xff && b == 0xff && c == 0xff && d == 0xff && e == 0xff &&
           f == 0xff && g == 0xff && h == 0xff && i == 0xff && j == 0xff)
              ? 1
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
index 8a23e24..1e88249 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -4231,7 +4231,7 @@
 // Used for testing structs and unions by value.
 // Struct with mis-aligned member.
 // Tests backfilling of CPU and FPU registers.
-DART_EXPORT double PassStruct9BytesPackedMixedx10DoubleInt32(
+DART_EXPORT double PassStruct9BytesPackedMixedx10DoubleInt32x2(
     Struct9BytesPackedMixed a0,
     Struct9BytesPackedMixed a1,
     Struct9BytesPackedMixed a2,
@@ -4243,8 +4243,9 @@
     Struct9BytesPackedMixed a8,
     Struct9BytesPackedMixed a9,
     double a10,
-    int32_t a11) {
-  std::cout << "PassStruct9BytesPackedMixedx10DoubleInt32"
+    int32_t a11,
+    int32_t a12) {
+  std::cout << "PassStruct9BytesPackedMixedx10DoubleInt32x2"
             << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
             << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
             << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
@@ -4255,7 +4256,7 @@
             << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
             << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
             << static_cast<int>(a9.a0) << ", " << a9.a1 << "), " << a10 << ", "
-            << a11 << ")"
+            << a11 << ", " << a12 << ")"
             << "\n";
 
   double result = 0;
@@ -4282,6 +4283,7 @@
   result += a9.a1;
   result += a10;
   result += a11;
+  result += a12;
 
   std::cout << "result = " << result << "\n";
 
@@ -11492,7 +11494,7 @@
 // Used for testing structs and unions by value.
 // Struct with mis-aligned member.
 // Tests backfilling of CPU and FPU registers.
-DART_EXPORT intptr_t TestPassStruct9BytesPackedMixedx10DoubleInt32(
+DART_EXPORT intptr_t TestPassStruct9BytesPackedMixedx10DoubleInt32x2(
     // NOLINTNEXTLINE(whitespace/parens)
     double (*f)(Struct9BytesPackedMixed a0,
                 Struct9BytesPackedMixed a1,
@@ -11505,7 +11507,8 @@
                 Struct9BytesPackedMixed a8,
                 Struct9BytesPackedMixed a9,
                 double a10,
-                int32_t a11)) {
+                int32_t a11,
+                int32_t a12)) {
   Struct9BytesPackedMixed a0;
   Struct9BytesPackedMixed a1;
   Struct9BytesPackedMixed a2;
@@ -11518,6 +11521,7 @@
   Struct9BytesPackedMixed a9;
   double a10;
   int32_t a11;
+  int32_t a12;
 
   a0.a0 = 1;
   a0.a1 = 2.0;
@@ -11541,8 +11545,9 @@
   a9.a1 = 20.0;
   a10 = -21.0;
   a11 = 22;
+  a12 = -23;
 
-  std::cout << "Calling TestPassStruct9BytesPackedMixedx10DoubleInt32("
+  std::cout << "Calling TestPassStruct9BytesPackedMixedx10DoubleInt32x2("
             << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
             << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
             << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
@@ -11553,26 +11558,26 @@
             << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
             << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
             << static_cast<int>(a9.a0) << ", " << a9.a1 << "), " << a10 << ", "
-            << a11 << ")"
+            << a11 << ", " << a12 << ")"
             << ")\n";
 
-  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   std::cout << "result = " << result << "\n";
 
-  CHECK_APPROX(211.0, result);
+  CHECK_APPROX(188.0, result);
 
   // Pass argument that will make the Dart callback throw.
   a0.a0 = 42;
 
-  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   CHECK_APPROX(0.0, result);
 
   // Pass argument that will make the Dart callback return null.
   a0.a0 = 84;
 
-  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   CHECK_APPROX(0.0, result);
 
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.cc b/runtime/vm/compiler/ffi/native_calling_convention.cc
index 8312871..8ed3646 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention.cc
@@ -383,6 +383,7 @@
         payload_type, container_type, CallingConventions::kStackPointerRegister,
         stack_height_in_bytes);
     stack_height_in_bytes += size;
+    align_stack(payload_type.AlignmentInBytesStack());
     return result;
   }
 
diff --git a/runtime/vm/compiler/ffi/native_calling_convention_test.cc b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
index e1fdfb0..1d1ae28 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention_test.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
@@ -494,6 +494,7 @@
 // See the *.expect in ./unit_tests for this behavior.
 UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_structPacked) {
   const auto& int8_type = *new (Z) NativePrimitiveType(kInt8);
+  const auto& int32_type = *new (Z) NativePrimitiveType(kInt32);
   const auto& double_type = *new (Z) NativePrimitiveType(kDouble);
 
   auto& member_types = *new (Z) NativeTypes(Z, 2);
@@ -504,13 +505,22 @@
   EXPECT_EQ(9, struct_type.SizeInBytes());
   EXPECT(struct_type.ContainsUnalignedMembers());
 
-  auto& arguments = *new (Z) NativeTypes(Z, 11);
+  auto& arguments = *new (Z) NativeTypes(Z, 13);
   arguments.Add(&struct_type);
   arguments.Add(&struct_type);
-  arguments.Add(&int8_type);    // Backfilling int registers.
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
+  arguments.Add(&struct_type);
   arguments.Add(&double_type);  // Backfilling float registers.
+  arguments.Add(&int32_type);   // Backfilling int registers.
+  arguments.Add(&int32_type);   // Backfilling int registers.
 
-  RunSignatureTest(Z, "structPacked", arguments, struct_type);
+  RunSignatureTest(Z, "structPacked", arguments, double_type);
 }
 
 // The union is only 5 bytes because it's members are packed.
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
index 0af60bd..9653167 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
@@ -1,6 +1,15 @@
 M(r0 int64, r1 int64) Struct(size: 9)
 M(r2 int64, r3 int64) Struct(size: 9)
-r4 int8
+M(r4 int64, r5 int64) Struct(size: 9)
+M(r6 int64, r7 int64) Struct(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
 v0 double
+S+96 int32
+S+104 int32
 =>
-M(r0 int64, r1 int64) Struct(size: 9)
+v0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
index 975b441..ef5848d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
@@ -1,6 +1,15 @@
 M(r0 int64, r1 int64) Struct(size: 9)
 M(r2 int64, r3 int64) Struct(size: 9)
-r4 int32[int8]
+M(r4 int64, r5 int64) Struct(size: 9)
+M(r6 int64, r7 int64) Struct(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
 v0 double
+S+96 int32
+S+100 int32
 =>
-M(r0 int64, r1 int64) Struct(size: 9)
+v0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
index 0af60bd..9653167 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
@@ -1,6 +1,15 @@
 M(r0 int64, r1 int64) Struct(size: 9)
 M(r2 int64, r3 int64) Struct(size: 9)
-r4 int8
+M(r4 int64, r5 int64) Struct(size: 9)
+M(r6 int64, r7 int64) Struct(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
 v0 double
+S+96 int32
+S+104 int32
 =>
-M(r0 int64, r1 int64) Struct(size: 9)
+v0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
index 0af60bd..ef5848d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
@@ -1,6 +1,15 @@
 M(r0 int64, r1 int64) Struct(size: 9)
 M(r2 int64, r3 int64) Struct(size: 9)
-r4 int8
+M(r4 int64, r5 int64) Struct(size: 9)
+M(r6 int64, r7 int64) Struct(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
 v0 double
+S+96 int32
+S+100 int32
 =>
-M(r0 int64, r1 int64) Struct(size: 9)
+v0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
index dedbb93..ec8c36b 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
@@ -1,6 +1,15 @@
-M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
-S+12 int32[int8]
-S+16 double
+M(r0 int32, r1 int32, r2 int32) Struct(size: 9)
+M(r3 int32, S+0 int32, S+4 int32) Struct(size: 9)
+M(S+8 int32, S+12 int32, S+16 int32) Struct(size: 9)
+M(S+20 int32, S+24 int32, S+28 int32) Struct(size: 9)
+M(S+32 int32, S+36 int32, S+40 int32) Struct(size: 9)
+M(S+44 int32, S+48 int32, S+52 int32) Struct(size: 9)
+M(S+56 int32, S+60 int32, S+64 int32) Struct(size: 9)
+M(S+68 int32, S+72 int32, S+76 int32) Struct(size: 9)
+M(S+80 int32, S+84 int32, S+88 int32) Struct(size: 9)
+M(S+92 int32, S+96 int32, S+100 int32) Struct(size: 9)
+S+104 double
+S+112 int32
+S+116 int32
 =>
-P(r0 uint32) Struct(size: 9)
+(r0, r1) int64[double]
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
index f362c98..78ee91b 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
@@ -1,6 +1,15 @@
-M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
-S+12 int32[int8]
+M(r0 int32, r1 int32, r2 int32) Struct(size: 9)
+M(r3 int32, S+0 int32, S+4 int32) Struct(size: 9)
+M(S+8 int32, S+12 int32, S+16 int32) Struct(size: 9)
+M(S+20 int32, S+24 int32, S+28 int32) Struct(size: 9)
+M(S+32 int32, S+36 int32, S+40 int32) Struct(size: 9)
+M(S+44 int32, S+48 int32, S+52 int32) Struct(size: 9)
+M(S+56 int32, S+60 int32, S+64 int32) Struct(size: 9)
+M(S+68 int32, S+72 int32, S+76 int32) Struct(size: 9)
+M(S+80 int32, S+84 int32, S+88 int32) Struct(size: 9)
+M(S+92 int32, S+96 int32, S+100 int32) Struct(size: 9)
 d0 double
+S+104 int32
+S+108 int32
 =>
-P(r0 uint32) Struct(size: 9)
+q0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
index f362c98..78ee91b 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
@@ -1,6 +1,15 @@
-M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
-S+12 int32[int8]
+M(r0 int32, r1 int32, r2 int32) Struct(size: 9)
+M(r3 int32, S+0 int32, S+4 int32) Struct(size: 9)
+M(S+8 int32, S+12 int32, S+16 int32) Struct(size: 9)
+M(S+20 int32, S+24 int32, S+28 int32) Struct(size: 9)
+M(S+32 int32, S+36 int32, S+40 int32) Struct(size: 9)
+M(S+44 int32, S+48 int32, S+52 int32) Struct(size: 9)
+M(S+56 int32, S+60 int32, S+64 int32) Struct(size: 9)
+M(S+68 int32, S+72 int32, S+76 int32) Struct(size: 9)
+M(S+80 int32, S+84 int32, S+88 int32) Struct(size: 9)
+M(S+92 int32, S+96 int32, S+100 int32) Struct(size: 9)
 d0 double
+S+104 int32
+S+108 int32
 =>
-P(r0 uint32) Struct(size: 9)
+q0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
index 8a22e1d..8540652 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
@@ -1,6 +1,15 @@
-S+4 Struct(size: 9)
-S+16 Struct(size: 9)
-S+28 int32[int8]
-S+32 double
+S+0 Struct(size: 9)
+S+12 Struct(size: 9)
+S+24 Struct(size: 9)
+S+36 Struct(size: 9)
+S+48 Struct(size: 9)
+S+60 Struct(size: 9)
+S+72 Struct(size: 9)
+S+84 Struct(size: 9)
+S+96 Struct(size: 9)
+S+108 Struct(size: 9)
+S+120 double
+S+128 int32
+S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
index 8a22e1d..8540652 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
@@ -1,6 +1,15 @@
-S+4 Struct(size: 9)
-S+16 Struct(size: 9)
-S+28 int32[int8]
-S+32 double
+S+0 Struct(size: 9)
+S+12 Struct(size: 9)
+S+24 Struct(size: 9)
+S+36 Struct(size: 9)
+S+48 Struct(size: 9)
+S+60 Struct(size: 9)
+S+72 Struct(size: 9)
+S+84 Struct(size: 9)
+S+96 Struct(size: 9)
+S+108 Struct(size: 9)
+S+120 double
+S+128 int32
+S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
index 8a22e1d..8540652 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
@@ -1,6 +1,15 @@
-S+4 Struct(size: 9)
-S+16 Struct(size: 9)
-S+28 int32[int8]
-S+32 double
+S+0 Struct(size: 9)
+S+12 Struct(size: 9)
+S+24 Struct(size: 9)
+S+36 Struct(size: 9)
+S+48 Struct(size: 9)
+S+60 Struct(size: 9)
+S+72 Struct(size: 9)
+S+84 Struct(size: 9)
+S+96 Struct(size: 9)
+S+108 Struct(size: 9)
+S+120 double
+S+128 int32
+S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
index 5753935..404a10f 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
@@ -1,6 +1,15 @@
 S+0 Struct(size: 9)
 S+16 Struct(size: 9)
-rsi int32[int8]
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
+S+96 Struct(size: 9)
+S+112 Struct(size: 9)
+S+128 Struct(size: 9)
+S+144 Struct(size: 9)
 xmm0 double
+rdi int32
+rsi int32
 =>
-P(rdi int64, ret:rax int64) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
index 5753935..404a10f 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
@@ -1,6 +1,15 @@
 S+0 Struct(size: 9)
 S+16 Struct(size: 9)
-rsi int32[int8]
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
+S+96 Struct(size: 9)
+S+112 Struct(size: 9)
+S+128 Struct(size: 9)
+S+144 Struct(size: 9)
 xmm0 double
+rdi int32
+rsi int32
 =>
-P(rdi int64, ret:rax int64) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
index 5753935..404a10f 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
@@ -1,6 +1,15 @@
 S+0 Struct(size: 9)
 S+16 Struct(size: 9)
-rsi int32[int8]
+S+32 Struct(size: 9)
+S+48 Struct(size: 9)
+S+64 Struct(size: 9)
+S+80 Struct(size: 9)
+S+96 Struct(size: 9)
+S+112 Struct(size: 9)
+S+128 Struct(size: 9)
+S+144 Struct(size: 9)
 xmm0 double
+rdi int32
+rsi int32
 =>
-P(rdi int64, ret:rax int64) Struct(size: 9)
+xmm0 double
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
index 3311a61..21374d9 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
@@ -1,6 +1,15 @@
+P(rcx int64) Struct(size: 9)
 P(rdx int64) Struct(size: 9)
 P(r8 int64) Struct(size: 9)
-r9 int8
-S+0 double
+P(r9 int64) Struct(size: 9)
+P(S+0 int64) Struct(size: 9)
+P(S+8 int64) Struct(size: 9)
+P(S+16 int64) Struct(size: 9)
+P(S+24 int64) Struct(size: 9)
+P(S+32 int64) Struct(size: 9)
+P(S+40 int64) Struct(size: 9)
+S+48 double
+S+56 int32
+S+64 int32
 =>
-P(rcx int64, ret:rax int64) Struct(size: 9)
+xmm0 double
diff --git a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
index d13cf55..f843c7c 100644
--- a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
@@ -295,10 +295,10 @@
           passStruct8BytesPackedIntx10, 0),
       passStruct8BytesPackedIntx10AfterCallback),
   CallbackTest.withCheck(
-      "PassStruct9BytesPackedMixedx10DoubleInt32",
-      Pointer.fromFunction<PassStruct9BytesPackedMixedx10DoubleInt32Type>(
-          passStruct9BytesPackedMixedx10DoubleInt32, 0.0),
-      passStruct9BytesPackedMixedx10DoubleInt32AfterCallback),
+      "PassStruct9BytesPackedMixedx10DoubleInt32x2",
+      Pointer.fromFunction<PassStruct9BytesPackedMixedx10DoubleInt32x2Type>(
+          passStruct9BytesPackedMixedx10DoubleInt32x2, 0.0),
+      passStruct9BytesPackedMixedx10DoubleInt32x2AfterCallback),
   CallbackTest.withCheck(
       "PassStruct5BytesPackedMixed",
       Pointer.fromFunction<PassStruct5BytesPackedMixedType>(
@@ -6545,7 +6545,7 @@
   Expect.equals(1275, result);
 }
 
-typedef PassStruct9BytesPackedMixedx10DoubleInt32Type = Double Function(
+typedef PassStruct9BytesPackedMixedx10DoubleInt32x2Type = Double Function(
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
@@ -6557,69 +6557,72 @@
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
     Double,
+    Int32,
     Int32);
 
 // Global variables to be able to test inputs after callback returned.
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a0 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a0 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a1 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a1 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a2 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a2 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a3 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a3 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a4 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a4 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a5 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a5 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a6 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a6 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a7 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a7 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a8 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a8 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a9 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a9 =
     Struct9BytesPackedMixed();
-double passStruct9BytesPackedMixedx10DoubleInt32_a10 = 0.0;
-int passStruct9BytesPackedMixedx10DoubleInt32_a11 = 0;
+double passStruct9BytesPackedMixedx10DoubleInt32x2_a10 = 0.0;
+int passStruct9BytesPackedMixedx10DoubleInt32x2_a11 = 0;
+int passStruct9BytesPackedMixedx10DoubleInt32x2_a12 = 0;
 
 // Result variable also global, so we can delete it after the callback.
-double passStruct9BytesPackedMixedx10DoubleInt32Result = 0.0;
+double passStruct9BytesPackedMixedx10DoubleInt32x2Result = 0.0;
 
-double passStruct9BytesPackedMixedx10DoubleInt32CalculateResult() {
+double passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult() {
   double result = 0;
 
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a0.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a0.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a1.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a1.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a2.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a2.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a3.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a3.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a4.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a4.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a5.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a5.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a6.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a6.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a7.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a7.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a8.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a8.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a9.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a9.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a10;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a11;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a0.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a0.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a1.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a1.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a2.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a2.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a3.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a3.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a4.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a4.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a5.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a5.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a6.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a6.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a7.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a7.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a8.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a8.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a9.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a9.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a10;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a11;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a12;
 
-  passStruct9BytesPackedMixedx10DoubleInt32Result = result;
+  passStruct9BytesPackedMixedx10DoubleInt32x2Result = result;
 
   return result;
 }
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-double passStruct9BytesPackedMixedx10DoubleInt32(
+double passStruct9BytesPackedMixedx10DoubleInt32x2(
     Struct9BytesPackedMixed a0,
     Struct9BytesPackedMixed a1,
     Struct9BytesPackedMixed a2,
@@ -6631,9 +6634,10 @@
     Struct9BytesPackedMixed a8,
     Struct9BytesPackedMixed a9,
     double a10,
-    int a11) {
+    int a11,
+    int a12) {
   print(
-      "passStruct9BytesPackedMixedx10DoubleInt32(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11})");
+      "passStruct9BytesPackedMixedx10DoubleInt32x2(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12})");
 
   // In legacy mode, possibly return null.
 
@@ -6641,35 +6645,36 @@
   if (a0.a0 == 42 || a0.a0 == 84) {
     print("throwing!");
     throw Exception(
-        "PassStruct9BytesPackedMixedx10DoubleInt32 throwing on purpose!");
+        "PassStruct9BytesPackedMixedx10DoubleInt32x2 throwing on purpose!");
   }
 
-  passStruct9BytesPackedMixedx10DoubleInt32_a0 = a0;
-  passStruct9BytesPackedMixedx10DoubleInt32_a1 = a1;
-  passStruct9BytesPackedMixedx10DoubleInt32_a2 = a2;
-  passStruct9BytesPackedMixedx10DoubleInt32_a3 = a3;
-  passStruct9BytesPackedMixedx10DoubleInt32_a4 = a4;
-  passStruct9BytesPackedMixedx10DoubleInt32_a5 = a5;
-  passStruct9BytesPackedMixedx10DoubleInt32_a6 = a6;
-  passStruct9BytesPackedMixedx10DoubleInt32_a7 = a7;
-  passStruct9BytesPackedMixedx10DoubleInt32_a8 = a8;
-  passStruct9BytesPackedMixedx10DoubleInt32_a9 = a9;
-  passStruct9BytesPackedMixedx10DoubleInt32_a10 = a10;
-  passStruct9BytesPackedMixedx10DoubleInt32_a11 = a11;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a0 = a0;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a1 = a1;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a2 = a2;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a3 = a3;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a4 = a4;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a5 = a5;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a6 = a6;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a7 = a7;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a8 = a8;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a9 = a9;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a10 = a10;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a11 = a11;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a12 = a12;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32CalculateResult();
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult();
 
   print("result = $result");
 
   return result;
 }
 
-void passStruct9BytesPackedMixedx10DoubleInt32AfterCallback() {
-  final result = passStruct9BytesPackedMixedx10DoubleInt32CalculateResult();
+void passStruct9BytesPackedMixedx10DoubleInt32x2AfterCallback() {
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult();
 
   print("after callback result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 }
 
 typedef PassStruct5BytesPackedMixedType = Double Function(
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index 6c970e1..9504081 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -72,7 +72,7 @@
     testPassUint8Struct4BytesInlineArrayMultiDimensionalIn();
     testPassStruct3BytesPackedIntx10();
     testPassStruct8BytesPackedIntx10();
-    testPassStruct9BytesPackedMixedx10DoubleInt32();
+    testPassStruct9BytesPackedMixedx10DoubleInt32x2();
     testPassStruct5BytesPackedMixed();
     testPassStructNestedAlignmentStruct5BytesPackedMixed();
     testPassStruct6BytesInlineArrayInt();
@@ -185,7 +185,7 @@
     testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf();
     testPassStruct3BytesPackedIntx10Leaf();
     testPassStruct8BytesPackedIntx10Leaf();
-    testPassStruct9BytesPackedMixedx10DoubleInt32Leaf();
+    testPassStruct9BytesPackedMixedx10DoubleInt32x2Leaf();
     testPassStruct5BytesPackedMixedLeaf();
     testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf();
     testPassStruct6BytesInlineArrayIntLeaf();
@@ -5892,7 +5892,7 @@
   calloc.free(a9Pointer);
 }
 
-final passStruct9BytesPackedMixedx10DoubleInt32 =
+final passStruct9BytesPackedMixedx10DoubleInt32x2 =
     ffiTestFunctions.lookupFunction<
         Double Function(
             Struct9BytesPackedMixed,
@@ -5906,6 +5906,7 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             Double,
+            Int32,
             Int32),
         double Function(
             Struct9BytesPackedMixed,
@@ -5919,11 +5920,12 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             double,
-            int)>("PassStruct9BytesPackedMixedx10DoubleInt32");
+            int,
+            int)>("PassStruct9BytesPackedMixedx10DoubleInt32x2");
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-void testPassStruct9BytesPackedMixedx10DoubleInt32() {
+void testPassStruct9BytesPackedMixedx10DoubleInt32x2() {
   final a0Pointer = calloc<Struct9BytesPackedMixed>();
   final Struct9BytesPackedMixed a0 = a0Pointer.ref;
   final a1Pointer = calloc<Struct9BytesPackedMixed>();
@@ -5946,6 +5948,7 @@
   final Struct9BytesPackedMixed a9 = a9Pointer.ref;
   double a10;
   int a11;
+  int a12;
 
   a0.a0 = 1;
   a0.a1 = 2.0;
@@ -5969,13 +5972,14 @@
   a9.a1 = 20.0;
   a10 = -21.0;
   a11 = 22;
+  a12 = -23;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32(
-      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   print("result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 
   calloc.free(a0Pointer);
   calloc.free(a1Pointer);
@@ -13390,7 +13394,7 @@
   calloc.free(a9Pointer);
 }
 
-final passStruct9BytesPackedMixedx10DoubleInt32Leaf =
+final passStruct9BytesPackedMixedx10DoubleInt32x2Leaf =
     ffiTestFunctions.lookupFunction<
         Double Function(
             Struct9BytesPackedMixed,
@@ -13404,6 +13408,7 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             Double,
+            Int32,
             Int32),
         double Function(
             Struct9BytesPackedMixed,
@@ -13417,11 +13422,12 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             double,
-            int)>("PassStruct9BytesPackedMixedx10DoubleInt32", isLeaf: true);
+            int,
+            int)>("PassStruct9BytesPackedMixedx10DoubleInt32x2", isLeaf: true);
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-void testPassStruct9BytesPackedMixedx10DoubleInt32Leaf() {
+void testPassStruct9BytesPackedMixedx10DoubleInt32x2Leaf() {
   final a0Pointer = calloc<Struct9BytesPackedMixed>();
   final Struct9BytesPackedMixed a0 = a0Pointer.ref;
   final a1Pointer = calloc<Struct9BytesPackedMixed>();
@@ -13444,6 +13450,7 @@
   final Struct9BytesPackedMixed a9 = a9Pointer.ref;
   double a10;
   int a11;
+  int a12;
 
   a0.a0 = 1;
   a0.a1 = 2.0;
@@ -13467,13 +13474,14 @@
   a9.a1 = 20.0;
   a10 = -21.0;
   a11 = 22;
+  a12 = -23;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32Leaf(
-      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2Leaf(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   print("result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 
   calloc.free(a0Pointer);
   calloc.free(a1Pointer);
diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart
index 07b5fd1..78c187f 100644
--- a/tests/ffi/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart
@@ -339,7 +339,7 @@
   FunctionType(List.filled(10, struct8bytesPacked), int64, """
 Struct with mis-aligned member."""),
   FunctionType(
-      [...List.filled(10, struct9bytesPacked), double_, int32],
+      [...List.filled(10, struct9bytesPacked), double_, int32, int32],
       double_,
       """
 Struct with mis-aligned member.
diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart
index c624d58..72f3585 100644
--- a/tests/ffi/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi/generator/structs_by_value_tests_generator.dart
@@ -856,7 +856,14 @@
 /// Some value between 0 and 127 (works in every native type).
 const returnNullValue = 84;
 
-const headerDartCallTest = """
+const dart2dot9 = '''
+// @dart = 2.9
+''';
+
+headerDartCallTest(bool nnbd) {
+  final dartVersion = nnbd ? '' : dart2dot9;
+
+  return """
 // Copyright (c) 2020, 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.
@@ -869,6 +876,8 @@
 // VMOptions=--use-slow-path
 // VMOptions=--use-slow-path --stacktrace-every=100
 
+$dartVersion
+
 import 'dart:ffi';
 
 import "package:expect/expect.dart";
@@ -878,11 +887,12 @@
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 """;
+}
 
 void writeDartCallTest() {
   for (bool nnbd in [true, false]) {
     final StringBuffer buffer = StringBuffer();
-    buffer.write(headerDartCallTest);
+    buffer.write(headerDartCallTest(nnbd));
 
     buffer.write("""
     void main() {
@@ -909,7 +919,10 @@
       .path;
 }
 
-const headerDartCallbackTest = """
+headerDartCallbackTest(bool nnbd) {
+  final dartVersion = nnbd ? '' : dart2dot9;
+
+  return """
 // Copyright (c) 2020, 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.
@@ -922,6 +935,8 @@
 // VMOptions=--use-slow-path
 // VMOptions=--use-slow-path --stacktrace-every=100
 
+$dartVersion
+
 import 'dart:ffi';
 
 import "package:expect/expect.dart";
@@ -942,11 +957,12 @@
 
 
 """;
+}
 
 void writeDartCallbackTest() {
   for (bool nnbd in [true, false]) {
     final StringBuffer buffer = StringBuffer();
-    buffer.write(headerDartCallbackTest);
+    buffer.write(headerDartCallbackTest(nnbd));
 
     buffer.write("""
   final testCases = [
diff --git a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
index 8ee7845..5eb0a63 100644
--- a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
@@ -297,10 +297,10 @@
           passStruct8BytesPackedIntx10, 0),
       passStruct8BytesPackedIntx10AfterCallback),
   CallbackTest.withCheck(
-      "PassStruct9BytesPackedMixedx10DoubleInt32",
-      Pointer.fromFunction<PassStruct9BytesPackedMixedx10DoubleInt32Type>(
-          passStruct9BytesPackedMixedx10DoubleInt32, 0.0),
-      passStruct9BytesPackedMixedx10DoubleInt32AfterCallback),
+      "PassStruct9BytesPackedMixedx10DoubleInt32x2",
+      Pointer.fromFunction<PassStruct9BytesPackedMixedx10DoubleInt32x2Type>(
+          passStruct9BytesPackedMixedx10DoubleInt32x2, 0.0),
+      passStruct9BytesPackedMixedx10DoubleInt32x2AfterCallback),
   CallbackTest.withCheck(
       "PassStruct5BytesPackedMixed",
       Pointer.fromFunction<PassStruct5BytesPackedMixedType>(
@@ -6755,7 +6755,7 @@
   Expect.equals(1275, result);
 }
 
-typedef PassStruct9BytesPackedMixedx10DoubleInt32Type = Double Function(
+typedef PassStruct9BytesPackedMixedx10DoubleInt32x2Type = Double Function(
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
@@ -6767,69 +6767,72 @@
     Struct9BytesPackedMixed,
     Struct9BytesPackedMixed,
     Double,
+    Int32,
     Int32);
 
 // Global variables to be able to test inputs after callback returned.
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a0 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a0 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a1 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a1 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a2 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a2 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a3 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a3 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a4 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a4 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a5 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a5 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a6 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a6 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a7 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a7 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a8 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a8 =
     Struct9BytesPackedMixed();
-Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32_a9 =
+Struct9BytesPackedMixed passStruct9BytesPackedMixedx10DoubleInt32x2_a9 =
     Struct9BytesPackedMixed();
-double passStruct9BytesPackedMixedx10DoubleInt32_a10 = 0.0;
-int passStruct9BytesPackedMixedx10DoubleInt32_a11 = 0;
+double passStruct9BytesPackedMixedx10DoubleInt32x2_a10 = 0.0;
+int passStruct9BytesPackedMixedx10DoubleInt32x2_a11 = 0;
+int passStruct9BytesPackedMixedx10DoubleInt32x2_a12 = 0;
 
 // Result variable also global, so we can delete it after the callback.
-double passStruct9BytesPackedMixedx10DoubleInt32Result = 0.0;
+double passStruct9BytesPackedMixedx10DoubleInt32x2Result = 0.0;
 
-double passStruct9BytesPackedMixedx10DoubleInt32CalculateResult() {
+double passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult() {
   double result = 0;
 
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a0.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a0.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a1.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a1.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a2.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a2.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a3.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a3.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a4.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a4.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a5.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a5.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a6.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a6.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a7.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a7.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a8.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a8.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a9.a0;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a9.a1;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a10;
-  result += passStruct9BytesPackedMixedx10DoubleInt32_a11;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a0.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a0.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a1.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a1.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a2.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a2.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a3.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a3.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a4.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a4.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a5.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a5.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a6.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a6.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a7.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a7.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a8.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a8.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a9.a0;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a9.a1;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a10;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a11;
+  result += passStruct9BytesPackedMixedx10DoubleInt32x2_a12;
 
-  passStruct9BytesPackedMixedx10DoubleInt32Result = result;
+  passStruct9BytesPackedMixedx10DoubleInt32x2Result = result;
 
   return result;
 }
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-double passStruct9BytesPackedMixedx10DoubleInt32(
+double passStruct9BytesPackedMixedx10DoubleInt32x2(
     Struct9BytesPackedMixed a0,
     Struct9BytesPackedMixed a1,
     Struct9BytesPackedMixed a2,
@@ -6841,9 +6844,10 @@
     Struct9BytesPackedMixed a8,
     Struct9BytesPackedMixed a9,
     double a10,
-    int a11) {
+    int a11,
+    int a12) {
   print(
-      "passStruct9BytesPackedMixedx10DoubleInt32(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11})");
+      "passStruct9BytesPackedMixedx10DoubleInt32x2(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12})");
 
   // In legacy mode, possibly return null.
   if (a0.a0 == 84) {
@@ -6855,35 +6859,36 @@
   if (a0.a0 == 42 || a0.a0 == 84) {
     print("throwing!");
     throw Exception(
-        "PassStruct9BytesPackedMixedx10DoubleInt32 throwing on purpose!");
+        "PassStruct9BytesPackedMixedx10DoubleInt32x2 throwing on purpose!");
   }
 
-  passStruct9BytesPackedMixedx10DoubleInt32_a0 = a0;
-  passStruct9BytesPackedMixedx10DoubleInt32_a1 = a1;
-  passStruct9BytesPackedMixedx10DoubleInt32_a2 = a2;
-  passStruct9BytesPackedMixedx10DoubleInt32_a3 = a3;
-  passStruct9BytesPackedMixedx10DoubleInt32_a4 = a4;
-  passStruct9BytesPackedMixedx10DoubleInt32_a5 = a5;
-  passStruct9BytesPackedMixedx10DoubleInt32_a6 = a6;
-  passStruct9BytesPackedMixedx10DoubleInt32_a7 = a7;
-  passStruct9BytesPackedMixedx10DoubleInt32_a8 = a8;
-  passStruct9BytesPackedMixedx10DoubleInt32_a9 = a9;
-  passStruct9BytesPackedMixedx10DoubleInt32_a10 = a10;
-  passStruct9BytesPackedMixedx10DoubleInt32_a11 = a11;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a0 = a0;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a1 = a1;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a2 = a2;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a3 = a3;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a4 = a4;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a5 = a5;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a6 = a6;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a7 = a7;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a8 = a8;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a9 = a9;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a10 = a10;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a11 = a11;
+  passStruct9BytesPackedMixedx10DoubleInt32x2_a12 = a12;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32CalculateResult();
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult();
 
   print("result = $result");
 
   return result;
 }
 
-void passStruct9BytesPackedMixedx10DoubleInt32AfterCallback() {
-  final result = passStruct9BytesPackedMixedx10DoubleInt32CalculateResult();
+void passStruct9BytesPackedMixedx10DoubleInt32x2AfterCallback() {
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2CalculateResult();
 
   print("after callback result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 }
 
 typedef PassStruct5BytesPackedMixedType = Double Function(
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
index b1e3f27..1de965c 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -74,7 +74,7 @@
     testPassUint8Struct4BytesInlineArrayMultiDimensionalIn();
     testPassStruct3BytesPackedIntx10();
     testPassStruct8BytesPackedIntx10();
-    testPassStruct9BytesPackedMixedx10DoubleInt32();
+    testPassStruct9BytesPackedMixedx10DoubleInt32x2();
     testPassStruct5BytesPackedMixed();
     testPassStructNestedAlignmentStruct5BytesPackedMixed();
     testPassStruct6BytesInlineArrayInt();
@@ -187,7 +187,7 @@
     testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf();
     testPassStruct3BytesPackedIntx10Leaf();
     testPassStruct8BytesPackedIntx10Leaf();
-    testPassStruct9BytesPackedMixedx10DoubleInt32Leaf();
+    testPassStruct9BytesPackedMixedx10DoubleInt32x2Leaf();
     testPassStruct5BytesPackedMixedLeaf();
     testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf();
     testPassStruct6BytesInlineArrayIntLeaf();
@@ -5894,7 +5894,7 @@
   calloc.free(a9Pointer);
 }
 
-final passStruct9BytesPackedMixedx10DoubleInt32 =
+final passStruct9BytesPackedMixedx10DoubleInt32x2 =
     ffiTestFunctions.lookupFunction<
         Double Function(
             Struct9BytesPackedMixed,
@@ -5908,6 +5908,7 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             Double,
+            Int32,
             Int32),
         double Function(
             Struct9BytesPackedMixed,
@@ -5921,11 +5922,12 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             double,
-            int)>("PassStruct9BytesPackedMixedx10DoubleInt32");
+            int,
+            int)>("PassStruct9BytesPackedMixedx10DoubleInt32x2");
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-void testPassStruct9BytesPackedMixedx10DoubleInt32() {
+void testPassStruct9BytesPackedMixedx10DoubleInt32x2() {
   final a0Pointer = calloc<Struct9BytesPackedMixed>();
   final Struct9BytesPackedMixed a0 = a0Pointer.ref;
   final a1Pointer = calloc<Struct9BytesPackedMixed>();
@@ -5948,6 +5950,7 @@
   final Struct9BytesPackedMixed a9 = a9Pointer.ref;
   double a10;
   int a11;
+  int a12;
 
   a0.a0 = 1;
   a0.a1 = 2.0;
@@ -5971,13 +5974,14 @@
   a9.a1 = 20.0;
   a10 = -21.0;
   a11 = 22;
+  a12 = -23;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32(
-      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   print("result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 
   calloc.free(a0Pointer);
   calloc.free(a1Pointer);
@@ -13392,7 +13396,7 @@
   calloc.free(a9Pointer);
 }
 
-final passStruct9BytesPackedMixedx10DoubleInt32Leaf =
+final passStruct9BytesPackedMixedx10DoubleInt32x2Leaf =
     ffiTestFunctions.lookupFunction<
         Double Function(
             Struct9BytesPackedMixed,
@@ -13406,6 +13410,7 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             Double,
+            Int32,
             Int32),
         double Function(
             Struct9BytesPackedMixed,
@@ -13419,11 +13424,12 @@
             Struct9BytesPackedMixed,
             Struct9BytesPackedMixed,
             double,
-            int)>("PassStruct9BytesPackedMixedx10DoubleInt32", isLeaf: true);
+            int,
+            int)>("PassStruct9BytesPackedMixedx10DoubleInt32x2", isLeaf: true);
 
 /// Struct with mis-aligned member.
 /// Tests backfilling of CPU and FPU registers.
-void testPassStruct9BytesPackedMixedx10DoubleInt32Leaf() {
+void testPassStruct9BytesPackedMixedx10DoubleInt32x2Leaf() {
   final a0Pointer = calloc<Struct9BytesPackedMixed>();
   final Struct9BytesPackedMixed a0 = a0Pointer.ref;
   final a1Pointer = calloc<Struct9BytesPackedMixed>();
@@ -13446,6 +13452,7 @@
   final Struct9BytesPackedMixed a9 = a9Pointer.ref;
   double a10;
   int a11;
+  int a12;
 
   a0.a0 = 1;
   a0.a1 = 2.0;
@@ -13469,13 +13476,14 @@
   a9.a1 = 20.0;
   a10 = -21.0;
   a11 = 22;
+  a12 = -23;
 
-  final result = passStruct9BytesPackedMixedx10DoubleInt32Leaf(
-      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+  final result = passStruct9BytesPackedMixedx10DoubleInt32x2Leaf(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 
   print("result = $result");
 
-  Expect.approxEquals(211.0, result);
+  Expect.approxEquals(188.0, result);
 
   calloc.free(a0Pointer);
   calloc.free(a1Pointer);
diff --git a/tests/ffi_2/generator/c_types.dart b/tests/ffi_2/generator/c_types.dart
deleted file mode 100644
index edd670c..0000000
--- a/tests/ffi_2/generator/c_types.dart
+++ /dev/null
@@ -1,461 +0,0 @@
-// Copyright (c) 2020, 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.
-
-// @dart = 2.9
-
-import 'dart:math' as math;
-
-import 'utils.dart';
-
-const int8 = FundamentalType(PrimitiveType.int8);
-const int16 = FundamentalType(PrimitiveType.int16);
-const int32 = FundamentalType(PrimitiveType.int32);
-const int64 = FundamentalType(PrimitiveType.int64);
-const uint8 = FundamentalType(PrimitiveType.uint8);
-const uint16 = FundamentalType(PrimitiveType.uint16);
-const uint32 = FundamentalType(PrimitiveType.uint32);
-const uint64 = FundamentalType(PrimitiveType.uint64);
-const intptr = FundamentalType(PrimitiveType.intptr);
-const float = FundamentalType(PrimitiveType.float);
-const double_ = FundamentalType(PrimitiveType.double_);
-
-enum PrimitiveType {
-  int8,
-  int16,
-  int32,
-  int64,
-  uint8,
-  uint16,
-  uint32,
-  uint64,
-  intptr,
-  float,
-  double_,
-}
-
-const primitiveNames = [
-  "int8",
-  "int16",
-  "int32",
-  "int64",
-  "uint8",
-  "uint16",
-  "uint32",
-  "uint64",
-  "intptr",
-  "float",
-  "double",
-];
-
-const intptrSize = -1;
-const primitiveSizesInBytes = [1, 2, 4, 8, 1, 2, 4, 8, intptrSize, 4, 8];
-
-abstract class CType {
-  String get cType;
-  String get dartCType;
-  String get dartType;
-  String get dartStructFieldAnnotation;
-
-  /// Has a known [size] that is the same for all architectures.
-  bool get hasSize;
-
-  /// Get a size in bytes that is the same on all architectures.
-  int get size;
-
-  /// All members have a floating point type.
-  bool get isOnlyFloatingPoint;
-
-  /// All members have a integer type.
-  bool get isOnlyInteger;
-
-  String toString() => dartCType;
-
-  const CType();
-}
-
-class FundamentalType extends CType {
-  final PrimitiveType primitive;
-
-  const FundamentalType(this.primitive);
-
-  bool get isFloatingPoint =>
-      primitive == PrimitiveType.float || primitive == PrimitiveType.double_;
-  bool get isInteger => !isFloatingPoint;
-  bool get isOnlyFloatingPoint => isFloatingPoint;
-  bool get isOnlyInteger => isInteger;
-  bool get isUnsigned =>
-      primitive == PrimitiveType.uint8 ||
-      primitive == PrimitiveType.uint16 ||
-      primitive == PrimitiveType.uint32 ||
-      primitive == PrimitiveType.uint64;
-  bool get isSigned => !isUnsigned;
-
-  String get name => primitiveNames[primitive.index];
-
-  String get cType => "${name}${isInteger ? "_t" : ""}";
-  String get dartCType => name.upperCaseFirst();
-  String get dartType => isInteger ? "int" : "double";
-  String get dartStructFieldAnnotation => "@${dartCType}()";
-  bool get hasSize => primitive != PrimitiveType.intptr;
-  int get size {
-    if (!hasSize) {
-      throw "Size unknown.";
-    }
-    return primitiveSizesInBytes[primitive.index];
-  }
-}
-
-class PointerType extends CType {
-  final CType pointerTo;
-
-  PointerType(this.pointerTo);
-
-  String get cType => "${pointerTo.cType}*";
-  String get dartCType => "Pointer<${pointerTo.dartCType}>";
-  String get dartType => "Pointer<${pointerTo.dartType}>";
-  String get dartStructFieldAnnotation => "";
-  bool get hasSize => false;
-  int get size => throw "Size unknown";
-
-  bool get isOnlyFloatingPoint => false;
-  bool get isOnlyInteger => true;
-}
-
-/// Used to give [StructType] fields and [FunctionType] arguments names.
-class Member {
-  final CType type;
-  final String name;
-
-  Member(this.type, this.name);
-
-  String dartStructField(bool nnbd) {
-    final modifier = nnbd ? "external" : "";
-    return "${type.dartStructFieldAnnotation} $modifier ${type.dartType} $name;";
-  }
-
-  String get cStructField {
-    String postFix = "";
-    if (type is FixedLengthArrayType) {
-      final dimensions = (type as FixedLengthArrayType).dimensions;
-      postFix = "[${dimensions.join("][")}]";
-    }
-    return "${type.cType} $name$postFix;";
-  }
-
-  String toString() => "$type $name";
-}
-
-List<Member> generateMemberNames(List<CType> memberTypes) {
-  int index = 0;
-  List<Member> result = [];
-  for (final type in memberTypes) {
-    result.add(Member(type, "a$index"));
-    index++;
-  }
-  return result;
-}
-
-abstract class CompositeType extends CType {
-  final List<Member> members;
-
-  /// To disambiguate same size structs.
-  final String suffix;
-
-  /// To override names.
-  final String overrideName;
-
-  CompositeType(List<CType> memberTypes)
-      : this.members = generateMemberNames(memberTypes),
-        this.suffix = "",
-        this.overrideName = "";
-  CompositeType.disambiguate(List<CType> memberTypes, this.suffix)
-      : this.members = generateMemberNames(memberTypes),
-        this.overrideName = "";
-  CompositeType.override(List<CType> memberTypes, this.overrideName)
-      : this.members = generateMemberNames(memberTypes),
-        this.suffix = "";
-
-  List<CType> get memberTypes => members.map((a) => a.type).toList();
-
-  String get name;
-
-  String get cType => name;
-  String get dartCType => name;
-  String get dartType => name;
-  String get dartStructFieldAnnotation => "";
-  String get cKeyword;
-  String get dartSuperClass;
-
-  bool get isOnlyFloatingPoint =>
-      !memberTypes.map((e) => e.isOnlyFloatingPoint).contains(false);
-  bool get isOnlyInteger =>
-      !memberTypes.map((e) => e.isOnlyInteger).contains(false);
-
-  bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
-
-  bool get hasNestedStructs =>
-      members.map((e) => e.type is StructType).contains(true);
-
-  bool get hasInlineArrays =>
-      members.map((e) => e.type is FixedLengthArrayType).contains(true);
-
-  bool get hasMultiDimensionalInlineArrays => members
-      .map((e) => e.type)
-      .whereType<FixedLengthArrayType>()
-      .where((e) => e.isMulti)
-      .isNotEmpty;
-}
-
-class StructType extends CompositeType {
-  final int? packing;
-
-  StructType(List<CType> memberTypes, {int? this.packing}) : super(memberTypes);
-  StructType.disambiguate(List<CType> memberTypes, String suffix,
-      {int? this.packing})
-      : super.disambiguate(memberTypes, suffix);
-  StructType.override(List<CType> memberTypes, String overrideName,
-      {int? this.packing})
-      : super.override(memberTypes, overrideName);
-
-  String get cKeyword => "struct";
-  String get dartSuperClass => "Struct";
-
-  bool get hasSize =>
-      !memberTypes.map((e) => e.hasSize).contains(false) && !hasPadding;
-  int get size => memberTypes.fold(0, (int acc, e) => acc + e.size);
-
-  bool get hasPacking => packing != null;
-
-  bool get hasPadding {
-    if (members.length < 2) {
-      return false;
-    }
-    if (packing == 1) {
-      return false;
-    }
-
-    /// Rough approximation, to not redo all ABI logic here.
-    return members[0].type.size < members[1].type.size;
-  }
-
-  /// All members have the same type.
-  bool get isHomogeneous => memberTypes.toSet().length == 1;
-
-  String get name {
-    String result = dartSuperClass;
-    if (overrideName != "") {
-      return result + overrideName;
-    }
-    if (hasSize) {
-      result += "${size}Byte" + (size != 1 ? "s" : "");
-    }
-    if (hasPacking) {
-      result += "Packed";
-      if (packing! > 1) {
-        result += "$packing";
-      }
-    }
-    if (hasNestedStructs) {
-      result += "Nested";
-    }
-    if (hasInlineArrays) {
-      result += "InlineArray";
-      if (hasMultiDimensionalInlineArrays) {
-        result += "MultiDimensional";
-      }
-    }
-    if (members.length == 0) {
-      // No suffix.
-    } else if (hasPadding) {
-      result += "Alignment${memberTypes[1].dartCType}";
-    } else if (isHomogeneous && members.length > 1 && !hasNestedStructs) {
-      result += "Homogeneous${memberTypes.first.dartCType}";
-    } else if (isOnlyFloatingPoint) {
-      result += "Float";
-    } else if (isOnlyInteger) {
-      result += "Int";
-    } else {
-      result += "Mixed";
-    }
-    result += suffix;
-    return result;
-  }
-}
-
-class UnionType extends CompositeType {
-  UnionType(List<CType> memberTypes) : super(memberTypes);
-
-  String get cKeyword => "union";
-  String get dartSuperClass => "Union";
-
-  bool get hasSize => !memberTypes.map((e) => e.hasSize).contains(false);
-  int get size => memberTypes.fold(0, (int acc, e) => math.max(acc, e.size));
-
-  String get name {
-    String result = dartSuperClass;
-    if (overrideName != "") {
-      return result + overrideName;
-    }
-    if (hasSize) {
-      result += "${size}Byte" + (size != 1 ? "s" : "");
-    }
-    if (hasNestedStructs) {
-      result += "Nested";
-    }
-    if (hasInlineArrays) {
-      result += "InlineArray";
-      if (hasMultiDimensionalInlineArrays) {
-        result += "MultiDimensional";
-      }
-    }
-    if (members.length == 0) {
-      // No suffix.
-    } else if (isOnlyFloatingPoint) {
-      result += "Float";
-    } else if (isOnlyInteger) {
-      result += "Int";
-    } else {
-      result += "Mixed";
-    }
-    result += suffix;
-    return result;
-  }
-}
-
-class FixedLengthArrayType extends CType {
-  final CType elementType;
-  final int length;
-
-  FixedLengthArrayType(this.elementType, this.length);
-
-  factory FixedLengthArrayType.multi(CType elementType, List<int> dimensions) {
-    if (dimensions.length == 1) {
-      return FixedLengthArrayType(elementType, dimensions.single);
-    }
-
-    final remainingDimensions = dimensions.sublist(1);
-    final nestedArray =
-        FixedLengthArrayType.multi(elementType, remainingDimensions);
-    return FixedLengthArrayType(nestedArray, dimensions.first);
-  }
-
-  String get cType => elementType.cType;
-  String get dartCType => "Array<${elementType.dartCType}>";
-  String get dartType => "Array<${elementType.dartCType}>";
-
-  String get dartStructFieldAnnotation {
-    if (dimensions.length > 5) {
-      return "@Array.multi([${dimensions.join(", ")}])";
-    }
-    return "@Array(${dimensions.join(", ")})";
-  }
-
-  List<int> get dimensions {
-    final elementType = this.elementType;
-    if (elementType is FixedLengthArrayType) {
-      return [length, ...elementType.dimensions];
-    }
-    return [length];
-  }
-
-  bool get isMulti => elementType is FixedLengthArrayType;
-
-  bool get hasSize => elementType.hasSize;
-  int get size => elementType.size * length;
-
-  bool get isOnlyFloatingPoint => elementType.isOnlyFloatingPoint;
-  bool get isOnlyInteger => elementType.isOnlyInteger;
-}
-
-class FunctionType extends CType {
-  final List<Member> arguments;
-  final CType returnValue;
-  final String reason;
-
-  List<CType> get argumentTypes => arguments.map((a) => a.type).toList();
-
-  FunctionType(List<CType> argumentTypes, this.returnValue, this.reason)
-      : this.arguments = generateMemberNames(argumentTypes);
-
-  String get cType =>
-      throw "Are not represented without function or variable name in C.";
-
-  String get dartCType {
-    final argumentsDartCType = argumentTypes.map((e) => e.dartCType).join(", ");
-    return "${returnValue.dartCType} Function($argumentsDartCType)";
-  }
-
-  String get dartType {
-    final argumentsDartType = argumentTypes.map((e) => e.dartType).join(", ");
-    return "${returnValue.dartType} Function($argumentsDartType)";
-  }
-
-  String get dartStructFieldAnnotation => throw "No nested function pointers.";
-
-  bool get hasSize => false;
-  int get size => throw "Unknown size.";
-
-  bool get isOnlyFloatingPoint => throw "Not implemented";
-  bool get isOnlyInteger => throw "Not implemented";
-
-  /// Group consecutive [arguments] by same type.
-  ///
-  /// Used for naming.
-  List<List<Member>> get argumentsGrouped {
-    List<List<Member>> result = [];
-    for (final a in arguments) {
-      if (result.isEmpty) {
-        result.add([a]);
-      } else if (result.last.first.type.dartCType == a.type.dartCType) {
-        result.last.add(a);
-      } else {
-        result.add([a]);
-      }
-    }
-    return result;
-  }
-
-  /// A suitable name based on the signature.
-  String get cName {
-    String result = "";
-    if (arguments.containsComposites && returnValue is FundamentalType) {
-      result = "Pass";
-    } else if (returnValue is StructType &&
-        argumentTypes.contains(returnValue)) {
-      result = "ReturnStructArgument";
-    } else if (returnValue is UnionType &&
-        argumentTypes.contains(returnValue)) {
-      result = "ReturnUnionArgument";
-    } else if (returnValue is StructType) {
-      if (arguments.length == (returnValue as StructType).members.length) {
-        return "Return${returnValue.dartCType}";
-      }
-    } else if (returnValue is UnionType && arguments.length == 1) {
-      return "Return${returnValue.dartCType}";
-    } else {
-      result = "Uncategorized";
-    }
-
-    for (final group in argumentsGrouped) {
-      result += group.first.type.dartCType;
-      if (group.length > 1) {
-        result += "x${group.length}";
-      }
-    }
-    return result.limitTo(50);
-  }
-
-  String get dartTestName => "test$cName";
-
-  String get dartName => cName.lowerCaseFirst();
-
-  /// Only valid for [TestType.structReturnArgument].
-  Member get structReturnArgument =>
-      arguments.firstWhere((a) => a.type == returnValue);
-}
-
-extension MemberList on List<Member> {
-  bool get containsComposites =>
-      map((m) => m.type is CompositeType).contains(true);
-}
diff --git a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
deleted file mode 100644
index f8fbb1b..0000000
--- a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
+++ /dev/null
@@ -1,812 +0,0 @@
-// Copyright (c) 2020, 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.
-
-// @dart = 2.9
-
-import 'c_types.dart';
-
-final functions = [
-  ...functionsStructArguments,
-  ...functionsStructReturn,
-  ...functionsReturnArgument,
-];
-
-final functionsStructArguments = [
-  FunctionType(List.filled(10, struct1byteInt), int64, """
-Smallest struct with data.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct3bytesInt), int64, """
-Not a multiple of word size, not a power of two.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct3bytesInt2), int64, """
-Not a multiple of word size, not a power of two.
-With alignment rules taken into account size is 4 bytes.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct4bytesInt), int64, """
-Exactly word size on 32-bit architectures.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct7bytesInt), int64, """
-Sub word size on 64 bit architectures.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct7bytesInt2), int64, """
-Sub word size on 64 bit architectures.
-With alignment rules taken into account size is 8 bytes.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct8bytesInt), int64, """
-Exactly word size struct on 64bit architectures.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct8bytesFloat), float, """
-Arguments passed in FP registers as long as they fit.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct8BytesMixed), float, """
-On x64, arguments go in int registers because it is not only float.
-10 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct9bytesInt), int64, """
-Argument is a single byte over a multiple of word size.
-10 struct arguments will exhaust available registers.
-Struct only has 1-byte aligned fields to test struct alignment itself.
-Tests upper bytes in the integer registers that are partly filled.
-Tests stack alignment of non word size stack arguments."""),
-  FunctionType(List.filled(10, struct9bytesInt2), int64, """
-Argument is a single byte over a multiple of word size.
-With alignment rules taken into account size is 12 or 16 bytes.
-10 struct arguments will exhaust available registers.
-"""),
-  FunctionType(List.filled(6, struct12bytesFloat), float, """
-Arguments in FPU registers on arm hardfp and arm64.
-Struct arguments will exhaust available registers, and leave some empty.
-The last argument is to test whether arguments are backfilled."""),
-  FunctionType(List.filled(5, struct16bytesFloat), float, """
-On Linux x64 argument is transferred on stack because it is over 16 bytes.
-Arguments in FPU registers on arm hardfp and arm64.
-5 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct16bytesMixed), double_, """
-On x64, arguments are split over FP and int registers.
-On x64, it will exhaust the integer registers with the 6th argument.
-The rest goes on the stack.
-On arm, arguments are 8 byte aligned."""),
-  FunctionType(List.filled(10, struct16bytesMixed2), float, """
-On x64, arguments are split over FP and int registers.
-On x64, it will exhaust the integer registers with the 6th argument.
-The rest goes on the stack.
-On arm, arguments are 4 byte aligned."""),
-  FunctionType(List.filled(10, struct17bytesInt), int64, """
-Arguments are passed as pointer to copy on arm64.
-Tests that the memory allocated for copies are rounded up to word size."""),
-  FunctionType(List.filled(10, struct19bytesInt), int64, """
-The minimum alignment of this struct is only 1 byte based on its fields.
-Test that the memory backing these structs is extended to the right size.
-"""),
-  FunctionType(List.filled(10, struct20bytesInt), int32, """
-Argument too big to go into integer registers on arm64.
-The arguments are passed as pointers to copies.
-The amount of arguments exhausts the number of integer registers, such that
-pointers to copies are also passed on the stack."""),
-  FunctionType(
-      [struct20bytesFloat],
-      float,
-      """
-Argument too big to go into FPU registers in hardfp and arm64."""),
-  FunctionType(List.filled(5, struct32bytesDouble), double_, """
-Arguments in FPU registers on arm64.
-5 struct arguments will exhaust available registers."""),
-  FunctionType(
-      [struct40bytesDouble],
-      double_,
-      """
-Argument too big to go into FPU registers in arm64."""),
-  FunctionType(
-      [struct1024bytesInt],
-      uint64,
-      """
-Test 1kb struct."""),
-  FunctionType(
-      [
-        float,
-        struct16bytesFloat,
-        float,
-        struct16bytesFloat,
-        float,
-        struct16bytesFloat,
-        float,
-        struct16bytesFloat,
-        float
-      ],
-      float,
-      """
-Tests the alignment of structs in FPU registers and backfilling."""),
-  FunctionType(
-      [
-        float,
-        struct32bytesDouble,
-        float,
-        struct32bytesDouble,
-        float,
-        struct32bytesDouble,
-        float,
-        struct32bytesDouble,
-        float
-      ],
-      double_,
-      """
-Tests the alignment of structs in FPU registers and backfilling."""),
-  FunctionType(
-      [
-        int8,
-        struct16bytesMixed,
-        int8,
-        struct16bytesMixed,
-        int8,
-        struct16bytesMixed,
-        int8,
-        struct16bytesMixed,
-        int8
-      ],
-      double_,
-      """
-Tests the alignment of structs in integers registers and on the stack.
-Arm32 aligns this struct at 8.
-Also, arm32 allocates the second struct partially in registers, partially
-on stack.
-Test backfilling of integer registers."""),
-  FunctionType(
-      [
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        int32,
-      ],
-      double_,
-      """
-On Linux x64, it will exhaust xmm registers first, after 6 doubles and 2
-structs. The rest of the structs will go on the stack.
-The int will be backfilled into the int register."""),
-  FunctionType(
-      [
-        int32,
-        int32,
-        int32,
-        int32,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        struct16bytesMixed,
-        double_,
-      ],
-      double_,
-      """
-On Linux x64, it will exhaust int registers first.
-The rest of the structs will go on the stack.
-The double will be backfilled into the xmm register."""),
-  FunctionType(
-      [
-        struct40bytesDouble,
-        struct4bytesInt,
-        struct8bytesFloat,
-      ],
-      double_,
-      """
-On various architectures, first struct is allocated on stack.
-Check that the other two arguments are allocated on registers."""),
-  FunctionType(
-      [
-        // Exhaust integer registers on all architectures
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        // Exhaust floating point registers on all architectures.
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        double_,
-        // Pass all kinds of structs to exercise stack placement behavior.
-        //
-        // For all structs, align stack with int64, then align to 1-byte with
-        // int8, then pass struct.
-        int64,
-        int8,
-        struct1byteInt,
-        int64,
-        int8,
-        struct4bytesInt,
-        int64,
-        int8,
-        struct8bytesInt,
-        int64,
-        int8,
-        struct8bytesFloat,
-        int64,
-        int8,
-        struct8BytesMixed,
-        int64,
-        int8,
-        structAlignmentInt16,
-        int64,
-        int8,
-        structAlignmentInt32,
-        int64,
-        int8,
-        structAlignmentInt64,
-      ],
-      double_,
-      """
-Test alignment and padding of 16 byte int within struct."""),
-  FunctionType(
-      [structAlignmentInt16],
-      int64,
-      """
-Test alignment and padding of 16 byte int within struct."""),
-  FunctionType(
-      [structAlignmentInt32],
-      int64,
-      """
-Test alignment and padding of 32 byte int within struct."""),
-  FunctionType(
-      [structAlignmentInt64],
-      int64,
-      """
-Test alignment and padding of 64 byte int within struct."""),
-  FunctionType(List.filled(10, struct8bytesNestedInt), int64, """
-Simple nested struct. No alignment gaps on any architectures.
-10 arguments exhaust registers on all platforms."""),
-  FunctionType(List.filled(10, struct8bytesNestedFloat), float, """
-Simple nested struct. No alignment gaps on any architectures.
-10 arguments exhaust fpu registers on all platforms."""),
-  FunctionType(List.filled(10, struct8bytesNestedFloat2), float, """
-Simple nested struct. No alignment gaps on any architectures.
-10 arguments exhaust fpu registers on all platforms.
-The nesting is irregular, testing homogenous float rules on arm and arm64,
-and the fpu register usage on x64."""),
-  FunctionType(List.filled(10, struct8bytesNestedMixed), double_, """
-Simple nested struct. No alignment gaps on any architectures.
-10 arguments exhaust all registers on all platforms."""),
-  FunctionType(List.filled(2, struct16bytesNestedInt), int64, """
-Deeper nested struct to test recursive member access."""),
-  FunctionType(List.filled(2, struct32bytesNestedInt), int64, """
-Even deeper nested struct to test recursive member access."""),
-  FunctionType(
-      [structNestedAlignmentInt16],
-      int64,
-      """
-Test alignment and padding of nested struct with 16 byte int."""),
-  FunctionType(
-      [structNestedAlignmentInt32],
-      int64,
-      """
-Test alignment and padding of nested struct with 32 byte int."""),
-  FunctionType(
-      [structNestedAlignmentInt64],
-      int64,
-      """
-Test alignment and padding of nested struct with 64 byte int."""),
-  FunctionType(List.filled(4, structNestedEvenBigger), double_, """
-Return big irregular struct as smoke test."""),
-  FunctionType(List.filled(4, structInlineArray), int32, """
-Simple struct with inline array."""),
-  FunctionType(List.filled(4, structInlineArrayIrregular), int32, """
-Irregular struct with inline array."""),
-  FunctionType(
-      [structInlineArray100Bytes],
-      int32,
-      """
-Regular larger struct with inline array."""),
-  FunctionType(List.filled(5, struct16bytesFloatInlineNested), float, """
-Arguments in FPU registers on arm hardfp and arm64.
-5 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(5, struct32bytesDoubleInlineNested), double_, """
-Arguments in FPU registers on arm64.
-5 struct arguments will exhaust available registers."""),
-  FunctionType(List.filled(10, struct16bytesMixedInlineNested), float, """
-On x64, arguments are split over FP and int registers.
-On x64, it will exhaust the integer registers with the 6th argument.
-The rest goes on the stack.
-On arm, arguments are 4 byte aligned."""),
-  FunctionType(
-      [
-        uint8,
-        struct32bytesInlineArrayMultiDimesional,
-        uint8,
-        struct8bytesInlineArrayMultiDimesional,
-        uint8,
-        struct8bytesInlineArrayMultiDimesional,
-        uint8
-      ],
-      uint32,
-      """
-Test multi dimensional inline array struct as argument."""),
-  FunctionType(
-      [uint8, structMultiDimensionalStruct, uint8],
-      uint32,
-      """
-Test struct in multi dimensional inline array."""),
-  FunctionType(List.filled(10, struct3bytesPacked), int64, """
-Small struct with mis-aligned member."""),
-  FunctionType(List.filled(10, struct8bytesPacked), int64, """
-Struct with mis-aligned member."""),
-  FunctionType(
-      [...List.filled(10, struct9bytesPacked), double_, int32],
-      double_,
-      """
-Struct with mis-aligned member.
-Tests backfilling of CPU and FPU registers."""),
-  FunctionType(
-      [struct5bytesPacked],
-      double_,
-      """
-This packed struct happens to have only aligned members."""),
-  FunctionType(
-      [struct6bytesPacked],
-      double_,
-      """
-Check alignment of packed struct in non-packed struct."""),
-  FunctionType(
-      [struct6bytesPacked2],
-      double_,
-      """
-Check alignment of packed struct array in non-packed struct."""),
-  FunctionType(
-      [struct15bytesPacked],
-      double_,
-      """
-Check alignment of packed struct array in non-packed struct."""),
-  FunctionType(List.filled(10, union4bytesMixed), double_, """
-Check placement of mixed integer/float union."""),
-  FunctionType(List.filled(10, union8bytesFloat), double_, """
-Check placement of mixed floats union."""),
-  FunctionType(List.filled(10, union12bytesInt), double_, """
-Mixed-size union argument."""),
-  FunctionType(List.filled(10, union16bytesFloat), double_, """
-Union with homogenous floats."""),
-  FunctionType(List.filled(10, union16bytesFloat2), double_, """
-Union with homogenous floats."""),
-];
-
-final functionsStructReturn = [
-  FunctionType(struct1byteInt.memberTypes, struct1byteInt, """
-Smallest struct with data."""),
-  FunctionType(struct3bytesInt.memberTypes, struct3bytesInt, """
-Smaller than word size return value on all architectures."""),
-  FunctionType(struct3bytesInt2.memberTypes, struct3bytesInt2, """
-Smaller than word size return value on all architectures.
-With alignment rules taken into account size is 4 bytes."""),
-  FunctionType(struct4bytesInt.memberTypes, struct4bytesInt, """
-Word size return value on 32 bit architectures.."""),
-  FunctionType(struct7bytesInt.memberTypes, struct7bytesInt, """
-Non-wordsize return value."""),
-  FunctionType(struct7bytesInt2.memberTypes, struct7bytesInt2, """
-Non-wordsize return value.
-With alignment rules taken into account size is 8 bytes."""),
-  FunctionType(struct8bytesInt.memberTypes, struct8bytesInt, """
-Return value in integer registers on many architectures."""),
-  FunctionType(struct8bytesFloat.memberTypes, struct8bytesFloat, """
-Return value in FP registers on many architectures."""),
-  FunctionType(struct8BytesMixed.memberTypes, struct8BytesMixed, """
-Return value split over FP and integer register in x64."""),
-  FunctionType(struct9bytesInt.memberTypes, struct9bytesInt, """
-The minimum alignment of this struct is only 1 byte based on its fields.
-Test that the memory backing these structs is the right size and that
-dart:ffi trampolines do not write outside this size."""),
-  FunctionType(struct9bytesInt2.memberTypes, struct9bytesInt2, """
-Return value in two integer registers on x64.
-With alignment rules taken into account size is 12 or 16 bytes."""),
-  FunctionType(struct12bytesFloat.memberTypes, struct12bytesFloat, """
-Return value in FPU registers, but does not use all registers on arm hardfp
-and arm64."""),
-  FunctionType(struct16bytesFloat.memberTypes, struct16bytesFloat, """
-Return value in FPU registers on arm hardfp and arm64."""),
-  FunctionType(struct16bytesMixed.memberTypes, struct16bytesMixed, """
-Return value split over FP and integer register in x64."""),
-  FunctionType(struct16bytesMixed2.memberTypes, struct16bytesMixed2, """
-Return value split over FP and integer register in x64.
-The integer register contains half float half int."""),
-  FunctionType(struct17bytesInt.memberTypes, struct17bytesInt, """
-Rerturn value returned in preallocated space passed by pointer on most ABIs.
-Is non word size on purpose, to test that structs are rounded up to word size
-on all ABIs."""),
-  FunctionType(struct19bytesInt.memberTypes, struct19bytesInt, """
-The minimum alignment of this struct is only 1 byte based on its fields.
-Test that the memory backing these structs is the right size and that
-dart:ffi trampolines do not write outside this size."""),
-  FunctionType(struct20bytesInt.memberTypes, struct20bytesInt, """
-Return value too big to go in cpu registers on arm64."""),
-  FunctionType(struct20bytesFloat.memberTypes, struct20bytesFloat, """
-Return value too big to go in FPU registers on x64, arm hardfp and arm64."""),
-  FunctionType(struct32bytesDouble.memberTypes, struct32bytesDouble, """
-Return value in FPU registers on arm64."""),
-  FunctionType(struct40bytesDouble.memberTypes, struct40bytesDouble, """
-Return value too big to go in FPU registers on arm64."""),
-  FunctionType(struct1024bytesInt.memberTypes, struct1024bytesInt, """
-Test 1kb struct."""),
-  FunctionType(struct3bytesPacked.memberTypes, struct3bytesPacked, """
-Small struct with mis-aligned member."""),
-  FunctionType(struct8bytesPacked.memberTypes, struct8bytesPacked, """
-Struct with mis-aligned member."""),
-  FunctionType(struct9bytesPacked.memberTypes, struct9bytesPacked, """
-Struct with mis-aligned member.
-Tests backfilling of CPU and FPU registers."""),
-  FunctionType(
-      [union4bytesMixed.memberTypes.first],
-      union4bytesMixed,
-      """
-Returning a mixed integer/float union."""),
-  FunctionType(
-      [union8bytesFloat.memberTypes.first],
-      union8bytesFloat,
-      """
-Returning a floating point only union."""),
-  FunctionType(
-      [union12bytesInt.memberTypes.first],
-      union12bytesInt,
-      """
-Returning a mixed-size union."""),
-  FunctionType(
-      [union16bytesFloat2.memberTypes.first],
-      union16bytesFloat2,
-      """
-Returning union with homogenous floats."""),
-];
-
-final functionsReturnArgument = [
-  FunctionType(
-      [struct1byteInt],
-      struct1byteInt,
-      """
-Test that a struct passed in as argument can be returned.
-Especially for ffi callbacks.
-Struct is passed in int registers in most ABIs."""),
-  FunctionType(
-      [int32, int32, int32, int32, int32, int32, int32, int32, struct1byteInt],
-      struct1byteInt,
-      """
-Test that a struct passed in as argument can be returned.
-Especially for ffi callbacks.
-Struct is passed on stack on all ABIs."""),
-  FunctionType(
-      [struct8bytesFloat],
-      struct8bytesFloat,
-      """
-Test that a struct passed in as argument can be returned.
-Especially for ffi callbacks.
-Struct is passed in float registers in most ABIs."""),
-  FunctionType(
-      [struct20bytesInt],
-      struct20bytesInt,
-      """
-On arm64, both argument and return value are passed in by pointer."""),
-  FunctionType(
-      [
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        int32,
-        struct20bytesInt
-      ],
-      struct20bytesInt,
-      """
-On arm64, both argument and return value are passed in by pointer.
-Ints exhaust registers, so that pointer is passed on stack."""),
-  FunctionType(
-      [structInlineArray],
-      structInlineArray,
-      """
-Test returning struct with inline array."""),
-  FunctionType(
-      [struct16bytesFloatInlineNested],
-      struct16bytesFloatInlineNested,
-      """
-Return value in FPU registers on arm hardfp and arm64."""),
-  FunctionType(
-      [struct32bytesDoubleInlineNested],
-      struct32bytesDoubleInlineNested,
-      """
-Return value in FPU registers on arm64."""),
-  FunctionType(
-      [struct16bytesMixedInlineNested],
-      struct16bytesMixedInlineNested,
-      """
-On x64 Linux, return value is split over FP and int registers."""),
-  FunctionType(structAlignmentInt16.memberTypes, structAlignmentInt16, """
-Test alignment and padding of 16 byte int within struct."""),
-  FunctionType(structAlignmentInt32.memberTypes, structAlignmentInt32, """
-Test alignment and padding of 32 byte int within struct."""),
-  FunctionType(structAlignmentInt64.memberTypes, structAlignmentInt64, """
-Test alignment and padding of 64 byte int within struct."""),
-  FunctionType(struct8bytesNestedInt.memberTypes, struct8bytesNestedInt, """
-Simple nested struct."""),
-  FunctionType(struct8bytesNestedFloat.memberTypes, struct8bytesNestedFloat, """
-Simple nested struct with floats."""),
-  FunctionType(
-      struct8bytesNestedFloat2.memberTypes, struct8bytesNestedFloat2, """
-The nesting is irregular, testing homogenous float rules on arm and arm64,
-and the fpu register usage on x64."""),
-  FunctionType(struct8bytesNestedMixed.memberTypes, struct8bytesNestedMixed, """
-Simple nested struct with mixed members."""),
-  FunctionType(struct16bytesNestedInt.memberTypes, struct16bytesNestedInt, """
-Deeper nested struct to test recursive member access."""),
-  FunctionType(struct32bytesNestedInt.memberTypes, struct32bytesNestedInt, """
-Even deeper nested struct to test recursive member access."""),
-  FunctionType(
-      structNestedAlignmentInt16.memberTypes, structNestedAlignmentInt16, """
-Test alignment and padding of nested struct with 16 byte int."""),
-  FunctionType(
-      structNestedAlignmentInt32.memberTypes, structNestedAlignmentInt32, """
-Test alignment and padding of nested struct with 32 byte int."""),
-  FunctionType(
-      structNestedAlignmentInt64.memberTypes, structNestedAlignmentInt64, """
-Test alignment and padding of nested struct with 64 byte int."""),
-  FunctionType(structNestedEvenBigger.memberTypes, structNestedEvenBigger, """
-Return big irregular struct as smoke test."""),
-];
-
-final compounds = [
-  struct1byteInt,
-  struct3bytesInt,
-  struct3bytesInt2,
-  struct4bytesInt,
-  struct4bytesFloat,
-  struct7bytesInt,
-  struct7bytesInt2,
-  struct8bytesInt,
-  struct8bytesFloat,
-  struct8bytesFloat2,
-  struct8BytesMixed,
-  struct9bytesInt,
-  struct9bytesInt2,
-  struct12bytesFloat,
-  struct16bytesFloat,
-  struct16bytesMixed,
-  struct16bytesMixed2,
-  struct17bytesInt,
-  struct19bytesInt,
-  struct20bytesInt,
-  struct20bytesFloat,
-  struct32bytesDouble,
-  struct40bytesDouble,
-  struct1024bytesInt,
-  structAlignmentInt16,
-  structAlignmentInt32,
-  structAlignmentInt64,
-  struct8bytesNestedInt,
-  struct8bytesNestedFloat,
-  struct8bytesNestedFloat2,
-  struct8bytesNestedMixed,
-  struct16bytesNestedInt,
-  struct32bytesNestedInt,
-  structNestedAlignmentInt16,
-  structNestedAlignmentInt32,
-  structNestedAlignmentInt64,
-  structNestedBig,
-  structNestedBigger,
-  structNestedEvenBigger,
-  structInlineArray,
-  structInlineArrayIrregular,
-  structInlineArray100Bytes,
-  structInlineArrayBig,
-  struct16bytesFloatInlineNested,
-  struct32bytesDoubleInlineNested,
-  struct16bytesMixedInlineNested,
-  struct8bytesInlineArrayMultiDimesional,
-  struct32bytesInlineArrayMultiDimesional,
-  struct64bytesInlineArrayMultiDimesional,
-  structMultiDimensionalStruct,
-  struct3bytesPacked,
-  struct3bytesPackedMembersAligned,
-  struct5bytesPacked,
-  struct6bytesPacked,
-  struct6bytesPacked2,
-  struct8bytesPacked,
-  struct9bytesPacked,
-  struct15bytesPacked,
-  union4bytesMixed,
-  union8bytesFloat,
-  union12bytesInt,
-  union16bytesFloat,
-  union16bytesFloat2,
-];
-
-final struct1byteInt = StructType([int8]);
-final struct3bytesInt = StructType(List.filled(3, uint8));
-final struct3bytesInt2 = StructType.disambiguate([int16, int8], "2ByteAligned");
-final struct4bytesInt = StructType([int16, int16]);
-final struct4bytesFloat = StructType([float]);
-final struct7bytesInt = StructType(List.filled(7, uint8));
-final struct7bytesInt2 =
-    StructType.disambiguate([int32, int16, int8], "4ByteAligned");
-final struct8bytesInt = StructType([int16, int16, int32]);
-final struct8bytesFloat = StructType([float, float]);
-final struct8bytesFloat2 = StructType([double_]);
-final struct8BytesMixed = StructType([float, int16, int16]);
-final struct9bytesInt = StructType(List.filled(9, uint8));
-final struct9bytesInt2 =
-    StructType.disambiguate([int64, int8], "4Or8ByteAligned");
-final struct12bytesFloat = StructType([float, float, float]);
-
-/// The largest homogenous float that goes into FPU registers on softfp and
-/// arm64.
-final struct16bytesFloat = StructType([float, float, float, float]);
-
-/// This struct will be 8 byte aligned on arm.
-final struct16bytesMixed = StructType([double_, int64]);
-
-/// This struct will be 4 byte aligned on arm.
-final struct16bytesMixed2 =
-    StructType.disambiguate([float, float, float, int32], "2");
-
-final struct17bytesInt = StructType([int64, int64, int8]);
-
-/// This struct has only 1 byte field-alignmnent requirements.
-final struct19bytesInt = StructType(List.filled(19, uint8));
-
-/// The first homogenous integer struct that does not go into registers
-/// anymore on arm64.
-final struct20bytesInt = StructType([int32, int32, int32, int32, int32]);
-
-/// The first homogenous float that does not go into FPU registers anymore on
-/// softfp and arm64.
-final struct20bytesFloat = StructType([float, float, float, float, float]);
-
-/// Largest homogenous doubles in arm64 that goes into FPU registers.
-final struct32bytesDouble = StructType([double_, double_, double_, double_]);
-
-/// The first homogenous doubles that does not go into FPU registers anymore on
-/// arm64.
-final struct40bytesDouble =
-    StructType([double_, double_, double_, double_, double_]);
-
-final struct1024bytesInt = StructType(List.filled(128, uint64));
-
-final structAlignmentInt16 = StructType([int8, int16, int8]);
-final structAlignmentInt32 = StructType([int8, int32, int8]);
-final structAlignmentInt64 = StructType([int8, int64, int8]);
-
-final struct8bytesNestedInt = StructType([struct4bytesInt, struct4bytesInt]);
-final struct8bytesNestedFloat =
-    StructType([struct4bytesFloat, struct4bytesFloat]);
-final struct8bytesNestedFloat2 =
-    StructType.disambiguate([struct4bytesFloat, float], "2");
-final struct8bytesNestedMixed =
-    StructType([struct4bytesInt, struct4bytesFloat]);
-
-final struct16bytesNestedInt =
-    StructType([struct8bytesNestedInt, struct8bytesNestedInt]);
-final struct32bytesNestedInt =
-    StructType([struct16bytesNestedInt, struct16bytesNestedInt]);
-
-final structNestedAlignmentInt16 = StructType.disambiguate(
-    List.filled(2, structAlignmentInt16), structAlignmentInt16.name);
-final structNestedAlignmentInt32 = StructType.disambiguate(
-    List.filled(2, structAlignmentInt32), structAlignmentInt32.name);
-final structNestedAlignmentInt64 = StructType.disambiguate(
-    List.filled(2, structAlignmentInt64), structAlignmentInt64.name);
-
-final structNestedBig = StructType.override([
-  uint16,
-  struct8bytesNestedMixed,
-  uint16,
-  struct8bytesNestedFloat2,
-  uint16,
-  struct8bytesNestedFloat,
-  uint16
-], "NestedIrregularBig");
-final structNestedBigger = StructType.override(
-    [structNestedBig, struct8bytesNestedMixed, float, double_],
-    "NestedIrregularBigger");
-final structNestedEvenBigger = StructType.override(
-    [uint64, structNestedBigger, structNestedBigger, double_],
-    "NestedIrregularEvenBigger");
-
-final structInlineArray = StructType([FixedLengthArrayType(uint8, 8)]);
-
-final structInlineArrayIrregular = StructType.override(
-    [FixedLengthArrayType(struct3bytesInt2, 2), uint8], "InlineArrayIrregular");
-
-final structInlineArray100Bytes = StructType.override(
-    [FixedLengthArrayType(uint8, 100)], "InlineArray100Bytes");
-
-final structInlineArrayBig = StructType.override(
-    [uint32, uint32, FixedLengthArrayType(uint8, 4000)], "InlineArrayBig");
-
-/// The largest homogenous float that goes into FPU registers on softfp and
-/// arm64. This time with nested structs and inline arrays.
-final struct16bytesFloatInlineNested = StructType.override([
-  StructType([float]),
-  FixedLengthArrayType(StructType([float]), 2),
-  float,
-], "Struct16BytesHomogeneousFloat2");
-
-/// The largest homogenous float that goes into FPU registers on arm64.
-/// This time with nested structs and inline arrays.
-final struct32bytesDoubleInlineNested = StructType.override([
-  StructType([double_]),
-  FixedLengthArrayType(StructType([double_]), 2),
-  double_,
-], "Struct32BytesHomogeneousDouble2");
-
-/// This struct is split over a CPU and FPU register in x64 Linux.
-/// This time with nested structs and inline arrays.
-final struct16bytesMixedInlineNested = StructType.override([
-  StructType([float]),
-  FixedLengthArrayType(StructType([float, int16, int16]), 1),
-  FixedLengthArrayType(int16, 2),
-], "Struct16BytesMixed3");
-
-final struct8bytesInlineArrayMultiDimesional = StructType([
-  FixedLengthArrayType.multi(uint8, [2, 2, 2])
-]);
-
-final struct32bytesInlineArrayMultiDimesional = StructType([
-  FixedLengthArrayType.multi(uint8, [2, 2, 2, 2, 2])
-]);
-
-final struct64bytesInlineArrayMultiDimesional = StructType([
-  FixedLengthArrayType.multi(uint8, [2, 2, 2, 2, 2, 2])
-]);
-
-final structMultiDimensionalStruct = StructType([
-  FixedLengthArrayType.multi(struct1byteInt, [2, 2])
-]);
-
-final struct3bytesPacked = StructType([int8, int16], packing: 1);
-
-final struct3bytesPackedMembersAligned =
-    StructType.disambiguate([int8, int16], "MembersAligned", packing: 1);
-
-final struct5bytesPacked = StructType([float, uint8], packing: 1);
-
-/// The float in the nested struct is not aligned.
-final struct6bytesPacked = StructType([uint8, struct5bytesPacked]);
-
-/// The second element in the array has a nested misaligned int16.
-final struct6bytesPacked2 =
-    StructType([FixedLengthArrayType(struct3bytesPackedMembersAligned, 2)]);
-
-final struct8bytesPacked =
-    StructType([uint8, uint32, uint8, uint8, uint8], packing: 1);
-
-final struct9bytesPacked = StructType([uint8, double_], packing: 1);
-
-/// The float in the nested struct is aligned in the first element in the
-/// inline array, but not in the subsequent ones.
-final struct15bytesPacked =
-    StructType([FixedLengthArrayType(struct5bytesPacked, 3)]);
-
-/// Mixed integer and float. Tests whether calling conventions put this in
-/// integer registers or not.
-final union4bytesMixed = UnionType([uint32, float]);
-
-/// Different types of float. Tests whether calling conventions put this in
-/// FPU registers or not.
-final union8bytesFloat = UnionType([double_, struct8bytesFloat]);
-
-/// This union has a size of 12, because of the 4-byte alignment of the first
-/// member.
-final union12bytesInt = UnionType([struct8bytesInt, struct9bytesInt]);
-
-/// This union has homogenous floats of the same sizes.
-final union16bytesFloat =
-    UnionType([FixedLengthArrayType(float, 4), struct16bytesFloat]);
-
-/// This union has homogenous floats of different sizes.
-final union16bytesFloat2 =
-    UnionType([struct8bytesFloat, struct12bytesFloat, struct16bytesFloat]);
diff --git a/tests/ffi_2/generator/structs_by_value_tests_generator.dart b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
deleted file mode 100644
index 39d8f7f..0000000
--- a/tests/ffi_2/generator/structs_by_value_tests_generator.dart
+++ /dev/null
@@ -1,1059 +0,0 @@
-// Copyright (c) 2020, 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.
-
-// @dart = 2.9
-
-import 'dart:io';
-
-import 'c_types.dart';
-import 'structs_by_value_tests_configuration.dart';
-import 'utils.dart';
-
-/// The test type determines how to convert the arguments into return values
-/// such that the caller knows what to check.
-enum TestType {
-  /// Tested by getting all the individual fields out of the structs and
-  /// summing their values.
-  structArguments,
-
-  /// Tested by passing assigning the arguments to the struct fields.
-  structReturn,
-
-  /// Tested by returning the struct passed in.
-  structReturnArgument,
-}
-
-extension on FunctionType {
-  TestType get testType {
-    if (arguments.containsComposites && returnValue is FundamentalType) {
-      return TestType.structArguments;
-    }
-    if (returnValue is CompositeType && argumentTypes.contains(returnValue)) {
-      return TestType.structReturnArgument;
-    }
-    if (returnValue is StructType) {
-      if (arguments.length == (returnValue as CompositeType).members.length) {
-        return TestType.structReturn;
-      }
-    }
-    if (returnValue is UnionType) {
-      if (arguments.length == 1) {
-        return TestType.structReturn;
-      }
-    }
-    throw Exception("Unknown test type: $this");
-  }
-}
-
-/// We use the class structure as an algebraic data type in order to keep the
-/// relevant parts of the code generation closer together.
-extension on CType {
-  /// The part of the cout expression after `std::cout` and before the `;`.
-  String coutExpression(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        if (this == uint8 || this == int8) {
-          return "<< static_cast<int>($variableName)";
-        }
-        return "<< $variableName";
-
-      case StructType:
-      case UnionType:
-        final this_ = this as CompositeType;
-        return this_.members.coutExpression("$variableName.");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        final indices = [for (var i = 0; i < this_.length; i += 1) i];
-
-        String result = '<< "["';
-        result += indices
-            .map((i) => this_.elementType.coutExpression("$variableName[$i]"))
-            .join('<< ", "');
-        result += '<< "]"';
-        return result.trimCouts();
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-
-  /// A statement recursively outputting all members.
-  String coutStatement(String variableName) {
-    final coutExpr = this.coutExpression(variableName);
-    return 'std::cout << "$variableName = " $coutExpr << "\\n";';
-  }
-}
-
-extension on List<Member> {
-  /// The part of the cout expression after `std::cout` and before the `;`.
-  String coutExpression([String namePrefix = ""]) {
-    String result = '<< "("';
-    result += this
-        .map((m) => m.type.coutExpression("$namePrefix${m.name}"))
-        .join('<< ", "');
-    result += '<< ")"';
-    return result.trimCouts();
-  }
-}
-
-extension on CType {
-  /// A list of statements adding all members recurisvely to `result`.
-  ///
-  /// Both valid in Dart and C.
-  String addToResultStatements(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        return "result += $variableName;\n";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.addToResultStatements("$variableName.");
-
-      case UnionType:
-        final this_ = this as UnionType;
-        final member = this_.members.first;
-        return member.type
-            .addToResultStatements("$variableName.${member.name}");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        final indices = [for (var i = 0; i < this_.length; i += 1) i];
-        return indices
-            .map((i) =>
-                this_.elementType.addToResultStatements("$variableName[$i]"))
-            .join();
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of statements adding all members recurisvely to `result`.
-  ///
-  /// Both valid in Dart and C.
-  String addToResultStatements([String namePrefix = ""]) {
-    return map((m) => m.type.addToResultStatements("$namePrefix${m.name}"))
-        .join();
-  }
-}
-
-extension on CType {
-  /// A list of statements recursively assigning all members with [a].
-  ///
-  /// Both valid in Dart and C.
-  String assignValueStatements(ArgumentValueAssigner a, String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        final this_ = this as FundamentalType;
-        return "$variableName = ${a.nextValue(this_)};\n";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.assignValueStatements(a, "$variableName.");
-
-      case UnionType:
-        final this_ = this as UnionType;
-        final member = this_.members.first;
-        return member.type
-            .assignValueStatements(a, "$variableName.${member.name}");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        final indices = [for (var i = 0; i < this_.length; i += 1) i];
-        return indices
-            .map((i) =>
-                this_.elementType.assignValueStatements(a, "$variableName[$i]"))
-            .join();
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-
-  /// A list of statements recursively coping all members from [source].
-  ///
-  /// Both valid in Dart and C.
-  String copyValueStatements(String source, String destination) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        return "$destination = $source;\n";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.copyValueStatements("$source.", "$destination.");
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of statements recursively assigning all members with [a].
-  ///
-  /// Both valid in Dart and C.
-  String assignValueStatements(ArgumentValueAssigner a,
-      [String namePrefix = ""]) {
-    return map((m) => m.type.assignValueStatements(a, "$namePrefix${m.name}"))
-        .join();
-  }
-
-  /// A list of statements recursively coping all members from [source].
-  ///
-  /// Both valid in Dart and C.
-  String copyValueStatements([sourcePrefix = "", destinationPrefix = ""]) {
-    return map((m) => m.type.copyValueStatements(
-        "$sourcePrefix${m.name}", "$destinationPrefix${m.name}")).join();
-  }
-}
-
-/// A helper class that assigns values to fundamental types.
-///
-/// Also keeps track of a sum of all values, to be used for testing the result.
-class ArgumentValueAssigner {
-  int i = 1;
-  int sum = 0;
-  String nextValue(FundamentalType type) {
-    int argumentValue = i;
-    i++;
-    if (type.isSigned && i % 2 == 0) {
-      argumentValue = -argumentValue;
-    }
-    sum += argumentValue;
-    if (type.isFloatingPoint) {
-      return argumentValue.toDouble().toString();
-    } else {
-      return argumentValue.toString();
-    }
-  }
-
-  String sumValue(FundamentalType type) {
-    if (type.isFloatingPoint) {
-      return sum.toDouble().toString();
-    } else {
-      return sum.toString();
-    }
-  }
-}
-
-extension on CType {
-  /// A list of Dart statements recursively allocating all members.
-  String dartAllocateStatements(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        return "${dartType} ${variableName};\n";
-
-      case StructType:
-      case UnionType:
-        return """
-final ${variableName}Pointer = calloc<$dartType>();
-final ${dartType} ${variableName} = ${variableName}Pointer.ref;
-""";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-
-  /// A list of Dart statements allocating as zero or nullptr.
-  String dartAllocateZeroStatements(String variableName,
-      {bool structsAsPointers = false}) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        final this_ = this as FundamentalType;
-        if (this_.isInteger) {
-          return "${dartType} ${variableName} = 0;\n";
-        }
-        return "${dartType} ${variableName} = 0.0;\n";
-
-      case StructType:
-      case UnionType:
-        if (structsAsPointers) {
-          return "Pointer<${dartType}> ${variableName}Pointer = nullptr;\n";
-        } else {
-          return "${dartType} ${variableName} = ${dartType}();\n";
-        }
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of Dart statements recursively allocating all members.
-  String dartAllocateStatements([String namePrefix = ""]) {
-    return map((m) => m.type.dartAllocateStatements("$namePrefix${m.name}"))
-        .join();
-  }
-
-  /// A list of Dart statements as zero or nullptr.
-  String dartAllocateZeroStatements(String namePrefix) {
-    return map((m) => m.type.dartAllocateZeroStatements("$namePrefix${m.name}"))
-        .join();
-  }
-}
-
-extension on CType {
-  /// A list of Dart statements recursively freeing all members.
-  String dartFreeStatements(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        return "";
-
-      case StructType:
-      case UnionType:
-        return "calloc.free(${variableName}Pointer);\n";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of Dart statements recursively freeing all members.
-  String dartFreeStatements([String namePrefix = ""]) {
-    return map((m) => m.type.dartFreeStatements("$namePrefix${m.name}")).join();
-  }
-}
-
-extension on CType {
-  /// A list of C statements recursively allocating all members.
-  String cAllocateStatements(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-      case StructType:
-      case UnionType:
-        return "${cType} ${variableName};\n";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of C statements recursively allocating all members.
-  String cAllocateStatements([String namePrefix = ""]) {
-    return map((m) => m.type.cAllocateStatements("$namePrefix${m.name}"))
-        .join();
-  }
-}
-
-extension on CType {
-  /// A list of Dart statements recursively checking all members.
-  String dartExpectsStatements(String expected, String actual) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        final this_ = this as FundamentalType;
-        if (this_.isInteger) {
-          return "Expect.equals(${expected}, ${actual});";
-        }
-        assert(this_.isFloatingPoint);
-        return "Expect.approxEquals(${expected}, ${actual});";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.dartExpectsStatements("$expected.", "$actual.");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        return """
-for (int i = 0; i < ${this_.length}; i++){
-  ${this_.elementType.dartExpectsStatements("$expected[i]", "$actual[i]")}
-}
-""";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of Dart statements recursively checking all members.
-  String dartExpectsStatements(
-      [String expectedPrefix = "", String actualPrefix = ""]) {
-    return map((m) => m.type.dartExpectsStatements(
-        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
-  }
-}
-
-extension on CType {
-  /// A list of C statements recursively checking all members.
-  String cExpectsStatements(String expected, String actual) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        final this_ = this as FundamentalType;
-        if (this_.isInteger) {
-          return "CHECK_EQ(${expected}, ${actual});";
-        }
-        assert(this_.isFloatingPoint);
-        return "CHECK_APPROX(${expected}, ${actual});";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.cExpectsStatements("$expected.", "$actual.");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        return """
-for (intptr_t i = 0; i < ${this_.length}; i++){
-  ${this_.elementType.cExpectsStatements("$expected[i]", "$actual[i]")}
-}
-""";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-
-  /// A list of C statements recursively checking all members for zero.
-  String cExpectsZeroStatements(String actual) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        final this_ = this as FundamentalType;
-        if (this_.isInteger) {
-          return "CHECK_EQ(0, ${actual});";
-        }
-        assert(this_.isFloatingPoint);
-        return "CHECK_APPROX(0.0, ${actual});";
-
-      case StructType:
-        final this_ = this as StructType;
-        return this_.members.cExpectsZeroStatements("$actual.");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        return """
-for (intptr_t i = 0; i < ${this_.length}; i++){
-  ${this_.elementType.cExpectsZeroStatements("$actual[i]")}
-}
-""";
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// A list of C statements recursively checking all members.
-  String cExpectsStatements(
-      [String expectedPrefix = "", String actualPrefix = ""]) {
-    return map((m) => m.type.cExpectsStatements(
-        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
-  }
-
-  /// A list of C statements recursively checking all members for zero.
-  String cExpectsZeroStatements([String actualPrefix = ""]) {
-    return map((m) => m.type.cExpectsZeroStatements("$actualPrefix${m.name}"))
-        .join();
-  }
-}
-
-extension on CType {
-  /// Expression denoting the first FundamentalType field.
-  ///
-  /// Both valid in Dart and C.
-  String firstArgumentName(String variableName) {
-    switch (this.runtimeType) {
-      case FundamentalType:
-        return variableName;
-
-      case StructType:
-      case UnionType:
-        final this_ = this as CompositeType;
-        return this_.members.firstArgumentName("$variableName.");
-
-      case FixedLengthArrayType:
-        final this_ = this as FixedLengthArrayType;
-        return this_.elementType.firstArgumentName("$variableName[0]");
-    }
-
-    throw Exception("Not implemented for ${this.runtimeType}");
-  }
-}
-
-extension on List<Member> {
-  /// Expression denoting the first FundamentalType field.
-  ///
-  /// Both valid in Dart and C.
-  String firstArgumentName([String prefix = ""]) {
-    return this[0].type.firstArgumentName("$prefix${this[0].name}");
-  }
-}
-
-extension on CompositeType {
-  String dartClass(bool nnbd) {
-    final self = this;
-    final packingAnnotation = (self is StructType) && self.hasPacking
-        ? "@Packed(${self.packing})"
-        : "";
-    String dartFields = "";
-    for (final member in members) {
-      dartFields += "${member.dartStructField(nnbd)}\n\n";
-    }
-    String toStringBody = members.map((m) {
-      if (m.type is FixedLengthArrayType) {
-        int dimensionNumber = 0;
-        String inlineFor = "";
-        String read = m.name;
-        String closing = "";
-        for (final dimension in (m.type as FixedLengthArrayType).dimensions) {
-          final i = "i$dimensionNumber";
-          inlineFor += "[for (var $i = 0; $i < $dimension; $i += 1)";
-          read += "[$i]";
-          closing += "]";
-          dimensionNumber++;
-        }
-        return "\$\{$inlineFor $read $closing\}";
-      }
-      return "\$\{${m.name}\}";
-    }).join(", ");
-    return """
-    $packingAnnotation
-    class $name extends $dartSuperClass {
-      $dartFields
-
-      String toString() => "($toStringBody)";
-    }
-    """;
-  }
-
-  String get cDefinition {
-    final self = this;
-    final packingPragmaPush = (self is StructType) && self.hasPacking
-        ? "#pragma pack(push, ${self.packing})"
-        : "";
-    final packingPragmaPop =
-        (self is StructType) && self.hasPacking ? "#pragma pack(pop)" : "";
-
-    String cFields = "";
-    for (final member in members) {
-      cFields += "  ${member.cStructField}\n";
-    }
-    return """
-    $packingPragmaPush
-    $cKeyword $name {
-      $cFields
-    };
-    $packingPragmaPop
-
-    """;
-  }
-}
-
-extension on FunctionType {
-  String dartCallCode({bool isLeaf: false}) {
-    final a = ArgumentValueAssigner();
-    final assignValues = arguments.assignValueStatements(a);
-    final argumentFrees = arguments.dartFreeStatements();
-
-    final argumentNames = arguments.map((e) => e.name).join(", ");
-
-    String expects;
-    switch (testType) {
-      case TestType.structArguments:
-        // Check against sum value.
-        final expectedResult = a.sumValue(returnValue as FundamentalType);
-        expects = returnValue.dartExpectsStatements(expectedResult, "result");
-        break;
-      case TestType.structReturn:
-        // Check against input arguments.
-        expects = arguments.dartExpectsStatements("", "result.");
-        break;
-      case TestType.structReturnArgument:
-        expects = returnValue.dartExpectsStatements(
-            structReturnArgument.name, "result");
-        break;
-    }
-
-    final namePostfix = isLeaf ? "Leaf" : "";
-    return """
-    final ${dartName}$namePostfix =
-      ffiTestFunctions.lookupFunction<$dartCType, $dartType>(
-          "$cName"${isLeaf ? ", isLeaf:true" : ""});
-
-    ${reason.makeDartDocComment()}
-    void ${dartTestName}$namePostfix() {
-      ${arguments.dartAllocateStatements()}
-
-      ${assignValues}
-
-      final result = ${dartName}$namePostfix($argumentNames);
-
-      print("result = \$result");
-
-      $expects
-
-      $argumentFrees
-    }
-    """;
-  }
-
-  String dartCallbackCode(bool nnbd) {
-    final argumentss =
-        arguments.map((a) => "${a.type.dartType} ${a.name}").join(", ");
-
-    final prints = arguments.map((a) => "\$\{${a.name}\}").join(", ");
-
-    bool structsAsPointers = false;
-    String assignReturnGlobal = "";
-    String buildReturnValue = "";
-    switch (testType) {
-      case TestType.structArguments:
-        // Sum all input values.
-        buildReturnValue = """
-        ${returnValue.dartType} result = 0;
-
-        ${arguments.addToResultStatements('${dartName}_')}
-        """;
-        assignReturnGlobal = "${dartName}Result = result;";
-        break;
-      case TestType.structReturn:
-        // Allocate a struct.
-        buildReturnValue = """
-        final resultPointer = calloc<${returnValue.dartType}>();
-        final result = resultPointer.ref;
-
-        ${arguments.copyValueStatements("${dartName}_", "result.")}
-        """;
-        assignReturnGlobal = "${dartName}ResultPointer = resultPointer;";
-        structsAsPointers = true;
-        break;
-      case TestType.structReturnArgument:
-        buildReturnValue = """
-        ${returnValue.cType} result = ${dartName}_${structReturnArgument.name};
-        """;
-        assignReturnGlobal = "${dartName}Result = result;";
-        break;
-    }
-
-    final globals = arguments.dartAllocateZeroStatements("${dartName}_");
-
-    final copyToGlobals =
-        arguments.map((a) => '${dartName}_${a.name} = ${a.name};').join("\n");
-
-    // Simulate assigning values the same way as in C, so that we know what the
-    // final return value should be.
-    final a = ArgumentValueAssigner();
-    arguments.assignValueStatements(a);
-    String afterCallbackExpects = "";
-    String afterCallbackFrees = "";
-    switch (testType) {
-      case TestType.structArguments:
-        // Check that the input structs are still available.
-        // Check against sum value.
-        final expectedResult = a.sumValue(returnValue as FundamentalType);
-        afterCallbackExpects =
-            returnValue.dartExpectsStatements(expectedResult, "result");
-        break;
-      case TestType.structReturn:
-        // We're passing allocating structs in [buildReturnValue].
-        afterCallbackFrees =
-            returnValue.dartFreeStatements("${dartName}Result");
-        break;
-      case TestType.structReturnArgument:
-        break;
-    }
-
-    String returnNull = "";
-    if (!nnbd) {
-      returnNull = """
-      if (${arguments.firstArgumentName()} == $returnNullValue) {
-        print("returning null!");
-        return null;
-      }
-      """;
-    }
-
-    return """
-    typedef ${cName}Type = $dartCType;
-
-    // Global variables to be able to test inputs after callback returned.
-    $globals
-
-    // Result variable also global, so we can delete it after the callback.
-    ${returnValue.dartAllocateZeroStatements("${dartName}Result", structsAsPointers: structsAsPointers)}
-
-    ${returnValue.dartType} ${dartName}CalculateResult() {
-      $buildReturnValue
-
-      $assignReturnGlobal
-
-      return result;
-    }
-
-    ${reason.makeDartDocComment()}
-    ${returnValue.dartType} $dartName($argumentss) {
-      print("$dartName($prints)");
-
-      // In legacy mode, possibly return null.
-      $returnNull
-
-      // In both nnbd and legacy mode, possibly throw.
-      if (${arguments.firstArgumentName()} == $throwExceptionValue ||
-          ${arguments.firstArgumentName()} == $returnNullValue) {
-        print("throwing!");
-        throw Exception("$cName throwing on purpose!");
-      }
-
-      $copyToGlobals
-
-      final result = ${dartName}CalculateResult();
-
-      print(\"result = \$result\");
-
-      return result;
-    }
-
-    void ${dartName}AfterCallback() {
-      $afterCallbackFrees
-
-      final result = ${dartName}CalculateResult();
-
-      print(\"after callback result = \$result\");
-
-      $afterCallbackExpects
-
-      $afterCallbackFrees
-    }
-
-    """;
-  }
-
-  String get dartCallbackTestConstructor {
-    String exceptionalReturn = "";
-    if (returnValue is FundamentalType) {
-      if ((returnValue as FundamentalType).isFloatingPoint) {
-        exceptionalReturn = ", 0.0";
-      } else {
-        exceptionalReturn = ", 0";
-      }
-    }
-    return """
-    CallbackTest.withCheck("$cName",
-      Pointer.fromFunction<${cName}Type>($dartName$exceptionalReturn),
-      ${dartName}AfterCallback),
-    """;
-  }
-
-  String get cCallCode {
-    String body = "";
-    switch (testType) {
-      case TestType.structArguments:
-        body = """
-        ${returnValue.cType} result = 0;
-
-        ${arguments.addToResultStatements()}
-        """;
-        break;
-      case TestType.structReturn:
-        body = """
-        ${returnValue.cType} result;
-
-        ${arguments.copyValueStatements("", "result.")}
-        """;
-        break;
-      case TestType.structReturnArgument:
-        body = """
-        ${returnValue.cType} result = ${structReturnArgument.name};
-        """;
-        break;
-    }
-
-    final argumentss =
-        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
-
-    return """
-    // Used for testing structs and unions by value.
-    ${reason.makeCComment()}
-    DART_EXPORT ${returnValue.cType} $cName($argumentss) {
-      std::cout << \"$cName\" ${arguments.coutExpression()} << \"\\n\";
-
-      $body
-
-      ${returnValue.coutStatement("result")}
-
-      return result;
-    }
-
-    """;
-  }
-
-  String get cCallbackCode {
-    final a = ArgumentValueAssigner();
-    final argumentAllocations = arguments.cAllocateStatements();
-    final assignValues = arguments.assignValueStatements(a);
-
-    final argumentss =
-        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
-
-    final argumentNames = arguments.map((e) => e.name).join(", ");
-
-    String expects = "";
-    String expectsZero = "";
-    switch (testType) {
-      case TestType.structArguments:
-        // Check against sum value.
-        final returnValue_ = returnValue as FundamentalType;
-        final expectedResult = a.sumValue(returnValue_);
-        expects = returnValue.cExpectsStatements(expectedResult, "result");
-
-        expectsZero = returnValue.cExpectsZeroStatements("result");
-        break;
-      case TestType.structReturn:
-        // Check against input statements.
-        expects = arguments.cExpectsStatements("", "result.");
-
-        expectsZero = arguments.cExpectsZeroStatements("result.");
-        break;
-      case TestType.structReturnArgument:
-        // Check against input struct fields.
-        expects =
-            returnValue.cExpectsStatements(structReturnArgument.name, "result");
-
-        expectsZero = returnValue.cExpectsZeroStatements("result");
-        break;
-    }
-
-    return """
-    // Used for testing structs and unions by value.
-    ${reason.makeCComment()}
-    DART_EXPORT intptr_t
-    Test$cName(
-        // NOLINTNEXTLINE(whitespace/parens)
-        ${returnValue.cType} (*f)($argumentss)) {
-      $argumentAllocations
-
-      $assignValues
-
-      std::cout << \"Calling Test$cName(\" ${arguments.coutExpression()} << \")\\n\";
-
-      ${returnValue.cType} result = f($argumentNames);
-
-      ${returnValue.coutStatement("result")}
-
-      $expects
-
-      // Pass argument that will make the Dart callback throw.
-      ${arguments.firstArgumentName()} = $throwExceptionValue;
-
-      result = f($argumentNames);
-
-      $expectsZero
-
-      // Pass argument that will make the Dart callback return null.
-      ${arguments.firstArgumentName()} = $returnNullValue;
-
-      result = f($argumentNames);
-
-      $expectsZero
-
-      return 0;
-    }
-
-    """;
-  }
-}
-
-/// Some value between 0 and 127 (works in every native type).
-const throwExceptionValue = 42;
-
-/// Some value between 0 and 127 (works in every native type).
-const returnNullValue = 84;
-
-const headerDartCallTest = """
-// Copyright (c) 2020, 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.
-//
-// This file has been automatically generated. Please do not edit it manually.
-//
-// SharedObjects=ffi_test_functions
-// VMOptions=
-// VMOptions=--deterministic --optimization-counter-threshold=5
-// VMOptions=--use-slow-path
-// VMOptions=--use-slow-path --stacktrace-every=100
-
-import 'dart:ffi';
-
-import "package:expect/expect.dart";
-import "package:ffi/ffi.dart";
-
-import 'dylib_utils.dart';
-
-final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
-""";
-
-void writeDartCallTest() {
-  for (bool nnbd in [true, false]) {
-    final StringBuffer buffer = StringBuffer();
-    buffer.write(headerDartCallTest);
-
-    buffer.write("""
-    void main() {
-      for (int i = 0; i < 10; ++i) {
-        ${functions.map((e) => "${e.dartTestName}();").join("\n")}
-        ${functions.map((e) => "${e.dartTestName}Leaf();").join("\n")}
-      }
-    }
-    """);
-    buffer.writeAll(compounds.map((e) => e.dartClass(nnbd)));
-    buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: false)));
-    buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: true)));
-
-    final path = callTestPath(nnbd);
-    File(path).writeAsStringSync(buffer.toString());
-    Process.runSync("dartfmt", ["-w", path]);
-  }
-}
-
-String callTestPath(bool nnbd) {
-  final folder = nnbd ? "ffi" : "ffi_2";
-  return Platform.script
-      .resolve("../../$folder/function_structs_by_value_generated_test.dart")
-      .path;
-}
-
-const headerDartCallbackTest = """
-// Copyright (c) 2020, 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.
-//
-// This file has been automatically generated. Please do not edit it manually.
-//
-// SharedObjects=ffi_test_functions
-// VMOptions=
-// VMOptions=--deterministic --optimization-counter-threshold=10
-// VMOptions=--use-slow-path
-// VMOptions=--use-slow-path --stacktrace-every=100
-
-import 'dart:ffi';
-
-import "package:expect/expect.dart";
-import "package:ffi/ffi.dart";
-
-import 'callback_tests_utils.dart';
-
-// Reuse the struct classes.
-import 'function_structs_by_value_generated_test.dart';
-
-
-void main() {
-  testCases.forEach((t) {
-    print("==== Running " + t.name);
-    t.run();
-  });
-}
-
-
-""";
-
-void writeDartCallbackTest() {
-  for (bool nnbd in [true, false]) {
-    final StringBuffer buffer = StringBuffer();
-    buffer.write(headerDartCallbackTest);
-
-    buffer.write("""
-  final testCases = [
-    ${functions.map((e) => e.dartCallbackTestConstructor).join("\n")}
-  ];
-  """);
-
-    buffer.writeAll(functions.map((e) => e.dartCallbackCode(nnbd)));
-
-    final path = callbackTestPath(nnbd);
-    File(path).writeAsStringSync(buffer.toString());
-    Process.runSync("dartfmt", ["-w", path]);
-  }
-}
-
-String callbackTestPath(bool nnbd) {
-  final folder = nnbd ? "ffi" : "ffi_2";
-  return Platform.script
-      .resolve(
-          "../../$folder/function_callbacks_structs_by_value_generated_test.dart")
-      .path;
-}
-
-const headerC = """
-// Copyright (c) 2020, 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.
-//
-// This file has been automatically generated. Please do not edit it manually.
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <cmath>
-#include <iostream>
-#include <limits>
-
-#if defined(_WIN32)
-#define DART_EXPORT extern "C" __declspec(dllexport)
-#else
-#define DART_EXPORT                                                            \\
-  extern "C" __attribute__((visibility("default"))) __attribute((used))
-#endif
-
-namespace dart {
-
-#define CHECK(X)                                                               \\
-  if (!(X)) {                                                                  \\
-    fprintf(stderr, "%s\\n", "Check failed: " #X);                              \\
-    return 1;                                                                  \\
-  }
-
-#define CHECK_EQ(X, Y) CHECK((X) == (Y))
-
-// Works for positive, negative and zero.
-#define CHECK_APPROX(EXPECTED, ACTUAL)                                         \\
-  CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \\
-        ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
-
-""";
-
-const footerC = """
-
-}  // namespace dart
-""";
-
-void writeC() {
-  final StringBuffer buffer = StringBuffer();
-  buffer.write(headerC);
-
-  buffer.writeAll(compounds.map((e) => e.cDefinition));
-  buffer.writeAll(functions.map((e) => e.cCallCode));
-  buffer.writeAll(functions.map((e) => e.cCallbackCode));
-
-  buffer.write(footerC);
-
-  File(ccPath).writeAsStringSync(buffer.toString());
-  Process.runSync("clang-format", ["-i", ccPath]);
-}
-
-final ccPath = Platform.script
-    .resolve("../../../runtime/bin/ffi_test/ffi_test_functions_generated.cc")
-    .path;
-
-void printUsage() {
-  print("""
-Generates structs by value tests.
-
-Generates:
-- $ccPath
-- ${callbackTestPath(true)}
-- ${callTestPath(true)}
-- ${callbackTestPath(false)}
-- ${callTestPath(false)}
-""");
-}
-
-void main(List<String> arguments) {
-  if (arguments.length != 0) {
-    printUsage();
-    return;
-  }
-
-  writeDartCallTest();
-  writeDartCallbackTest();
-  writeC();
-}
diff --git a/tests/ffi_2/generator/utils.dart b/tests/ffi_2/generator/utils.dart
deleted file mode 100644
index a1130cc..0000000
--- a/tests/ffi_2/generator/utils.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2020, 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.
-
-// @dart = 2.9
-
-extension TestGeneratorStringExtension on String {
-  String upperCaseFirst() => "${this[0].toUpperCase()}${this.substring(1)}";
-
-  String lowerCaseFirst() => "${this[0].toLowerCase()}${this.substring(1)}";
-
-  String makeCComment() => "// " + split("\n").join("\n// ");
-
-  String makeDartDocComment() => "/// " + split("\n").join("\n/// ");
-
-  String limitTo(int lenght) {
-    if (this.length > lenght) {
-      return substring(0, lenght);
-    }
-    return this;
-  }
-
-  String trimCouts() => replaceAll('" << "', '').replaceAll('"<< "', '');
-}
diff --git a/tests/language/constructor/tear_off_test.dart b/tests/language/constructor/tear_off_test.dart
new file mode 100644
index 0000000..f890b44
--- /dev/null
+++ b/tests/language/constructor/tear_off_test.dart
@@ -0,0 +1,229 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+import "package:expect/expect.dart";
+
+import "../static_type_helper.dart";
+
+// Test tearing off of constructors.
+
+// Non-generic classes.
+class NGen {
+  final int x;
+  const NGen(this.x);
+  const NGen.named(this.x);
+}
+
+class NGenRedir {
+  final int x;
+  const NGenRedir(int x) : this._(x);
+  const NGenRedir.named(int x) : this._(x);
+  const NGenRedir._(this.x);
+}
+
+class NFac {
+  final int x;
+  factory NFac(int x) => NFacRedir._(x);
+  factory NFac.named(int x) => NFacRedir._(x);
+  NFac._(this.x);
+}
+
+class NFacRedir {
+  final int x;
+  const factory NFacRedir(int x) = NFac._;
+  const factory NFacRedir.named(int x) = NFac._;
+  NFacRedir._(this.x);
+}
+
+// Generic classes.
+class GGen<T> {
+  final int x;
+  const GGen(this.x);
+  const GGen.named(this.x);
+}
+
+class GGenRedir<T> {
+  final int x;
+  const GGenRedir(int x) : this._(x);
+  const GGenRedir.named(int x) : this._(x);
+  const GGenRedir._(this.x);
+}
+
+class GFac<T> {
+  final int x;
+  factory GFac(int x) => GFacRedir._(x);
+  factory GFac.named(int x) => GFacRedir._(x);
+  GFac._(this.x);
+}
+
+class GFacRedir<T> {
+  final int x;
+  const factory GFacRedir(int x) = GFac._;
+  const factory GFacRedir.named(int x) = GFac._;
+  GFacRedir._(this.x);
+}
+
+class Optional<T> {
+  final int x;
+  final int y;
+  const Optional([this.x = 0, this.y = 0]);
+  const Optional.named({this.x = 0, this.y = 0});
+}
+
+void main() {
+  // Static types.
+  NGen.new.expectStaticType<Exactly<NGen Function(int)>>();
+  NGen.named.expectStaticType<Exactly<NGen Function(int)>>();
+  NGenRedir.new.expectStaticType<Exactly<NGenRedir Function(int)>>();
+  NGenRedir.named.expectStaticType<Exactly<NGenRedir Function(int)>>();
+  NFac.new.expectStaticType<Exactly<NFac Function(int)>>();
+  NFac.named.expectStaticType<Exactly<NFac Function(int)>>();
+  NFacRedir.new.expectStaticType<Exactly<NFacRedir Function(int)>>();
+  NFacRedir.named.expectStaticType<Exactly<NFacRedir Function(int)>>();
+
+  GGen.new.expectStaticType<Exactly<GGen<T> Function<T>(int)>>();
+  GGen.named.expectStaticType<Exactly<GGen<T> Function<T>(int)>>();
+  GGenRedir.new.expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
+  GGenRedir.named.expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
+  GFac.new.expectStaticType<Exactly<GFac<T> Function<T>(int)>>();
+  GFac.named.expectStaticType<Exactly<GFac<T> Function<T>(int)>>();
+  GFacRedir.new.expectStaticType<Exactly<GFacRedir<T> Function<T>(int)>>();
+  GFacRedir.named.expectStaticType<Exactly<GFacRedir<T> Function<T>(int)>>();
+
+  GGen<int>.new.expectStaticType<Exactly<GGen<int> Function(int)>>();
+  GGen<int>.named.expectStaticType<Exactly<GGen<int> Function(int)>>();
+  GGenRedir<int>.new
+      .expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
+  GGenRedir<int>.named
+      .expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
+  GFac<int>.new.expectStaticType<Exactly<GFac<int> Function(int)>>();
+  GFac<int>.named.expectStaticType<Exactly<GFac<int> Function(int)>>();
+  GFacRedir<int>.new
+      .expectStaticType<Exactly<GFacRedir<int> Function(int)>>();
+  GFacRedir<int>.named
+      .expectStaticType<Exactly<GFacRedir<int> Function(int)>>();
+
+  contextType<GGen<int> Function(int)>(
+      GGen.new..expectStaticType<Exactly<GGen<int> Function(int)>>());
+  contextType<GGen<int> Function(int)>(
+      GGen.named..expectStaticType<Exactly<GGen<int> Function(int)>>());
+  contextType<GGenRedir<int> Function(int)>(GGenRedir.new
+    ..expectStaticType<Exactly<GGenRedir<int> Function(int)>>());
+  contextType<GGenRedir<int> Function(int)>(GGenRedir.named
+    ..expectStaticType<Exactly<GGenRedir<int> Function(int)>>());
+  contextType<GFac<int> Function(int)>(
+      GFac.new..expectStaticType<Exactly<GFac<int> Function(int)>>());
+  contextType<GFac<int> Function(int)>(
+      GFac.named..expectStaticType<Exactly<GFac<int> Function(int)>>());
+  contextType<GFacRedir<int> Function(int)>(
+      GFacRedir.new..expectStaticType<Exactly<GFacRedir<int> Function(int)>>());
+  contextType<GFacRedir<int> Function(int)>(GFacRedir.named
+    ..expectStaticType<Exactly<GFacRedir<int> Function(int)>>());
+
+  contextType<Optional<int> Function()>(Optional.new
+    ..expectStaticType<Exactly<Optional<int> Function([int, int])>>());
+  contextType<Optional<int> Function()>(Optional.named
+    ..expectStaticType<Exactly<Optional<int> Function({int x, int y})>>());
+
+  // Check that tear-offs are canonicalized where possible
+  // (where not instantiates with a non-constant type).
+
+  void test<T>(Object? f1, [Object? same, Object? notSame]) {
+    Expect.type<T>(f1);
+    if (same != null) Expect.identical(f1, same);
+    if (notSame != null) Expect.notEquals(f1, notSame);
+  }
+
+  test<NGen Function(int)>(NGen.new, NGen.new, NGen.named);
+  test<NGen Function(int)>(NGen.named, NGen.named);
+  test<NGenRedir Function(int)>(NGenRedir.new, NGenRedir.new, NGenRedir.named);
+  test<NGenRedir Function(int)>(NGenRedir.named, NGenRedir.named);
+  test<NFac Function(int)>(NFac.new, NFac.new, NFac.named);
+  test<NFac Function(int)>(NFac.named, NFac.named);
+  test<NFacRedir Function(int)>(NFacRedir.new, NFacRedir.new, NFacRedir.named);
+  test<NFacRedir Function(int)>(NFacRedir.named, NFacRedir.named);
+
+  // Generic class constructors torn off as generic functions.
+  test<GGen<T> Function<T>(int)>(GGen.new, GGen.new, GGen.named);
+  test<GGen<T> Function<T>(int)>(GGen.named, GGen.named);
+  test<GGenRedir<T> Function<T>(int)>(
+      GGenRedir.new, GGenRedir.new, GGenRedir.named);
+  test<GGenRedir<T> Function<T>(int)>(GGenRedir.named, GGenRedir.named);
+  test<GFac<T> Function<T>(int)>(GFac.new, GFac.new, GFac.named);
+  test<GFac<T> Function<T>(int)>(GFac.named, GFac.named);
+  test<GFacRedir<T> Function<T>(int)>(
+      GFacRedir.new, GFacRedir.new, GFacRedir.named);
+  test<GFacRedir<T> Function<T>(int)>(GFacRedir.named, GFacRedir.named);
+
+  // Generic class constructors torn off with explicit instantiation
+  // to constant type.
+  test<GGen<int> Function(int)>(
+      GGen<int>.new, GGen<int>.new, GGen<int>.named);
+  test<GGen<int> Function(int)>(GGen<int>.named, GGen<int>.named);
+  test<GGenRedir<int> Function(int)>(
+      GGenRedir<int>.new, GGenRedir<int>.new, GGenRedir<int>.named);
+  test<GGenRedir<int> Function(int)>(
+      GGenRedir<int>.named, GGenRedir<int>.named);
+  test<GFac<int> Function(int)>(
+      GFac<int>.new, GFac<int>.new, GFac<int>.named);
+  test<GFac<int> Function(int)>(GFac<int>.named, GFac<int>.named);
+  test<GFacRedir<int> Function(int)>(
+      GFacRedir<int>.new, GFacRedir<int>.new, GFacRedir<int>.named);
+  test<GFacRedir<int> Function(int)>(
+      GFacRedir<int>.named, GFacRedir<int>.named);
+
+  // Not equal if *different* instantiations.
+  Expect.notEquals(GGen<int>.new, GGen<num>.new);
+  Expect.notEquals(GGen<int>.named, GGen<num>.named);
+  Expect.notEquals(GGenRedir<int>.new, GGenRedir<num>.new);
+  Expect.notEquals(GGenRedir<int>.named, GGenRedir<num>.named);
+  Expect.notEquals(GFac<int>.new, GFac<num>.new);
+  Expect.notEquals(GFac<int>.named, GFac<num>.named);
+  Expect.notEquals(GFacRedir<int>.new, GFacRedir<num>.new);
+  Expect.notEquals(GFacRedir<int>.named, GFacRedir<num>.named);
+
+  // Tear off with implicit instantiation to the same constant type.
+  void testImplicit<T>(T f1, T f2) {
+    Expect.identical(f1, f2);
+  }
+
+  testImplicit<GGen<int> Function(int)>(GGen.new, GGen.new);
+  testImplicit<GGen<int> Function(int)>(GGen.named, GGen.named);
+  testImplicit<GGenRedir<int> Function(int)>(GGenRedir.new, GGenRedir.new);
+  testImplicit<GGenRedir<int> Function(int)>(GGenRedir.named, GGenRedir.named);
+  testImplicit<GFac<int> Function(int)>(GFac.new, GFac.new);
+  testImplicit<GFac<int> Function(int)>(GFac.named, GFac.named);
+  testImplicit<GFacRedir<int> Function(int)>(GFacRedir.new, GFacRedir.new);
+  testImplicit<GFacRedir<int> Function(int)>(GFacRedir.named, GFacRedir.named);
+
+  // Using a type variable, not a constant type expression.
+  // Results are not canonicalized and not equal.
+  (<T>() {
+    // Tear off with explicit instantation to the same non-constant type.
+    Expect.notEquals(GGen<T>.new, GGen<T>.new);
+    Expect.notEquals(GGen<T>.named, GGen<T>.named);
+    Expect.notEquals(GGenRedir<T>.new, GGenRedir<T>.new);
+    Expect.notEquals(GGenRedir<T>.named, GGenRedir<T>.named);
+    Expect.notEquals(GFac<T>.new, GFac<T>.new);
+    Expect.notEquals(GFac<T>.named, GFac<T>.named);
+    Expect.notEquals(GFacRedir<T>.new, GFacRedir<T>.new);
+    Expect.notEquals(GFacRedir<T>.named, GFacRedir<T>.named);
+
+    // Tear off with implicit instantiation to the same non-constant type.
+    void testImplicit2<T>(T f1, T f2) {
+      Expect.notEquals(f1, f2);
+    }
+
+    testImplicit2<GGen<T> Function(int)>(GGen.new, GGen.new);
+    testImplicit2<GGen<T> Function(int)>(GGen.named, GGen.named);
+    testImplicit2<GGenRedir<T> Function(int)>(GGenRedir.new, GGenRedir.new);
+    testImplicit2<GGenRedir<T> Function(int)>(GGenRedir.named, GGenRedir.named);
+    testImplicit2<GFac<T> Function(int)>(GFac.new, GFac.new);
+    testImplicit2<GFac<T> Function(int)>(GFac.named, GFac.named);
+    testImplicit2<GFacRedir<T> Function(int)>(GFacRedir.new, GFacRedir.new);
+    testImplicit2<GFacRedir<T> Function(int)>(GFacRedir.named, GFacRedir.named);
+  }<int>());
+}
diff --git a/tests/language/constructor/unnamed_new_error_test.dart b/tests/language/constructor/unnamed_new_error_test.dart
new file mode 100644
index 0000000..0fec8bf
--- /dev/null
+++ b/tests/language/constructor/unnamed_new_error_test.dart
@@ -0,0 +1,123 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+import "package:expect/expect.dart";
+
+// Tests that `Classname.new` is allowed and works
+// only as an alias for the unnamed constructor.
+// It cannot be used to declare any other member.
+// It's not allowed as a reference if there is no unnamed constructor.
+
+// Not allowed without class prefix as constructor.
+class C1 {
+  const new();
+  //    ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class C2 {
+  factory new() => C2._();
+  //      ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+  C2._();
+}
+
+// Not allowed as normal member.
+class C3 {
+  int new() => 1;
+  //  ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class C4 {
+  int get new => 1;
+  //      ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+
+  void set new(int value) {}
+  //       ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class C5 {
+  int new = 1;
+  //  ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+// Not allowed as static member.
+class C6 {
+  static void new() {}
+  //          ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class C7 {
+  static int get new => 42;
+  //             ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+
+  static void set new(int x) {}
+  //              ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class C8 {
+  static int new = 1;
+  //         ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+// Not allowed as reference if there is no unnamed constructor.
+
+// Class with no unnamed constructor.
+class NoUnnamed<T> {
+  NoUnnamed.named();
+
+  NoUnnamed.genRedir() : this.new();
+  //                          ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+
+  factory NoUnnamed.facRedir() = NoUnnamed.new;
+  //                                       ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+
+  factory NoUnnamed.facRedir2() = NoUnnamed<T>.new;
+  //                                           ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+class SubNoUnnamed extends NoUnnamed<int> {
+  SubNoUnnamed() : super.new();
+  //                     ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
+
+void main() {
+  NoUnnamed.new();
+  //        ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+
+  NoUnnamed<int>.new();
+  //             ^^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
diff --git a/tests/language/constructor/unnamed_new_test.dart b/tests/language/constructor/unnamed_new_test.dart
new file mode 100644
index 0000000..a0ced5a6
--- /dev/null
+++ b/tests/language/constructor/unnamed_new_test.dart
@@ -0,0 +1,280 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+import "package:expect/expect.dart";
+
+import "unnamed_new_test.dart" as prefix;
+
+// Tests that `Classname.new` is allowed and works
+// as an alias for the unnamed constructor.
+
+// Constructor using `new` syntax.
+class New<T> {
+  final int x;
+  const New.new([this.x = 0]) : super.new();
+  const New.thisNew(int x) : this.new(x);
+  const New.thisNoNew(int x) : this(x);
+  const factory New.factoryNew(int x) = New<T>.new;
+  const factory New.factoryNoNew(int x) = New<T>;
+}
+
+class NewSub<T> extends New<T> {
+  const NewSub.new(); // Implicit `: super()`
+  const NewSub.implicit(); // Implicit `: super()`
+  const NewSub.superNew(int x) : super.new(x);
+  const NewSub.superNoNew(int x) : super(x);
+}
+
+// Same without `.new` on the constructor declaration.
+// Can still be referred to as `.new`.
+class NoNew<T> {
+  final int x;
+  const NoNew([this.x = 0]);
+  const NoNew.thisNew(int x) : this.new(x);
+  const NoNew.thisNoNew(int x) : this(x);
+  const factory NoNew.factoryNew(int x) = NoNew<T>.new;
+  const factory NoNew.factoryNoNew(int x) = NoNew<T>;
+}
+
+class NoNewSub<T> extends NoNew<T> {
+  const NoNewSub.new(); // Implicit `: super()`
+  const NoNewSub.implicit(); // Implicit `: super()`
+  const NoNewSub.superNew(int x) : super.new(x);
+  const NoNewSub.superNoNew(int x) : super(x);
+}
+
+// Avoid "unused value" warnings from the analyzer.
+void use(Object _) {}
+
+void main() {
+  use(const Object.new());
+  use(new Object.new());
+  use(Object.new());
+  use(const Symbol.new("a"));
+  use(new Symbol.new("a"));
+  use(Symbol.new("a"));
+
+  use(const New(1));
+  use(const New.new(1));
+  use(new New(1));
+  use(new New.new(1));
+  use(New(1));
+  use(New.new(1));
+
+  use(const New.thisNew(1));
+  use(const New.thisNoNew(1));
+  use(new New.thisNew(1));
+  use(new New.thisNoNew(1));
+  use(New.thisNew(1));
+  use(New.thisNoNew(1));
+
+  use(const New.factoryNew(1));
+  use(const New.factoryNoNew(1));
+  use(new New.factoryNew(1));
+  use(new New.factoryNoNew(1));
+  use(New.factoryNew(1));
+  use(New.factoryNoNew(1));
+
+  use(const NewSub.new());
+  use(const NewSub.implicit());
+  use(const NewSub.superNew(1));
+  use(const NewSub.superNoNew(1));
+
+  use(const New<int>(1));
+  use(const New<int>.new(1));
+  use(new New<int>(1));
+  use(new New<int>.new(1));
+  use(New<int>(1));
+  use(New<int>.new(1));
+
+  use(const New<int>.thisNew(1));
+  use(const New<int>.thisNoNew(1));
+  use(new New<int>.thisNew(1));
+  use(new New<int>.thisNoNew(1));
+  use(New<int>.thisNew(1));
+  use(New<int>.thisNoNew(1));
+
+  use(const New<int>.factoryNew(1));
+  use(const New<int>.factoryNoNew(1));
+  use(new New<int>.factoryNew(1));
+  use(new New<int>.factoryNoNew(1));
+  use(New<int>.factoryNew(1));
+  use(New<int>.factoryNoNew(1));
+
+  use(const NewSub<int>.new());
+  use(const NewSub<int>.implicit());
+  use(const NewSub<int>.superNew(1));
+  use(const NewSub<int>.superNoNew(1));
+
+  use(New.new);
+  use(New<int>.new);
+
+  use(const prefix.New(1));
+  use(const prefix.New.new(1));
+  use(new prefix.New(1));
+  use(new prefix.New.new(1));
+  use(prefix.New(1));
+  use(prefix.New.new(1));
+
+  use(const prefix.New.thisNew(1));
+  use(const prefix.New.thisNoNew(1));
+  use(new prefix.New.thisNew(1));
+  use(new prefix.New.thisNoNew(1));
+  use(prefix.New.thisNew(1));
+  use(prefix.New.thisNoNew(1));
+
+  use(const prefix.New.factoryNew(1));
+  use(const prefix.New.factoryNoNew(1));
+  use(new prefix.New.factoryNew(1));
+  use(new prefix.New.factoryNoNew(1));
+  use(prefix.New.factoryNew(1));
+  use(prefix.New.factoryNoNew(1));
+
+  use(const prefix.NewSub.new());
+  use(const prefix.NewSub.implicit());
+  use(const prefix.NewSub.superNew(1));
+  use(const prefix.NewSub.superNoNew(1));
+
+  use(const prefix.New<int>(1));
+  use(const prefix.New<int>.new(1));
+  use(new prefix.New<int>(1));
+  use(new prefix.New<int>.new(1));
+  use(prefix.New<int>(1));
+  use(prefix.New<int>.new(1));
+
+  use(const prefix.New<int>.thisNew(1));
+  use(const prefix.New<int>.thisNoNew(1));
+  use(new prefix.New<int>.thisNew(1));
+  use(new prefix.New<int>.thisNoNew(1));
+  use(prefix.New<int>.thisNew(1));
+  use(prefix.New<int>.thisNoNew(1));
+
+  use(const prefix.New<int>.factoryNew(1));
+  use(const prefix.New<int>.factoryNoNew(1));
+  use(new prefix.New<int>.factoryNew(1));
+  use(new prefix.New<int>.factoryNoNew(1));
+  use(prefix.New<int>.factoryNew(1));
+  use(prefix.New<int>.factoryNoNew(1));
+
+  use(const prefix.NewSub<int>.new());
+  use(const prefix.NewSub<int>.implicit());
+  use(const prefix.NewSub<int>.superNew(1));
+  use(const prefix.NewSub<int>.superNoNew(1));
+
+  use(prefix.New.new);
+  use(prefix.New<int>.new);
+
+  // Ditto for NoNew
+  use(const NoNew(1));
+  use(const NoNew.new(1));
+  use(new NoNew(1));
+  use(new NoNew.new(1));
+  use(NoNew(1));
+  use(NoNew.new(1));
+
+  use(const NoNew.thisNew(1));
+  use(const NoNew.thisNoNew(1));
+  use(new NoNew.thisNew(1));
+  use(new NoNew.thisNoNew(1));
+  use(NoNew.thisNew(1));
+  use(NoNew.thisNoNew(1));
+
+  use(const NoNew.factoryNew(1));
+  use(const NoNew.factoryNoNew(1));
+  use(new NoNew.factoryNew(1));
+  use(new NoNew.factoryNoNew(1));
+  use(NoNew.factoryNew(1));
+  use(NoNew.factoryNoNew(1));
+
+  use(const NoNewSub.new());
+  use(const NoNewSub.implicit());
+  use(const NoNewSub.superNew(1));
+  use(const NoNewSub.superNoNew(1));
+
+  use(const NoNew<int>(1));
+  use(const NoNew<int>.new(1));
+  use(new NoNew<int>(1));
+  use(new NoNew<int>.new(1));
+  use(NoNew<int>(1));
+  use(NoNew<int>.new(1));
+
+  use(const NoNew<int>.thisNew(1));
+  use(const NoNew<int>.thisNoNew(1));
+  use(new NoNew<int>.thisNew(1));
+  use(new NoNew<int>.thisNoNew(1));
+  use(NoNew<int>.thisNew(1));
+  use(NoNew<int>.thisNoNew(1));
+
+  use(const NoNew<int>.factoryNew(1));
+  use(const NoNew<int>.factoryNoNew(1));
+  use(new NoNew<int>.factoryNew(1));
+  use(new NoNew<int>.factoryNoNew(1));
+  use(NoNew<int>.factoryNew(1));
+  use(NoNew<int>.factoryNoNew(1));
+
+  use(const NoNewSub<int>.new());
+  use(const NoNewSub<int>.implicit());
+  use(const NoNewSub<int>.superNew(1));
+  use(const NoNewSub<int>.superNoNew(1));
+
+  use(NoNew.new);
+  use(NoNew<int>.new);
+
+  use(const prefix.NoNew(1));
+  use(const prefix.NoNew.new(1));
+  use(new prefix.NoNew(1));
+  use(new prefix.NoNew.new(1));
+  use(prefix.NoNew(1));
+  use(prefix.NoNew.new(1));
+
+  use(const prefix.NoNew.thisNew(1));
+  use(const prefix.NoNew.thisNoNew(1));
+  use(new prefix.NoNew.thisNew(1));
+  use(new prefix.NoNew.thisNoNew(1));
+  use(prefix.NoNew.thisNew(1));
+  use(prefix.NoNew.thisNoNew(1));
+
+  use(const prefix.NoNew.factoryNew(1));
+  use(const prefix.NoNew.factoryNoNew(1));
+  use(new prefix.NoNew.factoryNew(1));
+  use(new prefix.NoNew.factoryNoNew(1));
+  use(prefix.NoNew.factoryNew(1));
+  use(prefix.NoNew.factoryNoNew(1));
+
+  use(const prefix.NoNewSub.new());
+  use(const prefix.NoNewSub.implicit());
+  use(const prefix.NoNewSub.superNew(1));
+  use(const prefix.NoNewSub.superNoNew(1));
+
+  use(const prefix.NoNew<int>(1));
+  use(const prefix.NoNew<int>.new(1));
+  use(new prefix.NoNew<int>(1));
+  use(new prefix.NoNew<int>.new(1));
+  use(prefix.NoNew<int>(1));
+  use(prefix.NoNew<int>.new(1));
+
+  use(const prefix.NoNew<int>.thisNew(1));
+  use(const prefix.NoNew<int>.thisNoNew(1));
+  use(new prefix.NoNew<int>.thisNew(1));
+  use(new prefix.NoNew<int>.thisNoNew(1));
+  use(prefix.NoNew<int>.thisNew(1));
+  use(prefix.NoNew<int>.thisNoNew(1));
+
+  use(const prefix.NoNew<int>.factoryNew(1));
+  use(const prefix.NoNew<int>.factoryNoNew(1));
+  use(new prefix.NoNew<int>.factoryNew(1));
+  use(new prefix.NoNew<int>.factoryNoNew(1));
+  use(prefix.NoNew<int>.factoryNew(1));
+  use(prefix.NoNew<int>.factoryNoNew(1));
+
+  use(const prefix.NoNewSub<int>.new());
+  use(const prefix.NoNewSub<int>.implicit());
+  use(const prefix.NoNewSub<int>.superNew(1));
+  use(const prefix.NoNewSub<int>.superNoNew(1));
+
+  use(prefix.NoNew.new);
+  use(prefix.NoNew<int>.new);
+}
diff --git a/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart b/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart
new file mode 100644
index 0000000..8de7729
--- /dev/null
+++ b/tests/language/generic_methods/explicit_instantiated_tearoff_test.dart
@@ -0,0 +1,167 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+import "package:expect/expect.dart";
+
+import "../static_type_helper.dart";
+
+// Tests that generic methods can be torn off with explicit instantiation.
+
+R toplevel<R, T>(T value, [T? other]) => value as R;
+
+class C {
+  static R staticMethod<R, T>(T value, [T? other]) => value as R;
+  R instanceMethod<R, T>(T value, [T? other]) => value as R;
+
+  void tearOffsOnThis() {
+    const staticTearoff = staticMethod<int, String>;
+    staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    instanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    this.instanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+
+    Expect.identical(staticMethod<int, String>, staticTearOff);
+
+    Expect.equals(
+        instanceMethod<int, String>, this.instanceMethod<int, String>);
+  }
+}
+
+mixin M on C {
+  static R staticMethod<R, T>(T value, [T? other]) => value as R;
+  R mixinInstanceMethod<R, T>(T value, [T? other]) => value as R;
+
+  void mixinTearOffsOnThis() {
+    const staticTearoff = staticMethod<int, String>;
+    staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    mixinInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    this.mixinInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+
+    Expect.identical(staticMethod<int, String>, staticTearOff);
+
+    Expect.equals(
+        mixinInstanceMethod<int, String>,
+        this.mixinInstanceMethod<int, String>);
+  }
+}
+
+extension E on C {
+  static R staticMethod<R, T>(T value, [T? other]) => value as R;
+  R extInstanceMethod<R, T>(T value, [T? other]) => value as R;
+
+  void extenstionTearOffsOnThis() {
+    const staticTearoff = staticMethod<int, String>;
+    staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    extInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    this.extInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+
+    Expect.identical(staticMethod<int, String>, staticTearOff);
+
+    Expect.equals(
+        extInstanceMethod<int, String>, this.extInstanceMethod<int, String>);
+  }
+}
+
+class D extends C with M {
+  void tearOffsOnSuper() {
+    super.instanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+    Expect.equals(
+        super.instanceMethod<int, String>, super.instanceMethod<int, String>);
+  }
+}
+
+void main() {
+  var o = D();
+  R local<R, T>(T value, [T? other]) => value as R;
+
+  // Check that some tear-offs are constant.
+  const topTearoff = toplevel<int, String>;
+  const staticTearoff = C.staticMethod<int, String>;
+  const mixinStaticTearoff = M.staticMethod<int, String>;
+  const extensionStaticTearoff = E.staticMethod<int, String>;
+
+  // Check that the tear-offs have the correct static type.
+
+  toplevel<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  C
+      .staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  M
+      .staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  E
+      .staticMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  c
+      .instanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  c
+      .mixinInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  c
+      .extInstanceMethod<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+  local<int, String>
+      .expectStaticType<Exactly<int Function(String, [String?])>>();
+
+  // Check that the tear-offs are canonicalized where possible.
+  Expect.identical(toplevel<int, String>, topTearoff);
+  Expect.identical(C.staticMethod<int, String>, staticTearoff);
+  Expect.identical(M.staticMethod<int, String>, mixinStaticTearoff);
+  Expect.identical(E.staticMethod<int, String>, extensionStaticTearoff);
+
+  // Instantiated local methods may or may not be equal.
+  // (Specification makes no promise about equality.).
+
+  // But not for instance method tear-off.
+  // Specification requires equality.
+  Expect.equals(
+      o.instanceMethod<int, String>, o.instanceMethod<int, String>);
+  Expect.equals(
+      o.mixinInstanceMethod<int, String>, o.mixinInstanceMethod<int, String>);
+  Expect.equals(
+      o.extInstanceMethod<int, String>, o.extInstanceMethod<int, String>);
+
+  // And not canonicalized where they shouldn't (different types).
+  Expect.notEquals(toplevel<int, String>, toplevel<num, String>);
+  Expect.notEquals(
+      C.staticMethod<int, String>, C.staticMethod<num, String>);
+  Expect.notEquals(local<int, String>, local<num, String>);
+  Expect.notEquals(
+      o.instanceMethod<int, String>, o.instanceMethod<num, String>);
+
+  (<T>() {
+    // Not canonicalized if any type is non-constant.
+    // Toplevel, static and instance members are still equal
+    // if types are "the same".
+    // (Current implementations do not implement that).
+    Expect.equals(toplevel<T, String>, toplevel<T, String>);
+    Expect.equals(C.staticMethod<T, String>, C.staticMethod<T, String>);
+    Expect.equals(M.staticMethod<T, String>, M.staticMethod<T, String>);
+    Expect.equals(E.staticMethod<T, String>, E.staticMethod<T, String>);
+    Expect.notEquals(local<T, String>, local<T, String>);
+    Expect.equals(toplevel<int, T>, toplevel<int, T>);
+    Expect.equals(C.staticMethod<int, T>, C.staticMethod<int, T>);
+    Expect.equals(M.staticMethod<int, T>, M.staticMethod<int, T>);
+    Expect.equals(E.staticMethod<int, T>, E.staticMethod<int, T>);
+    Expect.notEquals(local<int, T>, local<int, T>);
+  }<int>());
+
+  o.tearOffsOnThis();
+  o.tearOffOnSuper();
+  o.mixinTearOffOnThis();
+  o.extensionTearOffOnThis();
+}
diff --git a/tests/language/type_object/explicit_instantiated_type_literal_error_test.dart b/tests/language/type_object/explicit_instantiated_type_literal_error_test.dart
new file mode 100644
index 0000000..af49363
--- /dev/null
+++ b/tests/language/type_object/explicit_instantiated_type_literal_error_test.dart
@@ -0,0 +1,31 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+// Tests that explicitly instantiated type objects only work
+// when instantiated correctly.
+
+class C<T extends num> {}
+
+void use(Type type) {}
+
+void main() {
+  use(C<Object>);
+  //  ^
+  // [cfe] Type argument 'Object' doesn't conform to the bound 'num' of the type variable 'T' on 'C'.
+  //    ^^^^^^
+  // [analyzer] unspecified
+
+  use(C<int, int>);
+  //  ^
+  // [cfe] Expected 1 type arguments.
+  //  ^
+  // [analyzer] unspecified
+
+  use(C<>);
+  //   ^^
+  // [cfe] unspecified
+  // [analyzer] unspecified
+}
diff --git a/tests/language/type_object/explicit_instantiated_type_literal_test.dart b/tests/language/type_object/explicit_instantiated_type_literal_test.dart
new file mode 100644
index 0000000..07fa243
--- /dev/null
+++ b/tests/language/type_object/explicit_instantiated_type_literal_test.dart
@@ -0,0 +1,53 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+import "package:expect/expect.dart";
+
+import "../static_type_helper.dart";
+
+import "explicit_instantiated_type_literal_test.dart" as prefix;
+
+// Tests that explicitly instantiated type objects work and are canonicalized
+// correctly.
+
+class C<T extends num> {}
+
+Type type<T>() => T;
+
+void main() {
+  C.expectStaticType<Type>();
+  C<int>.expectStaticType<Type>();
+
+  Expect.identical(C<num>, C);
+  Expect.identical(C<int>, C<int>);
+
+  Expect.equals(C<int>, type<C<int>>());
+
+  // Super-bounded types are valid.
+  Expect.identical(C<dynamic>, C<dynamic>);
+  Expect.equals(C<dynamic>, type<C<dynamic>>());
+
+  prefix.C.expectStaticType<Type>();
+  prefix.C<int>.expectStaticType<Type>();
+
+  Expect.identical(prefix.C<num>, prefix.C);
+  Expect.identical(prefix.C<int>, prefix.C<int>);
+
+  Expect.equals(prefix.C<int>, type<prefix.C<int>>());
+
+  // Super-bounded types are valid.
+  Expect.identical(prefix.C<dynamic>, prefix.C<dynamic>);
+  Expect.equals(prefix.C<dynamic>, type<prefix.C<dynamic>>());
+
+  Expect.identical(C<int>, prefix.C<int>);
+
+  (<T extends num>() {
+    Expect.notIdentical(C<T>, C<T>);
+    Expect.equals(C<T>, C<T>);
+    Expect.notIdentical(prefix.C<T>, prefix.C<T>);
+    Expect.equals(prefix.C<T>, prefix.C<T>);
+  }<int>());
+}
diff --git a/tests/language/typedef/aliased_constructor_tear_off_test.dart b/tests/language/typedef/aliased_constructor_tear_off_test.dart
new file mode 100644
index 0000000..e63b693
--- /dev/null
+++ b/tests/language/typedef/aliased_constructor_tear_off_test.dart
@@ -0,0 +1,231 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+// Tests that constructor tear-offs from type aliases work and
+// are canonicalized correctly
+
+import "package:expect/expect.dart";
+
+import "../static_type_helper.dart";
+
+void use(Type type) {}
+
+class C<T> {
+  final T value;
+  C(this.x);
+  C.named(this.x);
+}
+
+typedef Special = C<int>; // Not generic. Not proper rename.
+typedef Direct<T> = C<T>; // A proper rename
+typedef Bounded<T extends num> = C<T>; // Not proper rename.
+typedef Wrapping<T> = C<C<T>>; // Not proper rename.
+typedef Extra<T, S> = C<T>; // Not proper rename.
+
+class D<S, T> {
+  D();
+  D.named();
+}
+
+typedef Swapped<T, S> = D<S, T>; // Not a proper rename.
+
+void main() {
+  // Tear-offs are constant if uninstantiated
+  // or if instantiated with a constant type.
+  const List<Object> constructors = [
+    Special.new,
+    Spceial.named,
+    Direct.new,
+    Direct.named,
+    Bounded.new,
+    Bounded.named,
+    Wrapping.new,
+    Wrapping.named,
+    Extra.new,
+    Extra.named,
+    Direct<int>.new,
+    Direct<int>.named,
+    Bounded<int>.new,
+    Bounded<int>.named,
+    Wrapping<int>.new,
+    Wrapping<int>.named,
+    Extra<int, int>.new,
+    Extra<int, int>.named,
+    const <C<int> Function(int)>[
+      Direct.new,
+      Direct.named,
+      Bounded.new,
+      Bounded.named,
+    ],
+    const <C<C<int>> Function(C<int>)>[
+      Wrapping.new,
+      Wrapping.named,
+    ],
+    const <C<int, int> Function(C<int>)>[
+      Extra.new,
+      Extra.named,
+    ]
+  ];
+  Expect.notNull(constructors); // Use variable.
+
+  // The static type is as expected.
+
+  Special.new.expectStaticType<Exactly<C<int> Function(int)>>();
+  Special.named.expectStaticType<Exactly<C<int> Function(int)>>();
+
+  // Generic tear-off uses the generics of the type alias.
+  Direct.new.expectStaticType<Exactly<C<T> Function<T>(T)>>();
+  Direct.named.expectStaticType<Exactly<C<T> Function<T>(T)>>();
+
+  Bounded.new.expectStaticType<Exactly<C<T> Function<T extends num>(T)>>();
+  Bounded.named.expectStaticType<Exactly<C<T> Function<T extends num>(T)>>();
+
+  Wrapping.new.expectStaticType<Exactly<C<C<T>> Function<T>(T)>>();
+  Wrapping.named.expectStaticType<Exactly<C<C<T>> Function<T>(T)>>();
+
+  Extra.new.expectStaticType<Exactly<C<T> Function<T, S>(T)>>();
+  Extra.named.expectStaticType<Exactly<C<T> Function<T, S>(T)>>();
+
+  // Instantiated tear-off uses the instantiated aliased type.
+
+  // Explicitly instantiated.
+  Direct<int>.new.expectStaticType<Exactly<C<int> Function(int)>>();
+  Direct<int>.named.expectStaticType<Exactly<C<int> Function(int)>>();
+
+  Bounded<int>.new.expectStaticType<Exactly<C<int> Function(int)>>();
+  Bounded<int>.named.expectStaticType<Exactly<C<int> Function(int)>>();
+
+  Wrapping<int>.new.expectStaticType<Exactly<C<C<int>> Function(C<int>)>>();
+  Wrapping<int>.named.expectStaticType<Exactly<C<C<int>> Function(C<int>)>>();
+
+  Extra<int, String>.new.expectStaticType<Exactly<C<int> Function(int)>>();
+  Extra<int, String>.named.expectStaticType<Exactly<C<int> Function(int)>>();
+
+  // Implicitly instantiated.
+  contextType<C<int> Function(int)>(
+      Direct<int>.new..expectStaticType<Exactly<C<int> Function(int)>>());
+  contextType<C<int> Function(int)>(
+      Direct<int>.named..expectStaticType<Exactly<C<int> Function(int)>>());
+
+  contextType<C<int> Function(int)>(
+      Bounded<int>.new..expectStaticType<Exactly<C<int> Function(int)>>());
+  contextType<C<int> Function(int)>(
+      Bounded<int>.named..expectStaticType<Exactly<C<int> Function(int)>>());
+
+  contextType<C<C<int>> Function(C<int>)>(Wrapping<int>.new
+    ..expectStaticType<Exactly<C<C<int>> Function(C<int>)>>());
+  contextType<C<C<int>> Function(C<int>)>(Wrapping<int>.named
+    ..expectStaticType<Exactly<C<C<int>> Function(C<int>)>>());
+
+  contextType<C<int, String> Function(int)>(Extra<int, String>.new
+    ..expectStaticType<Exactly<C<int> Function(int)>>());
+  contextType<C<int, String> Function(int)>(Extra<int, String>.named
+    ..expectStaticType<Exactly<C<int> Function(int)>>());
+
+  // Uninstantiated tear-offs always canonicalize.
+  Expect.identical(Direct.new, Direct.new);
+  Expect.identical(Direct.named, Direct.named);
+  Expect.identical(Bounded.new, Bounded.new);
+  Expect.identical(Bounded.named, Bounded.named);
+  Expect.identical(Wrapping.new, Wrapping.new);
+  Expect.identical(Wrapping.named, Wrapping.named);
+  Expect.identical(Extra.new, Extra.new);
+  Expect.identical(Extra.named, Extra.named);
+
+  // Here the type is the same, and the alias is a proper rename.
+  Expect.identical(Direct.named, C.named);
+  Expect.identical(Direct.new, C.new);
+
+  // The next are unsurprising since the types are different.
+  Expect.notEquals(Bounded.named, C.named);
+  Expect.notEquals(Bounded.new, C.new);
+
+  Expect.notEquals(Wrapping.named, C.named);
+  Expect.notEquals(Wrapping.new, C.new);
+
+  Expect.notEquals(Extra.named, C.named);
+  Expect.notEquals(Extra.new, C.new);
+
+  Expect.notEquals(Swapped.new, D.new);
+  Expect.notEquals(Swapped.named, D.named);
+
+  // Instantiated alias tear-offs are canonicalized along with direct tear-offs
+  // when instantiation uses constant types.
+
+  // Explicit instantiation.
+  Expect.identical(Special.new, C<int>.new);
+  Expect.identical(Special.named, C<int>.named);
+
+  Expect.identical(Direct<int>.new, C<int>.new);
+  Expect.identical(Direct<int>.named, C<int>.named);
+  Expect.identical(Bounded<int>.new, C<int>.new);
+  Expect.identical(Bounded<int>.named, C<int>.named);
+  Expect.identical(Wrapping<int>.new, C<C<int>>.new);
+  Expect.identical(Wrapping<int>.named, C<C<int>>.named);
+  Expect.identical(Extra<int, String>.new, C<int>.new);
+  Expect.identical(Extra<int, String>.named, C<int>.named);
+  // And, since the second type parameter doesn't matter:
+  Expect.identical(Extra<int, String>.new, Extra<int, bool>.new);
+  Expect.identical(Extra<int, String>.named, Extra<int, bool>.named);
+
+  Expect.identical(Swapped<int, String>.new, D<String, int>.new);
+  Expect.identical(Swapped<int, String>.named, D<String, int>.named);
+
+  // Implicit instantiation.
+  Expect.identical(
+    contextType<C<int> Function(int)>(Direct.new),
+    C<int>.new,
+  );
+  Expect.identical(
+    contextType<C<int> Function(int)>(Direct.named),
+    C<int>.named,
+  );
+  Expect.identical(
+    contextType<C<int> Function(int)>(Bounded.new),
+    C<int>.new,
+  );
+  Expect.identical(
+    contextType<C<int> Function(int)>(Bounded.named),
+    C<int>.named,
+  );
+  Expect.identical(
+    contextType<C<C<int>> Function(C<int>)>(Wrapping.new),
+    C<C<int>>.new,
+  );
+  Expect.identical(
+    contextType<C<C<int>> Function(C<int>)>(Wrapping.named),
+    C<C<int>>.named,
+  );
+  Expect.identical(
+    contextType<D<int, String> Function()>(Swapped.new),
+    D<int, String>.new,
+  );
+  Expect.identical(
+    contextType<D<int, String> Function()>(Swapped.named),
+    D<int, String>.named,
+  );
+
+  (<T extends num>() {
+    // Non-constant type instantiation prevents canonicalization and equality.
+    // Also not constant.
+    Expect.notEquals(Direct<T>.new, Direct<T>.new);
+    Expect.notEquals(Direct<T>.named, Direct<T>.named);
+    Expect.notEquals(Bounded<T>.new, Bounded<T>.new);
+    Expect.notEquals(Bounded<T>.named, Bounded<T>.named);
+    Expect.notEquals(Wrapping<T>.new, Wrapping<T>.new);
+    Expect.notEquals(Wrapping<T>.named, Wrapping<T>.named);
+    Expect.notEquals(Extra<T, String>.new, Extra<T, String>.new);
+    Expect.notEquals(Extra<T, String>.named, Extra<T, String>.named);
+    // Also if the non-constant type doesn't occur in the expansion.
+    Expect.notEquals(Extra<int, T>.new, Extra<int, T>.new);
+    Expect.notEquals(Extra<int, T>.named, Extra<int, T>.named);
+
+    Expect.notEquals(Swapped<T, int>.new, Swapped<T, int>.new);
+    Expect.notEquals(Swapped<T, int>.named, Swapped<T, int>.named);
+    Expect.notEquals(Swapped<int, T>.new, Swapped<int, T>.new);
+    Expect.notEquals(Swapped<int, T>.named, Swapped<int, T>.named);
+  }<int>());
+}
diff --git a/tests/language/typedef/aliased_type_literal_instantiation_test.dart b/tests/language/typedef/aliased_type_literal_instantiation_test.dart
new file mode 100644
index 0000000..c99e904
--- /dev/null
+++ b/tests/language/typedef/aliased_type_literal_instantiation_test.dart
@@ -0,0 +1,65 @@
+// 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.
+
+// SharedOptions=--enable-experiment=constructor-tearoffs
+
+// Tests that type literals made from type aliases work and
+// are canonicalized correctly
+
+import "package:expect/expect.dart";
+
+class C<T> {
+  final T value;
+  C(this.x);
+  C.named(this.x);
+}
+
+typedef Special = C<int>; // Not generic.
+typedef Direct<T> = C<T>;
+typedef Bounded<T extends num> = C<T>;
+typedef Wrapping<T> = C<C<T>>;
+typedef Extra<T, S> = C<T>;
+
+void main() {
+  const Type co = C<Object?>;
+  const Type cn = C<num>;
+  const Type ci = C<int>;
+  const Type cco = C<C<Object?>>;
+  const Type cci = C<C<int>>;
+  const Type s1 = Special;
+  const Type d1 = Direct;
+  const Type d2 = Direct<Object?>;
+  const Type d3 = Direct<int>;
+  const Type b1 = Bounded;
+  const Type b2 = Bounded<num>;
+  const Type b3 = Bounded<int>;
+  const Type w1 = Wrapping;
+  const Type w2 = Wrapping<Object?>;
+  const Type w3 = Wrapping<int>;
+  const Type e1 = Extra;
+  const Type e2 = Extra<Object?, bool>;
+  const Type e3 = Extra<int, bool>;
+
+  Expect.identical(s1, ci);
+  Expect.identical(d1, co);
+  Expect.identical(d2, co);
+  Expect.identical(d3, ci);
+  Expect.identical(b1, cn);
+  Expect.identical(b2, cn);
+  Expect.identical(b3, ci);
+  Expect.identical(w1, cco);
+  Expect.identical(w2, cco);
+  Expect.identical(w3, cci);
+  Expect.identical(e1, co);
+  Expect.identical(e2, co);
+  Expect.identical(e3, ci);
+
+  (<T>() {
+    // Using a non-constant type.
+    Expect.equals(Direct<T>, ci);
+    Expect.equals(Bounded<T>, ci);
+    Expect.equals(Wrapping<T>, cci);
+    Expect.equals(Extra<T, bool>, ci);
+  }<int>());
+}
diff --git a/tools/VERSION b/tools/VERSION
index e371750..e65c72f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 201
+PRERELEASE 202
 PRERELEASE_PATCH 0
\ No newline at end of file