[vm/ffi] Fix mixin of _BoolArrayList

_BoolArrayList needs to extend FixedLengthListMixin instead of
UnmodifiableListMixin since it implements `operator []=`.

Also contains some other doc fixes that were brought up post-submit in
https://dart-review.googlesource.com/c/sdk/+/414821.

TEST=tests/ffi/array_primitive_elements_generated_test.dart

CoreLibraryReviewExempt: Dart VM only.
Bug: https://github.com/dart-lang/sdk/issues/45508
Change-Id: I7635152283aec51a4f38e06fdfc7da84e93e55ab
Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-arm64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-mac-debug-simarm64_arm64-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-arm64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-arm64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-tsan-linux-release-arm64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-arm64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417100
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Michael Goderbauer <goderbauer@google.com>
diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
index a498b8f..e73d39c 100644
--- a/runtime/tools/ffi/sdk_lib_ffi_generator.dart
+++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
@@ -106,7 +106,7 @@
 
 const header = """
 //
-// The following code is generated, do not edit by hand.
+// Generated code, do not edit!
 //
 // Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
 //
@@ -286,14 +286,23 @@
       buffer.write("""
 /// Bounds checking indexing methods on [Array]s of [$nativeType].
 $since extension ${nativeType}Array on Array<$nativeType> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external $dartType operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, $dartType value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external $elementsGetterReturnType get elements;
 }
@@ -406,7 +415,7 @@
   List<$dartType> get elements => _${nativeType}ArrayList(this);
 """;
         listHelperClass = """
-class _${nativeType}ArrayList with ListMixin<$dartType>, UnmodifiableListMixin<$dartType> {
+class _${nativeType}ArrayList with ListMixin<$dartType>, FixedLengthListMixin<$dartType> {
   _${nativeType}ArrayList(this._array);
 
   final Array<$nativeType> _array;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 87342a3..f3b0f09 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -657,7 +657,7 @@
 }
 
 //
-// The following code is generated, do not edit by hand.
+// Generated code, do not edit!
 //
 // Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
 //
@@ -1401,7 +1401,7 @@
   List<bool> get elements => _BoolArrayList(this);
 }
 
-class _BoolArrayList with ListMixin<bool>, UnmodifiableListMixin<bool> {
+class _BoolArrayList with ListMixin<bool>, FixedLengthListMixin<bool> {
   _BoolArrayList(this._array);
 
   final Array<Bool> _array;
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 80aa6c3..cd50033 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -492,7 +492,7 @@
 }
 
 //
-// The following code is generated, do not edit by hand.
+// Generated code, do not edit!
 //
 // Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
 //
@@ -1315,14 +1315,23 @@
 /// Bounds checking indexing methods on [Array]s of [Int8].
 @Since('2.13')
 extension Int8Array on Array<Int8> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Int8List get elements;
 }
@@ -1330,14 +1339,23 @@
 /// Bounds checking indexing methods on [Array]s of [Int16].
 @Since('2.13')
 extension Int16Array on Array<Int16> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Int16List get elements;
 }
@@ -1345,14 +1363,23 @@
 /// Bounds checking indexing methods on [Array]s of [Int32].
 @Since('2.13')
 extension Int32Array on Array<Int32> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Int32List get elements;
 }
@@ -1360,14 +1387,23 @@
 /// Bounds checking indexing methods on [Array]s of [Int64].
 @Since('2.13')
 extension Int64Array on Array<Int64> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Int64List get elements;
 }
@@ -1375,14 +1411,23 @@
 /// Bounds checking indexing methods on [Array]s of [Uint8].
 @Since('2.13')
 extension Uint8Array on Array<Uint8> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Uint8List get elements;
 }
@@ -1390,14 +1435,23 @@
 /// Bounds checking indexing methods on [Array]s of [Uint16].
 @Since('2.13')
 extension Uint16Array on Array<Uint16> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Uint16List get elements;
 }
@@ -1405,14 +1459,23 @@
 /// Bounds checking indexing methods on [Array]s of [Uint32].
 @Since('2.13')
 extension Uint32Array on Array<Uint32> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Uint32List get elements;
 }
@@ -1420,14 +1483,23 @@
 /// Bounds checking indexing methods on [Array]s of [Uint64].
 @Since('2.13')
 extension Uint64Array on Array<Uint64> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Uint64List get elements;
 }
