Version 2.10.0-57.0.dev

Merge commit 'ce494e791024936b30911bde38d6979fd458aece' into 'dev'
diff --git a/benchmarks/MD5/dart/md5.dart b/benchmarks/MD5/dart/md5.dart
new file mode 100644
index 0000000..30dd6d4
--- /dev/null
+++ b/benchmarks/MD5/dart/md5.dart
@@ -0,0 +1,37 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected = '6556112372898c69e1de0bf689d8db26';
+
+class MD5Bench extends BenchmarkBase {
+  List<int> data;
+
+  MD5Bench()
+      : data = List<int>.generate(size, (i) => i % 256, growable: false),
+        super('MD5');
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = md5.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  MD5Bench().report();
+}
diff --git a/benchmarks/MD5/dart2/md5.dart b/benchmarks/MD5/dart2/md5.dart
new file mode 100644
index 0000000..a65803d
--- /dev/null
+++ b/benchmarks/MD5/dart2/md5.dart
@@ -0,0 +1,40 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected = '6556112372898c69e1de0bf689d8db26';
+
+class MD5Bench extends BenchmarkBase {
+  List<int> data;
+
+  MD5Bench() : super('MD5') {
+    data = List<int>(size);
+    for (int i = 0; i < data.length; i++) {
+      data[i] = i % 256;
+    }
+  }
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = md5.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  MD5Bench().report();
+}
diff --git a/benchmarks/SHA1/dart/sha1.dart b/benchmarks/SHA1/dart/sha1.dart
new file mode 100644
index 0000000..713cb87
--- /dev/null
+++ b/benchmarks/SHA1/dart/sha1.dart
@@ -0,0 +1,37 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected = 'ecca46e1a1d0a6012713b09a870d84f695b6d9b0';
+
+class SHA1Bench extends BenchmarkBase {
+  List<int> data;
+
+  SHA1Bench()
+      : data = List<int>.generate(size, (i) => i % 256, growable: false),
+        super('SHA1');
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = sha1.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  SHA1Bench().report();
+}
diff --git a/benchmarks/SHA1/dart2/sha1.dart b/benchmarks/SHA1/dart2/sha1.dart
new file mode 100644
index 0000000..4ce65f5
--- /dev/null
+++ b/benchmarks/SHA1/dart2/sha1.dart
@@ -0,0 +1,40 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected = 'ecca46e1a1d0a6012713b09a870d84f695b6d9b0';
+
+class SHA1Bench extends BenchmarkBase {
+  List<int> data;
+
+  SHA1Bench() : super('SHA1') {
+    data = List<int>(size);
+    for (int i = 0; i < data.length; i++) {
+      data[i] = i % 256;
+    }
+  }
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = sha1.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  SHA1Bench().report();
+}
diff --git a/benchmarks/SHA256/dart/sha256.dart b/benchmarks/SHA256/dart/sha256.dart
new file mode 100644
index 0000000..83ae27d
--- /dev/null
+++ b/benchmarks/SHA256/dart/sha256.dart
@@ -0,0 +1,38 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected =
+    'dc404a613fedaeb54034514bc6505f56b933caa5250299ba7d094377a51caa46';
+
+class SHA256Bench extends BenchmarkBase {
+  List<int> data;
+
+  SHA256Bench()
+      : data = List<int>.generate(size, (i) => i % 256, growable: false),
+        super('SHA256');
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = sha256.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  SHA256Bench().report();
+}
diff --git a/benchmarks/SHA256/dart2/sha256.dart b/benchmarks/SHA256/dart2/sha256.dart
new file mode 100644
index 0000000..c138387
--- /dev/null
+++ b/benchmarks/SHA256/dart2/sha256.dart
@@ -0,0 +1,41 @@
+// 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.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+const size = 8 * 1024;
+const expected =
+    'dc404a613fedaeb54034514bc6505f56b933caa5250299ba7d094377a51caa46';
+
+class SHA256Bench extends BenchmarkBase {
+  List<int> data;
+
+  SHA256Bench() : super('SHA256') {
+    data = List<int>(size);
+    for (int i = 0; i < data.length; i++) {
+      data[i] = i % 256;
+    }
+  }
+
+  @override
+  void warmup() {
+    for (int i = 0; i < 4; i++) {
+      run();
+    }
+  }
+
+  @override
+  void run() {
+    final hash = sha256.convert(data);
+    if (hex.encode(hash.bytes) != expected) {
+      throw 'Incorrect HASH computed.';
+    }
+  }
+}
+
+void main() {
+  SHA256Bench().report();
+}
diff --git a/benchmarks/SkeletalAnimation/dart/SkeletalAnimation.dart b/benchmarks/SkeletalAnimation/dart/SkeletalAnimation.dart
new file mode 100644
index 0000000..adda3d3
--- /dev/null
+++ b/benchmarks/SkeletalAnimation/dart/SkeletalAnimation.dart
@@ -0,0 +1,33 @@
+// 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.
+
+/// A Dart implementation of two computation kernels used for skeletal
+/// animation.
+
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:vector_math/vector_math_operations.dart';
+
+void main() {
+  SkeletalAnimation().report();
+}
+
+class SkeletalAnimation extends BenchmarkBase {
+  SkeletalAnimation() : super('SkeletalAnimation');
+
+  final Float32List A = Float32List(16);
+  final Float32List B = Float32List(16);
+  final Float32List C = Float32List(16);
+  final Float32List D = Float32List(4);
+  final Float32List E = Float32List(4);
+
+  @override
+  void run() {
+    for (int i = 0; i < 100; i++) {
+      Matrix44Operations.multiply(C, 0, A, 0, B, 0);
+      Matrix44Operations.transform4(E, 0, A, 0, D, 0);
+    }
+  }
+}
diff --git a/benchmarks/SkeletalAnimation/dart2/SkeletalAnimation.dart b/benchmarks/SkeletalAnimation/dart2/SkeletalAnimation.dart
new file mode 100644
index 0000000..adda3d3
--- /dev/null
+++ b/benchmarks/SkeletalAnimation/dart2/SkeletalAnimation.dart
@@ -0,0 +1,33 @@
+// 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.
+
+/// A Dart implementation of two computation kernels used for skeletal
+/// animation.
+
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:vector_math/vector_math_operations.dart';
+
+void main() {
+  SkeletalAnimation().report();
+}
+
+class SkeletalAnimation extends BenchmarkBase {
+  SkeletalAnimation() : super('SkeletalAnimation');
+
+  final Float32List A = Float32List(16);
+  final Float32List B = Float32List(16);
+  final Float32List C = Float32List(16);
+  final Float32List D = Float32List(4);
+  final Float32List E = Float32List(4);
+
+  @override
+  void run() {
+    for (int i = 0; i < 100; i++) {
+      Matrix44Operations.multiply(C, 0, A, 0, B, 0);
+      Matrix44Operations.transform4(E, 0, A, 0, D, 0);
+    }
+  }
+}
diff --git a/benchmarks/SkeletalAnimationSIMD/dart/SkeletalAnimationSIMD.dart b/benchmarks/SkeletalAnimationSIMD/dart/SkeletalAnimationSIMD.dart
new file mode 100644
index 0000000..fc7727e
--- /dev/null
+++ b/benchmarks/SkeletalAnimationSIMD/dart/SkeletalAnimationSIMD.dart
@@ -0,0 +1,33 @@
+// 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.
+
+/// A Dart implementation of two computation kernels used for skeletal
+/// animation. SIMD version.
+
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:vector_math/vector_math_operations.dart';
+
+void main() {
+  SkeletalAnimationSIMD().report();
+}
+
+class SkeletalAnimationSIMD extends BenchmarkBase {
+  SkeletalAnimationSIMD() : super('SkeletalAnimationSIMD');
+
+  final Float32x4List A = Float32x4List(4);
+  final Float32x4List B = Float32x4List(4);
+  final Float32x4List C = Float32x4List(4);
+  final Float32x4List D = Float32x4List(1);
+  final Float32x4List E = Float32x4List(1);
+
+  @override
+  void run() {
+    for (int i = 0; i < 100; i++) {
+      Matrix44SIMDOperations.multiply(C, 0, A, 0, B, 0);
+      Matrix44SIMDOperations.transform4(E, 0, A, 0, D, 0);
+    }
+  }
+}
diff --git a/benchmarks/SkeletalAnimationSIMD/dart2/SkeletalAnimationSIMD.dart b/benchmarks/SkeletalAnimationSIMD/dart2/SkeletalAnimationSIMD.dart
new file mode 100644
index 0000000..fc7727e
--- /dev/null
+++ b/benchmarks/SkeletalAnimationSIMD/dart2/SkeletalAnimationSIMD.dart
@@ -0,0 +1,33 @@
+// 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.
+
+/// A Dart implementation of two computation kernels used for skeletal
+/// animation. SIMD version.
+
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:vector_math/vector_math_operations.dart';
+
+void main() {
+  SkeletalAnimationSIMD().report();
+}
+
+class SkeletalAnimationSIMD extends BenchmarkBase {
+  SkeletalAnimationSIMD() : super('SkeletalAnimationSIMD');
+
+  final Float32x4List A = Float32x4List(4);
+  final Float32x4List B = Float32x4List(4);
+  final Float32x4List C = Float32x4List(4);
+  final Float32x4List D = Float32x4List(1);
+  final Float32x4List E = Float32x4List(1);
+
+  @override
+  void run() {
+    for (int i = 0; i < 100; i++) {
+      Matrix44SIMDOperations.multiply(C, 0, A, 0, B, 0);
+      Matrix44SIMDOperations.transform4(E, 0, A, 0, D, 0);
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index 391b46b..1e68c39 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -152,16 +152,11 @@
   var file = message.filePath;
   var offset = message.offset;
   var length = message.length;
-  var startLine = -1;
-  var startColumn = -1;
-  var lineInfo = result.session.getFile(file).lineInfo;
-  if (lineInfo != null) {
-    CharacterLocation lineLocation = lineInfo.getLocation(offset);
-    if (lineLocation != null) {
-      startLine = lineLocation.lineNumber;
-      startColumn = lineLocation.columnNumber;
-    }
-  }
+
+  var lineLocation = result.lineInfo.getLocation(offset);
+  var startLine = lineLocation.lineNumber;
+  var startColumn = lineLocation.columnNumber;
+
   return DiagnosticMessage(
       message.message, Location(file, offset, length, startLine, startColumn));
 }
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index b0b3a9cc..19a3d5f 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -1348,8 +1348,9 @@
   DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
       DartType rightType, DartType currentType, MethodElement operatorElement) {
     if (isNonNullableByDefault) {
-      return _refineBinaryExpressionTypeNullSafe(
-          leftType, operator, rightType, currentType);
+      if (operatorElement == null) return currentType;
+      return _refineNumericInvocationTypeNullSafe(
+          leftType, operatorElement, [rightType], currentType);
     } else {
       return _refineBinaryExpressionTypeLegacy(
           leftType, operator, rightType, currentType);
@@ -1513,74 +1514,117 @@
     return currentType;
   }
 
-  DartType _refineBinaryExpressionTypeNullSafe(DartType leftType,
-      TokenType operator, DartType rightType, DartType currentType) {
-    if (leftType is TypeParameterType && leftType.bound.isDartCoreNum) {
-      if (rightType == leftType || rightType.isDartCoreInt) {
-        if (operator == TokenType.PLUS ||
-            operator == TokenType.MINUS ||
-            operator == TokenType.STAR ||
-            operator == TokenType.PLUS_EQ ||
-            operator == TokenType.MINUS_EQ ||
-            operator == TokenType.STAR_EQ ||
-            operator == TokenType.PLUS_PLUS ||
-            operator == TokenType.MINUS_MINUS) {
-          return promoteToNonNull(leftType as TypeImpl);
-        }
-      }
-      if (rightType.isDartCoreDouble) {
-        if (operator == TokenType.PLUS ||
-            operator == TokenType.MINUS ||
-            operator == TokenType.STAR ||
-            operator == TokenType.SLASH) {
-          InterfaceTypeImpl doubleType = typeProvider.doubleType;
-          return promoteToNonNull(doubleType);
-        }
-      }
-      return currentType;
-    }
-    // bool
-    if (operator == TokenType.AMPERSAND_AMPERSAND ||
-        operator == TokenType.BAR_BAR ||
-        operator == TokenType.EQ_EQ ||
-        operator == TokenType.BANG_EQ) {
-      return promoteToNonNull(typeProvider.boolType);
-    }
-    if (leftType.isDartCoreInt) {
-      // int op double
-      if (operator == TokenType.MINUS ||
-          operator == TokenType.PERCENT ||
-          operator == TokenType.PLUS ||
-          operator == TokenType.STAR ||
-          operator == TokenType.MINUS_EQ ||
-          operator == TokenType.PERCENT_EQ ||
-          operator == TokenType.PLUS_EQ ||
-          operator == TokenType.STAR_EQ) {
-        if (rightType.isDartCoreDouble) {
-          InterfaceTypeImpl doubleType = typeProvider.doubleType;
-          return promoteToNonNull(doubleType);
-        }
-      }
-      // int op int
-      if (operator == TokenType.MINUS ||
-          operator == TokenType.PERCENT ||
-          operator == TokenType.PLUS ||
-          operator == TokenType.STAR ||
-          operator == TokenType.TILDE_SLASH ||
-          operator == TokenType.MINUS_EQ ||
-          operator == TokenType.PERCENT_EQ ||
-          operator == TokenType.PLUS_EQ ||
-          operator == TokenType.STAR_EQ ||
-          operator == TokenType.TILDE_SLASH_EQ ||
-          operator == TokenType.PLUS_PLUS ||
-          operator == TokenType.MINUS_MINUS) {
-        if (rightType.isDartCoreInt) {
-          InterfaceTypeImpl intType = typeProvider.intType;
-          return promoteToNonNull(intType);
+  DartType _refineNumericInvocationTypeNullSafe(
+      DartType targetType,
+      MethodElement methodElement,
+      List<DartType> argumentTypes,
+      DartType currentType) {
+    // Let e be an expression of one of the forms e1 + e2, e1 - e2, e1 * e2,
+    // e1 % e2 or e1.remainder(e2)...
+    if (const {'+', '-', '*', '%', 'remainder'}.contains(methodElement.name)) {
+      // ...where the static type of e1 is a non-Never type T and T <: num...
+      // Notes:
+      // - We don't have to check for Never because if T is Never, the method
+      //   element will fail to resolve so we'll never reach here.
+      // - We actually check against `num?` rather than `num`.  It's equivalent
+      //   from the standpoint of correctness (since it's illegal to call these
+      //   methods on nullable types, and that's checked for elsewhere), but
+      //   better from the standpoint of error recovery (since it allows e.g.
+      //   `int? + int` to resolve to `int` rather than `num`).
+      var t = targetType;
+      assert(!t.isBottom);
+      var numType = typeProvider.numType;
+      var numTypeQuestion = makeNullable(numType as InterfaceTypeImpl);
+      if (isSubtypeOf(t, numTypeQuestion)) {
+        // ...and where the static type of e2 is S and S is assignable to num.
+        // (Note: we don't have to check that S is assignable to num because
+        // this is required by the signature of the method.)
+        if (argumentTypes.length == 1) {
+          var s = argumentTypes[0];
+          // Then:
+          // - If T <: double then the static type of e is double. This includes
+          //   S being dynamic or Never.
+          // (Note: as above, we check against `double?` because it's equivalent
+          // and leads to better error recovery.)
+          var doubleType = typeProvider.doubleType;
+          var doubleTypeQuestion =
+              makeNullable(doubleType as InterfaceTypeImpl);
+          if (isSubtypeOf(t, doubleTypeQuestion)) {
+            return doubleType;
+          }
+          // - If S <: double and not S <: Never, then the static type of e is
+          //   double.
+          // (Again, we check against `double?` for error recovery.)
+          if (!s.isBottom && isSubtypeOf(s, doubleTypeQuestion)) {
+            return doubleType;
+          }
+          // - If T <: int, S <: int and not S <: Never, then the static type of
+          //   e is int.
+          // (As above, we check against `int?` for error recovery.)
+          var intType = typeProvider.intType;
+          var intTypeQuestion = makeNullable(intType as InterfaceTypeImpl);
+          if (!s.isBottom &&
+              isSubtypeOf(t, intTypeQuestion) &&
+              isSubtypeOf(s, intTypeQuestion)) {
+            return intType;
+          }
+          // - Otherwise the static type of e is num.
+          return numType;
         }
       }
     }
-    // default
+    // Let e be a normal invocation of the form e1.clamp(e2, e3)...
+    if (methodElement.name == 'clamp') {
+      // ...where the static types of e1, e2 and e3 are T1, T2 and T3
+      // respectively...
+      var t1 = targetType;
+      if (argumentTypes.length == 2) {
+        var t2 = argumentTypes[0];
+        var t3 = argumentTypes[1];
+        // ...and where T1, T2, and T3 are all non-Never subtypes of num.
+        // (Note: we actually check against `num?` rather than `num`.  It's
+        // equivalent from the standpoint of correctness (since it's illegal to
+        // call `num.clamp` on a nullable type or to pass it a nullable type
+        // as an argument, and that's checked for elsewhere), but better from
+        // the standpoint of error recovery (since it allows e.g.
+        // `int?.clamp(int, int)` to resolve to `int` rather than `num`).
+        var numType = typeProvider.numType;
+        var numTypeQuestion = makeNullable(numType as InterfaceTypeImpl);
+        if (!t1.isBottom &&
+            isSubtypeOf(t1, numTypeQuestion) &&
+            !t2.isBottom &&
+            isSubtypeOf(t2, numTypeQuestion) &&
+            !t3.isBottom &&
+            isSubtypeOf(t3, numTypeQuestion)) {
+          // Then:
+          // - If T1, T2 and T3 are all subtypes of int, the static type of e is
+          //   int.
+          // (Note: as above, we check against `int?` because it's equivalent
+          // and leads to better error recovery.)
+          var intType = typeProvider.intType;
+          var intTypeQuestion = makeNullable(intType as InterfaceTypeImpl);
+          if (isSubtypeOf(t1, intTypeQuestion) &&
+              isSubtypeOf(t2, intTypeQuestion) &&
+              isSubtypeOf(t3, intTypeQuestion)) {
+            return intType;
+          }
+          // If T1, T2 and T3 are all subtypes of double, the static type of e
+          // is double.
+          // (As above, we check against `double?` for error recovery.)
+          var doubleType = typeProvider.doubleType;
+          var doubleTypeQuestion =
+              makeNullable(doubleType as InterfaceTypeImpl);
+          if (isSubtypeOf(t1, doubleTypeQuestion) &&
+              isSubtypeOf(t2, doubleTypeQuestion) &&
+              isSubtypeOf(t3, doubleTypeQuestion)) {
+            return doubleType;
+          }
+          // Otherwise the static type of e is num.
+          return numType;
+        }
+      }
+    }
+    // No special rules apply.
     return currentType;
   }
 }
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 7e2636a..fe58576 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -117,7 +117,13 @@
       currentClassElement,
       getterName,
     );
-    overriddenGetters ??= const [];
+    if (overriddenGetters != null) {
+      overriddenGetters = overriddenGetters.where((e) {
+        return e is PropertyAccessorElement && e.isGetter;
+      }).toList();
+    } else {
+      overriddenGetters = const [];
+    }
 
     var setterName = Name(elementLibraryUri, '$elementName=');
     var overriddenSetters = inheritance.getOverridden2(
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index 33ce9bf..482672b 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -2,7 +2,9 @@
 // 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 'package:analyzer/src/dart/error/hint_codes.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'context_collection_resolution.dart';
@@ -115,6 +117,91 @@
     );
   }
 
+  test_minus_int_double() async {
+    await assertNoErrorsInCode(r'''
+f(int a, double b) {
+  a - b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a - b'),
+      element: elementMatcher(
+        numElement.getMethod('-'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'double',
+    );
+  }
+
+  test_minus_int_int() async {
+    await assertNoErrorsInCode(r'''
+f(int a, int b) {
+  a - b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a - b'),
+      element: elementMatcher(
+        numElement.getMethod('-'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'int',
+    );
+  }
+
+  test_mod_int_double() async {
+    await assertNoErrorsInCode(r'''
+f(int a, double b) {
+  a % b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a % b'),
+      element: elementMatcher(
+        numElement.getMethod('%'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'double',
+    );
+  }
+
+  test_mod_int_int() async {
+    await assertNoErrorsInCode(r'''
+f(int a, int b) {
+  a % b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a % b'),
+      element: elementMatcher(
+        numElement.getMethod('%'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'int',
+    );
+  }
+
+  test_plus_double_dynamic() async {
+    await assertNoErrorsInCode(r'''
+f(double a, dynamic b) {
+  a + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: elementMatcher(
+        doubleElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'double',
+    );
+  }
+
   test_plus_int_double() async {
     await assertNoErrorsInCode(r'''
 f(int a, double b) {
@@ -132,6 +219,23 @@
     );
   }
 
+  test_plus_int_dynamic() async {
+    await assertNoErrorsInCode(r'''
+f(int a, dynamic b) {
+  a + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'num',
+    );
+  }
+
   test_plus_int_int() async {
     await assertNoErrorsInCode(r'''
 f(int a, int b) {
@@ -149,6 +253,124 @@
     );
   }
 
+  test_plus_int_int_target_rewritten() async {
+    await assertNoErrorsInCode('''
+f(int Function() a, int b) {
+  a() + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a() + b'),
+      element: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'int',
+    );
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/43114')
+  test_plus_int_int_via_extension_explicit() async {
+    await assertNoErrorsInCode('''
+extension E on int {
+  String operator+(int other) => '';
+}
+f(int a, int b) {
+  E(a) + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('E(a) + b'),
+      element: elementMatcher(
+        findElement.method('+', of: 'E'),
+        isLegacy: false,
+      ),
+      type: 'String',
+    );
+  }
+
+  test_plus_int_num() async {
+    await assertNoErrorsInCode(r'''
+f(int a, num b) {
+  a + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'num',
+    );
+  }
+
+  test_plus_other_double() async {
+    await assertNoErrorsInCode('''
+abstract class A {
+  String operator+(double other);
+}
+f(A a, double b) {
+  a + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: elementMatcher(
+        findElement.method('+', of: 'A'),
+        isLegacy: false,
+      ),
+      type: 'String',
+    );
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/43114')
+  test_plus_other_int_via_extension_explicit() async {
+    await assertNoErrorsInCode('''
+class A {}
+extension E on A {
+  String operator+(int other) => '';
+}
+f(A a, int b) {
+  E(a) + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('E(a) + b'),
+      element: elementMatcher(
+        findElement.method('+', of: 'E'),
+        isLegacy: false,
+      ),
+      type: 'String',
+    );
+  }
+
+  test_plus_other_int_via_extension_implicit() async {
+    await assertNoErrorsInCode('''
+class A {}
+extension E on A {
+  String operator+(int other) => '';
+}
+f(A a, int b) {
+  a + b;
+}
+''');
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: elementMatcher(
+        findElement.method('+', of: 'E'),
+        isLegacy: false,
+      ),
+      type: 'String',
+    );
+  }
+
   test_receiverTypeParameter_bound_dynamic() async {
     await assertNoErrorsInCode(r'''
 f<T extends dynamic>(T a) {
@@ -299,4 +521,32 @@
       type: 'int?',
     );
   }
+
+  test_plus_int_never() async {
+    await assertErrorsInCode('''
+f(int a, Never b) {
+  a + b;
+}
+''', []);
+
+    assertBinaryExpression(findNode.binary('a + b'),
+        element: numElement.getMethod('+'), type: 'num');
+  }
+
+  test_plus_never_int() async {
+    await assertErrorsInCode(r'''
+f(Never a, int b) {
+  a + b;
+}
+''', [
+      error(HintCode.RECEIVER_OF_TYPE_NEVER, 22, 1),
+      error(HintCode.DEAD_CODE, 26, 2),
+    ]);
+
+    assertBinaryExpression(
+      findNode.binary('a + b'),
+      element: isNull,
+      type: 'Never',
+    );
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
index 4cf9ec2..0ea4180 100644
--- a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -106,7 +106,7 @@
         numPlusElement,
         isLegacy: isNullSafetySdkAndLegacyLibrary,
       ),
-      type: 'num',
+      type: typeToStringWithNullability ? 'double' : 'num',
     );
     assertParameterElement(
       assignment.rightHandSide,
@@ -322,7 +322,7 @@
     assertAssignment(
       assignment,
       operatorElement: numPlusElement,
-      type: 'num?',
+      type: 'double?',
     );
     assertParameterElement(
       assignment.rightHandSide,
diff --git a/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart b/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
index a4d9df5..ac4be3b 100644
--- a/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
@@ -386,6 +386,20 @@
     _assertGetterTypeDynamic(foo);
   }
 
+  test_invalid_field_overrides_method() async {
+    await resolveTestCode('''
+abstract class A {
+  List<T> foo<T>() {}
+}
+
+class B implements A {
+  var foo = <String, int>{};
+}
+''');
+    var foo = findElement.field('foo', of: 'B');
+    _assertFieldType(foo, 'Map<String, int>');
+  }
+
   test_invalid_inheritanceCycle() async {
     await resolveTestCode('''
 class A extends C {}
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index dfd1530..1fa1328 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -34,6 +34,23 @@
     );
   }
 
+  test_inc_double() async {
+    await assertNoErrorsInCode(r'''
+f(double x) {
+  x++;
+}
+''');
+
+    assertPostfixExpression(
+      findNode.postfix('x++'),
+      element: elementMatcher(
+        doubleElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'double',
+    );
+  }
+
   test_inc_localVariable() async {
     await assertNoErrorsInCode(r'''
 f(int x) {
@@ -51,6 +68,23 @@
     );
   }
 
+  test_inc_num() async {
+    await assertNoErrorsInCode(r'''
+f(num x) {
+  x++;
+}
+''');
+
+    assertPostfixExpression(
+      findNode.postfix('x++'),
+      element: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'num',
+    );
+  }
+
   test_inc_property_differentTypes() async {
     await assertNoErrorsInCode(r'''
 int get x => 0;
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 2cb17f3..2900aa3 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -90,6 +90,23 @@
     );
   }
 
+  test_plusPlus_double() async {
+    await assertNoErrorsInCode(r'''
+f(double x) {
+  ++x;
+}
+''');
+
+    assertPrefixExpression(
+      findNode.prefix('++x'),
+      element: elementMatcher(
+        doubleElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'double',
+    );
+  }
+
   test_plusPlus_extensionOverride() async {
     await assertErrorsInCode(r'''
 class C {}
@@ -152,6 +169,23 @@
     );
   }
 
+  test_plusPlus_num() async {
+    await assertNoErrorsInCode(r'''
+f(num x) {
+  ++x;
+}
+''');
+
+    assertPrefixExpression(
+      findNode.prefix('++x'),
+      element: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'num',
+    );
+  }
+
   test_tilde_int_localVariable() async {
     await assertNoErrorsInCode(r'''
 f(int x) {
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index e6f5143..2c2acf8 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -858,11 +858,11 @@
     }
   }
 
-  _ElementMatcher _elementMatcher(Object elementOrMatcher) {
+  Matcher _elementMatcher(Object elementOrMatcher) {
     if (elementOrMatcher is Element) {
       return _ElementMatcher(this, declaration: elementOrMatcher);
     } else {
-      return elementOrMatcher;
+      return wrapMatcher(elementOrMatcher);
     }
   }
 
diff --git a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
index 1abf518..bf80618 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -3,6 +3,8 @@
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1514|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1516|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
 ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1676|28|1|The operator '&' isn't defined for the type 'JSInt'.
 ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1678|27|1|The operator '&' isn't defined for the type 'JSInt'.
 ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1681|17|1|The operator '&' isn't defined for the type 'JSInt'.
diff --git a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
index 004f021..b77ed3f 100644
--- a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
@@ -2,6 +2,9 @@
 ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|7913|5|97|Const constructors can't throw exceptions.
 ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|939|5|95|Const constructors can't throw exceptions.
 ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|972|5|94|Const constructors can't throw exceptions.
+ERROR|COMPILE_TIME_ERROR|INVALID_ASSIGNMENT|lib/_internal/js_dev_runtime/private/interceptors.dart|1348|18|27|A value of type 'double' can't be assigned to a variable of type 'int'.
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_dev_runtime/private/interceptors.dart|1215|14|38|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_dev_runtime/private/interceptors.dart|1217|14|38|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
 ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|3723|3|5|Only redirecting factory constructors can be declared to be 'const'.
 ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|7911|3|5|Only redirecting factory constructors can be declared to be 'const'.
 ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|937|3|5|Only redirecting factory constructors can be declared to be 'const'.
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index 930cd9a..37d7bb3 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -1125,7 +1125,7 @@
 }
 ''');
     var assignment = findNode.assignment('+=');
-    visitSubexpression(assignment, 'T',
+    visitSubexpression(assignment, 'num',
         changes: {assignment: isNullableSource});
   }
 
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index c30ee49..6ad304e 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -12,9 +12,9 @@
 #include <stdint.h>
 
 #include <fuchsia/deprecatedtimezone/cpp/fidl.h>
-#include <lib/async/default.h>
-#include <lib/async-loop/loop.h>
 #include <lib/async-loop/default.h>
+#include <lib/async-loop/loop.h>
+#include <lib/async/default.h>
 #include <lib/inspect/cpp/inspect.h>
 #include <lib/sys/cpp/component_context.h>
 #include <lib/sys/cpp/service_directory.h>
@@ -22,6 +22,7 @@
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/object.h>
+#include <zircon/time.h>
 #include <zircon/types.h>
 
 #include "platform/assert.h"
@@ -115,6 +116,15 @@
   return true;
 }
 
+int64_t GetCurrentTimeNanos() {
+  struct timespec ts;
+  if (timespec_get(&ts, TIME_UTC) == 0) {
+    FATAL("timespec_get failed");
+    return 0;
+  }
+  return zx_time_add_duration(ZX_SEC(ts.tv_sec), ZX_NSEC(ts.tv_nsec));
+}
+
 }  // namespace
 
 namespace dart {
@@ -177,21 +187,18 @@
 
 int OS::GetLocalTimeZoneAdjustmentInSeconds() {
   int32_t local_offset, dst_offset;
-  zx_time_t now = 0;
-  zx_clock_get(ZX_CLOCK_UTC, &now);
-  zx_status_t status = GetLocalAndDstOffsetInSeconds(
-      now / ZX_SEC(1), &local_offset, &dst_offset);
+  int64_t now_seconds = GetCurrentTimeNanos() / ZX_SEC(1);
+  zx_status_t status =
+      GetLocalAndDstOffsetInSeconds(now_seconds, &local_offset, &dst_offset);
   return status == ZX_OK ? local_offset : 0;
 }
 
 int64_t OS::GetCurrentTimeMillis() {
-  return GetCurrentTimeMicros() / 1000;
+  return GetCurrentTimeNanos() / ZX_MSEC(1);
 }
 
 int64_t OS::GetCurrentTimeMicros() {
-  zx_time_t now = 0;
-  zx_clock_get(ZX_CLOCK_UTC, &now);
-  return now / kNanosecondsPerMicrosecond;
+  return GetCurrentTimeNanos() / ZX_USEC(1);
 }
 
 int64_t OS::GetCurrentMonotonicTicks() {
diff --git a/tests/language/inference/dynamic_nullable_test.dart b/tests/language/inference/dynamic_nullable_test.dart
new file mode 100644
index 0000000..6bcb121
--- /dev/null
+++ b/tests/language/inference/dynamic_nullable_test.dart
@@ -0,0 +1,81 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+// Tests that inference can solve for T? ~ dynamic or void.
+
+class C<T extends Object> {
+  final T? value;
+  const C(this.value);
+  C.list(List<T?> list) : value = list.first;
+  void set nonNullValue(T value) {}
+}
+
+List<T> foo<T extends Object>(T? value) => [value!];
+
+List<T> bar<T extends Object>(List<T?> value) => [
+      for (var element in value)
+        if (element != null) element
+    ];
+
+extension Ext<T extends Object> on List<T?> {
+  List<T> whereNotNull() => [
+        for (var element in this)
+          if (element != null) element
+      ];
+}
+
+main() {
+  {
+    // Testing for dynamic.
+    const dynamic o = 42;
+
+    var c = const C(o);
+    var f = foo(o);
+    var l = [o].whereNotNull();
+
+    c.expectStaticType<Exactly<C<Object>>>();
+    Expect.type<C<Object>>(c); // Run-time type is subtype of C<Object>.
+    c.nonNullValue = Object(); // And supertype.
+
+    f.expectStaticType<Exactly<List<Object>>>();
+    Expect.type<List<Object>>(f); // Run-time type is subtype of List<Object>.
+    f[0] = Object(); // And supertype.
+
+    l.expectStaticType<Exactly<List<Object>>>();
+    Expect.type<List<Object>>(l); // Run-time type is subtype of List<Object>.
+    l[0] = Object(); // And supertype.
+  }
+
+  {
+    // Testing for void
+    List<void> o = <void>[42];
+
+    var c = C.list(o);
+    var f = bar(o);
+    var l = o.whereNotNull;
+
+    c.expectStaticType<Exactly<C<Object>>>();
+    Expect.type<C<Object>>(c); // Run-time type is subtype of C<Object>.
+    c.nonNullValue = Object(); // And supertype.
+
+    f.expectStaticType<Exactly<List<Object>>>();
+    Expect.type<List<Object>>(f); // Run-time type is subtype of List<Object>.
+    f[0] = Object(); // And supertype.
+
+    l.expectStaticType<Exactly<List<Object>>>();
+    Expect.type<List<Object>>(l); // Run-time type is subtype of List<Object>.
+    l[0] = Object(); // And supertype.
+  }
+}
+
+// Captures and checks static type of expression.
+extension TypeCheck<T> on T {
+  T expectStaticType<R extends Exactly<T>>() {
+    return this;
+  }
+}
+
+typedef Exactly<T> = T Function(T);
diff --git a/tools/VERSION b/tools/VERSION
index 6978f1f..befae4f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 56
+PRERELEASE 57
 PRERELEASE_PATCH 0
\ No newline at end of file