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