@@ -1435,14 +1507,23 @@
 /// Bounds checking indexing methods on [Array]s of [Float].
 @Since('2.13')
 extension FloatArray on Array<Float> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external double operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, double value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Float32List get elements;
 }
@@ -1450,14 +1531,23 @@
 /// Bounds checking indexing methods on [Array]s of [Double].
 @Since('2.13')
 extension DoubleArray on Array<Double> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external double operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, double value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external Float64List get elements;
 }
@@ -1465,14 +1555,23 @@
 /// Bounds checking indexing methods on [Array]s of [Bool].
 @Since('2.15')
 extension BoolArray on Array<Bool> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external bool operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, bool value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external List<bool> get elements;
 }
@@ -2064,14 +2163,23 @@
 /// Bounds checking indexing methods on [Array]s of [Pointer].
 @Since('2.13')
 extension PointerArray<T extends NativeType> on Array<Pointer<T>> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external Pointer<T> operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, Pointer<T> value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external List<Pointer<T>> get elements;
 }
@@ -2116,7 +2224,8 @@
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external List<Array<T>> get elements;
 }
@@ -2124,14 +2233,23 @@
 /// Bounds checking indexing methods on [Array]s of [AbiSpecificInteger].
 @Since('2.16')
 extension AbiSpecificIntegerArray<T extends AbiSpecificInteger> on Array<T> {
+  /// Loads a Dart value from this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external int operator [](int index);
 
+  /// Stores a Dart value in this array at [index].
+  ///
+  /// This extension method must be invoked on a receiver of type `Array<T>`
+  /// where `T` is a compile-time constant type.
   external void operator []=(int index, int value);
 
   /// A list view of the bytes of this array.
   ///
   /// Has the same length and elements (as accessed using the index operator)
-  /// as this array, and writes to either the list or this arrary are visible in both.
+  /// as this array, and writes to either the list or this arrary are visible
+  /// in both.
   @Since('3.8')
   external List<int> get elements;
 }
diff --git a/tests/ffi/array_primitive_elements_generated_test.dart b/tests/ffi/array_primitive_elements_generated_test.dart
index dd9e283..f41e692 100644
--- a/tests/ffi/array_primitive_elements_generated_test.dart
+++ b/tests/ffi/array_primitive_elements_generated_test.dart
@@ -27,6 +27,7 @@
     testMallocedInt8ArrayElements();
     testWriteToInt8ArrayElementsBackedByTypedData();
     testWriteToInt8ArrayElementsBackedByPointer();
+    testInt8ArrayElementsFirstAndLast();
     testInt8ArrayElementsTypedDataListBackedByTypedData();
     testInt8ArrayElementsTypedDataListBackedByPointer();
     testInt16ArrayElements();
@@ -34,6 +35,7 @@
     testMallocedInt16ArrayElements();
     testWriteToInt16ArrayElementsBackedByTypedData();
     testWriteToInt16ArrayElementsBackedByPointer();
+    testInt16ArrayElementsFirstAndLast();
     testInt16ArrayElementsTypedDataListBackedByTypedData();
     testInt16ArrayElementsTypedDataListBackedByPointer();
     testInt16Misaligned();
@@ -42,6 +44,7 @@
     testMallocedInt32ArrayElements();
     testWriteToInt32ArrayElementsBackedByTypedData();
     testWriteToInt32ArrayElementsBackedByPointer();
+    testInt32ArrayElementsFirstAndLast();
     testInt32ArrayElementsTypedDataListBackedByTypedData();
     testInt32ArrayElementsTypedDataListBackedByPointer();
     testInt32Misaligned();
@@ -50,6 +53,7 @@
     testMallocedInt64ArrayElements();
     testWriteToInt64ArrayElementsBackedByTypedData();
     testWriteToInt64ArrayElementsBackedByPointer();
+    testInt64ArrayElementsFirstAndLast();
     testInt64ArrayElementsTypedDataListBackedByTypedData();
     testInt64ArrayElementsTypedDataListBackedByPointer();
     testInt64Misaligned();
@@ -58,6 +62,7 @@
     testMallocedUint8ArrayElements();
     testWriteToUint8ArrayElementsBackedByTypedData();
     testWriteToUint8ArrayElementsBackedByPointer();
