Fix null-safety issue in VM's typed-data + operators.

Fixes #45140.

Bug: http://dartbug.com/45140
Change-Id: I95f45c64d86428ddb67d176cdd2d50cfdbadfe8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188283
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/sdk/lib/_internal/vm/lib/typed_data_patch.dart b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
index d608ab6..b0c18d5 100644
--- a/sdk/lib/_internal/vm/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
@@ -150,13 +150,7 @@
     return -1;
   }
 
-  List<int> operator +(List<int> other) {
-    int totalLength = this.length + other.length;
-    return <int>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<int> operator +(List<int> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -506,13 +500,7 @@
     return -1;
   }
 
-  List<double> operator +(List<double> other) {
-    int totalLength = this.length + other.length;
-    return <double>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<double> operator +(List<double> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -868,13 +856,7 @@
     return -1;
   }
 
-  List<Float32x4> operator +(List<Float32x4> other) {
-    int totalLength = this.length + other.length;
-    return <Float32x4>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Float32x4> operator +(List<Float32x4> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -1228,13 +1210,7 @@
     return -1;
   }
 
-  List<Int32x4> operator +(List<Int32x4> other) {
-    int totalLength = this.length + other.length;
-    return <Int32x4>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Int32x4> operator +(List<Int32x4> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -1587,13 +1563,7 @@
     return -1;
   }
 
-  List<Float64x2> operator +(List<Float64x2> other) {
-    int totalLength = this.length + other.length;
-    return <Float64x2>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Float64x2> operator +(List<Float64x2> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
diff --git a/tests/lib/typed_data/regression_45140_test.dart b/tests/lib/typed_data/regression_45140_test.dart
new file mode 100644
index 0000000..864ce45
--- /dev/null
+++ b/tests/lib/typed_data/regression_45140_test.dart
@@ -0,0 +1,63 @@
+// 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.
+
+import 'dart:math' show Random;
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+void main() {
+  var r = Random();
+  int genInt() => r.nextInt(256);
+  double genDbl() => r.nextDouble();
+  Int32x4 genIx4() => Int32x4(genInt(), genInt(), genInt(), genInt());
+  Float32x4 genFx4() => Float32x4(genDbl(), genDbl(), genDbl(), genDbl());
+  Float64x2 genDx2() => Float64x2(genDbl(), genDbl());
+
+  test("Uint8List", (n) => Uint8List(n)..fill(genInt));
+  test("Uint16List", (n) => Uint16List(n)..fill(genInt));
+  test("Uint32List", (n) => Uint32List(n)..fill(genInt));
+  test("Int8List", (n) => Int8List(n)..fill(genInt));
+  test("Int16List", (n) => Int16List(n)..fill(genInt));
+  test("Int32List", (n) => Int32List(n)..fill(genInt));
+  test("Uint8ClampedList", (n) => Uint8ClampedList(n)..fill(genInt));
+  test("Float32List", (n) => Float32List(n)..fill(genDbl));
+  test("Float64List", (n) => Float64List(n)..fill(genDbl));
+  test("Int32x4List", (n) => Int32x4List(n)..fill(genIx4));
+  test("Float32x4List", (n) => Float32x4List(n)..fill(genFx4));
+  test("Float64x2List", (n) => Float64x2List(n)..fill(genDx2));
+}
+
+void test<T>(String name, List<T> create(int n)) {
+  var l1 = create(17);
+  var l2 = create(13);
+  List<T> l3;
+  try {
+    // Shouldn't throw:
+    l3 = l1 + l2;
+  } catch (e) {
+    // Until we change Expect.fail to return Never.
+    Expect.fail("$name: $e") as Never;
+  }
+  Expect.equals(30, l3.length);
+  if (0 is T || 0.0 is T) {
+    // Int32x4 etc. do not support `==`.
+    Expect.listEquals(l1, l3.sublist(0, 17), "$name first");
+    Expect.listEquals(l2, l3.sublist(17), "$name second");
+  }
+  // Result is growable, shouldn't throw.
+  try {
+    l3.add(l3.first);
+  } catch (e) {
+    Expect.fail("$name: $e");
+  }
+}
+
+// Fill a list with (random) generated values.
+extension<T> on List<T> {
+  void fill(T gen()) {
+    for (var i = 0; i < length; i++) {
+      this[i] = gen();
+    }
+  }
+}