+    testUint8ArrayElementsFirstAndLast();
     testUint8ArrayElementsTypedDataListBackedByTypedData();
     testUint8ArrayElementsTypedDataListBackedByPointer();
     testUint16ArrayElements();
@@ -65,6 +70,7 @@
     testMallocedUint16ArrayElements();
     testWriteToUint16ArrayElementsBackedByTypedData();
     testWriteToUint16ArrayElementsBackedByPointer();
+    testUint16ArrayElementsFirstAndLast();
     testUint16ArrayElementsTypedDataListBackedByTypedData();
     testUint16ArrayElementsTypedDataListBackedByPointer();
     testUint16Misaligned();
@@ -73,6 +79,7 @@
     testMallocedUint32ArrayElements();
     testWriteToUint32ArrayElementsBackedByTypedData();
     testWriteToUint32ArrayElementsBackedByPointer();
+    testUint32ArrayElementsFirstAndLast();
     testUint32ArrayElementsTypedDataListBackedByTypedData();
     testUint32ArrayElementsTypedDataListBackedByPointer();
     testUint32Misaligned();
@@ -81,6 +88,7 @@
     testMallocedUint64ArrayElements();
     testWriteToUint64ArrayElementsBackedByTypedData();
     testWriteToUint64ArrayElementsBackedByPointer();
+    testUint64ArrayElementsFirstAndLast();
     testUint64ArrayElementsTypedDataListBackedByTypedData();
     testUint64ArrayElementsTypedDataListBackedByPointer();
     testUint64Misaligned();
@@ -89,6 +97,7 @@
     testMallocedFloatArrayElements();
     testWriteToFloatArrayElementsBackedByTypedData();
     testWriteToFloatArrayElementsBackedByPointer();
+    testFloatArrayElementsFirstAndLast();
     testFloatArrayElementsTypedDataListBackedByTypedData();
     testFloatArrayElementsTypedDataListBackedByPointer();
     testFloatMisaligned();
@@ -97,6 +106,7 @@
     testMallocedDoubleArrayElements();
     testWriteToDoubleArrayElementsBackedByTypedData();
     testWriteToDoubleArrayElementsBackedByPointer();
+    testDoubleArrayElementsFirstAndLast();
     testDoubleArrayElementsTypedDataListBackedByTypedData();
     testDoubleArrayElementsTypedDataListBackedByPointer();
     testDoubleMisaligned();
@@ -105,11 +115,13 @@
     testMallocedBoolArrayElements();
     testWriteToBoolArrayElementsBackedByTypedData();
     testWriteToBoolArrayElementsBackedByPointer();
+    testBoolArrayElementsFirstAndLast();
     testWCharArrayElements();
     testWCharArrayBackedByInt64ListElements();
     testMallocedWCharArrayElements();
     testWriteToWCharArrayElementsBackedByTypedData();
     testWriteToWCharArrayElementsBackedByPointer();
+    testWCharArrayElementsFirstAndLast();
   }
 }
 
@@ -195,6 +207,17 @@
   malloc.free(struct);
 }
 
+void testInt8ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Int8ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testInt8ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Int8ArrayStruct>();
   final array = struct.array;
@@ -340,6 +363,17 @@
   malloc.free(struct);
 }
 
+void testInt16ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Int16ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testInt16ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Int16ArrayStruct>();
   final array = struct.array;
@@ -512,6 +546,17 @@
   malloc.free(struct);
 }
 
+void testInt32ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Int32ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testInt32ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Int32ArrayStruct>();
   final array = struct.array;
@@ -684,6 +729,17 @@
   malloc.free(struct);
 }
 
+void testInt64ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Int64ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testInt64ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Int64ArrayStruct>();
   final array = struct.array;
@@ -856,6 +912,17 @@
   malloc.free(struct);
 }
 
+void testUint8ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Uint8ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testUint8ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Uint8ArrayStruct>();
   final array = struct.array;
@@ -1001,6 +1068,17 @@
   malloc.free(struct);
 }
 
+void testUint16ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Uint16ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testUint16ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Uint16ArrayStruct>();
   final array = struct.array;
@@ -1173,6 +1251,17 @@
   malloc.free(struct);
 }
 
+void testUint32ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Uint32ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testUint32ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Uint32ArrayStruct>();
   final array = struct.array;
@@ -1345,6 +1434,17 @@
   malloc.free(struct);
 }
 
+void testUint64ArrayElementsFirstAndLast() {
+  final struct = Struct.create<Uint64ArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testUint64ArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<Uint64ArrayStruct>();
   final array = struct.array;
@@ -1517,6 +1617,17 @@
   malloc.free(struct);
 }
 
+void testFloatArrayElementsFirstAndLast() {
+  final struct = Struct.create<FloatArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100.0 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100.0 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testFloatArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<FloatArrayStruct>();
   final array = struct.array;
@@ -1689,6 +1800,17 @@
   malloc.free(struct);
 }
 
+void testDoubleArrayElementsFirstAndLast() {
+  final struct = Struct.create<DoubleArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100.0 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100.0 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 void testDoubleArrayElementsTypedDataListBackedByTypedData() {
   final struct = Struct.create<DoubleArrayStruct>();
   final array = struct.array;
@@ -1861,6 +1983,17 @@
   malloc.free(struct);
 }
 
+void testBoolArrayElementsFirstAndLast() {
+  final struct = Struct.create<BoolArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 3.isEven;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 4.isEven;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+
 final class WCharArrayStruct extends Struct {
   // Placeholder value before array to test the offset calculation logic.
   @Int8()
@@ -1942,3 +2075,14 @@
   Expect.listEquals(expected, actual);
   malloc.free(struct);
 }
+
+void testWCharArrayElementsFirstAndLast() {
+  final struct = Struct.create<WCharArrayStruct>();
+  final elements = struct.array.elements;
+  var value = 100 + 3;
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = 100 + 4;
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
diff --git a/tests/ffi/generator/array_primitive_elements_test_generator.dart b/tests/ffi/generator/array_primitive_elements_test_generator.dart
index 3a363ea..d6c850f 100644
--- a/tests/ffi/generator/array_primitive_elements_test_generator.dart
+++ b/tests/ffi/generator/array_primitive_elements_test_generator.dart
@@ -20,6 +20,7 @@
     buffer.write(testBackedByPointer(type));
     buffer.write(testWriteToElementsBackedByTypedData(type));
     buffer.write(testWriteToElementsBackedByPointer(type));
+    buffer.write(testElementsFirstAndLast(type));
     if (typedDataListTypes.contains(type)) {
       buffer.write(testElementsTypedDataListBackedByTypedData(type));
       buffer.write(testElementsTypedDataListBackedByPointer(type));
@@ -88,6 +89,8 @@
     'testWriteTo${type.dartCType}ArrayElementsBackedByTypedData';
 String testWriteToElementsBackedByPointerFunctionName(FundamentalType type) =>
     'testWriteTo${type.dartCType}ArrayElementsBackedByPointer';
+String testElementsFirstAndLastFunctionName(FundamentalType type) =>
+    'test${type.dartCType}ArrayElementsFirstAndLast';
 String testElementsTypedDataListBackedByTypedDataFunctionName(
   FundamentalType type,
 ) => 'test${type.dartCType}ArrayElementsTypedDataListBackedByTypedData';
@@ -108,6 +111,7 @@
       '${testBackedByPointerFunctionName(type)}();',
       '${testWriteToElementsBackedByTypedDataFunctionName(type)}();',
       '${testWriteToElementsBackedByPointerFunctionName(type)}();',
+      '${testElementsFirstAndLastFunctionName(type)}();',
       if (typedDataListTypes.contains(type)) ...[
         '${testElementsTypedDataListBackedByTypedDataFunctionName(type)}();',
         '${testElementsTypedDataListBackedByPointerFunctionName(type)}();',
@@ -232,6 +236,21 @@
 """;
 }
 
+String testElementsFirstAndLast(FundamentalType type) {
+  return """
+void ${testElementsFirstAndLastFunctionName(type)}() {
+  final struct = Struct.create<${structName(type)}>();
+  final elements = struct.array.elements;
+  var value = ${calculateArrayItem(type, '3')};
+  elements.first = value;
+  Expect.equals(value, elements.first);
+  value = ${calculateArrayItem(type, '4')};
+  elements.last = value;
+  Expect.equals(value, elements.last);
+}
+""";
+}
+
 String testElementsTypedDataListBackedByTypedData(FundamentalType type) {
   return """
 void ${testElementsTypedDataListBackedByTypedDataFunctionName(type)}() {