Make TypeError no longer implement AssertionError.

This means that TypeError no longer inherits a spurious `message` member.
The message of a platform-thrown TypeError is still available as `toString()`.

Fixes #40317

Bug: http://dartbug.com/40317
Change-Id: I77312859ebae3f92c2e56aeea6283b075b71c8d5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136129
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Erik Ernst <eernst@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4dc9ab3..ee707c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,14 @@
 
 ### Core libraries
 
+#### `dart:core`
+
+* The class `TypeError` no longer extends `AssertionError`.
+  This also means that it no longer inherits the spurious `message` getter
+  which was added to `AssertionError` when the second operand to `assert`
+  was allowed. The value of that getter on a `TypeError` was the same
+  string as returned by `toString`, so it is still available.
+
 #### `dart:html`
 
 * **Breaking Change**: Changed the return type of several html native methods
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 7bde8a2..6a7f637 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -1,6 +1,6 @@
 ERROR|COMPILE_TIME_ERROR|BODY_MAY_COMPLETE_NORMALLY|lib/_internal/js_runtime/lib/js_helper.dart|2688|17|17|The body might complete normally, which would cause 'null' to be returned, but the return type is a potentially non-nullable type.
-ERROR|COMPILE_TIME_ERROR|BODY_MAY_COMPLETE_NORMALLY|lib/_internal/js_runtime/lib/js_helper.dart|3632|5|11|The body might complete normally, which would cause 'null' to be returned, but the return type is a potentially non-nullable type.
-ERROR|COMPILE_TIME_ERROR|BODY_MAY_COMPLETE_NORMALLY|lib/_internal/js_runtime/lib/js_helper.dart|3660|5|6|The body might complete normally, which would cause 'null' to be returned, but the return type is a potentially non-nullable type.
+ERROR|COMPILE_TIME_ERROR|BODY_MAY_COMPLETE_NORMALLY|lib/_internal/js_runtime/lib/js_helper.dart|3628|5|11|The body might complete normally, which would cause 'null' to be returned, but the return type is a potentially non-nullable type.
+ERROR|COMPILE_TIME_ERROR|BODY_MAY_COMPLETE_NORMALLY|lib/_internal/js_runtime/lib/js_helper.dart|3656|5|6|The body might complete normally, which would cause 'null' to be returned, but the return type is a potentially non-nullable type.
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1637|7|5|Superinterfaces don't have a valid override for '&': int.& (int Function(int)), JSNumber.& (num Function(num)).
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1637|7|5|Superinterfaces don't have a valid override for '<<': int.<< (int Function(int)), JSNumber.<< (num Function(num)).
 ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1637|7|5|Superinterfaces don't have a valid override for '>>': int.>> (int Function(int)), JSNumber.>> (num Function(num)).
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
index 94ef1de..a6edb37 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -704,25 +704,22 @@
  */
 abstract class JavaScriptIndexingBehavior<E> {}
 
-// TODO(lrn): These exceptions should be implemented in core.
-// When they are, remove the 'Implementation' here.
-
 /// Thrown by type assertions that fail.
 class TypeErrorImpl extends Error implements TypeError {
-  final String message;
+  final String _message;
 
-  TypeErrorImpl(this.message);
+  TypeErrorImpl(this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 /// Thrown by the 'as' operator if the cast isn't valid.
 class CastErrorImpl extends Error implements CastError {
-  final String message;
+  final String _message;
 
-  CastErrorImpl(this.message);
+  CastErrorImpl(this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 class FallThroughErrorImplementation extends FallThroughError {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 4f332f4..548286b 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3087,34 +3087,30 @@
 /// visible to anyone, and is only injected into special libraries.
 abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
 
-// TODO(lrn): These exceptions should be implemented in core.
-// When they are, remove the 'Implementation' here.
-
 /// Thrown by type assertions that fail.
 class TypeErrorImplementation extends Error implements TypeError {
-  final String message;
+  final String _message;
 
   /// Normal type error caused by a failed subtype test.
   TypeErrorImplementation(Object value, String type)
-      : message = "TypeError: ${Error.safeToString(value)}: type "
+      : _message = "TypeError: ${Error.safeToString(value)}: type "
             "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
-  TypeErrorImplementation.fromMessage(String this.message);
+  TypeErrorImplementation.fromMessage(String this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 /// Thrown by the 'as' operator if the cast isn't valid.
 class CastErrorImplementation extends Error implements CastError {
-  // TODO(lrn): Rename to CastError (and move implementation into core).
-  final String message;
+  final String _message;
 
   /// Normal cast error caused by a failed type cast.
   CastErrorImplementation(Object value, Object type)
-      : message = "CastError: ${Error.safeToString(value)}: type "
+      : _message = "CastError: ${Error.safeToString(value)}: type "
             "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 String _typeDescription(value) {
diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart
index 24ca940..9457152 100644
--- a/sdk/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/errors_patch.dart
@@ -82,15 +82,19 @@
   final Object message;
 }
 
-class _TypeError extends _AssertionError implements TypeError {
+class _TypeError extends Error implements TypeError {
   @pragma("vm:entry-point")
-  _TypeError._create(String url, int line, int column, String errorMsg)
-      : super._create("is assignable", url, line, column, errorMsg);
+  _TypeError._create(this._url, this._line, this._column, this._message);
 
   static _throwNew(int location, Object src_value, _Type dst_type,
       String dst_name) native "TypeError_throwNew";
 
-  String toString() => super.message;
+  String toString() => _message;
+
+  final String _url;
+  final int _line;
+  final int _column;
+  final Object _message;
 }
 
 class _CastError extends Error implements CastError {
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 53692d4..bb12431 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -112,9 +112,9 @@
 }
 
 /**
- * Error thrown by the runtime system when a type assertion fails.
+ * Error thrown by the runtime system when a dynamic type error happens.
  */
-class TypeError extends AssertionError {}
+class TypeError extends Error {}
 
 /**
  * Error thrown by the runtime system when a cast operation fails.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
index 26c9db6..d084aeb 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -704,25 +704,22 @@
  */
 abstract class JavaScriptIndexingBehavior<E> {}
 
-// TODO(lrn): These exceptions should be implemented in core.
-// When they are, remove the 'Implementation' here.
-
 /// Thrown by type assertions that fail.
 class TypeErrorImpl extends Error implements TypeError {
-  final String message;
+  final String _message;
 
-  TypeErrorImpl(this.message);
+  TypeErrorImpl(this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 /// Thrown by the 'as' operator if the cast isn't valid.
 class CastErrorImpl extends Error implements CastError {
-  final String message;
+  final String _message;
 
-  CastErrorImpl(this.message);
+  CastErrorImpl(this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 class FallThroughErrorImplementation extends FallThroughError {
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
index 83302ec..ca5caab 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3086,34 +3086,30 @@
 /// visible to anyone, and is only injected into special libraries.
 abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
 
-// TODO(lrn): These exceptions should be implemented in core.
-// When they are, remove the 'Implementation' here.
-
 /// Thrown by type assertions that fail.
 class TypeErrorImplementation extends Error implements TypeError {
-  final String message;
+  final String _message;
 
   /// Normal type error caused by a failed subtype test.
   TypeErrorImplementation(Object value, String type)
-      : message = "TypeError: ${Error.safeToString(value)}: type "
+      : _message = "TypeError: ${Error.safeToString(value)}: type "
             "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
-  TypeErrorImplementation.fromMessage(String this.message);
+  TypeErrorImplementation.fromMessage(String this._message);
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 /// Thrown by the 'as' operator if the cast isn't valid.
 class CastErrorImplementation extends Error implements CastError {
-  // TODO(lrn): Rename to CastError (and move implementation into core).
-  final String message;
+  final String _message;
 
   /// Normal cast error caused by a failed type cast.
   CastErrorImplementation(Object value, Object type)
-      : message = "CastError: ${Error.safeToString(value)}: type "
+      : _message = "CastError: ${Error.safeToString(value)}: type "
             "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
-  String toString() => message;
+  String toString() => _message;
 }
 
 String _typeDescription(value) {
diff --git a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
index 4ce85be..c9dd54d 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
@@ -81,15 +81,19 @@
   final Object? message;
 }
 
-class _TypeError extends _AssertionError implements TypeError {
+class _TypeError extends Error implements TypeError {
   @pragma("vm:entry-point")
-  _TypeError._create(String url, int line, int column, String errorMsg)
-      : super._create("is assignable", url, line, column, errorMsg);
+  _TypeError._create(this._url, this._line, this._column, this._message);
 
   static _throwNew(int location, Object srcValue, _Type dstType, String dstName)
       native "TypeError_throwNew";
 
-  String toString() => super.message as String;
+  String toString() => _message;
+
+  final String _url;
+  final int _line;
+  final int _column;
+  final String _message;
 }
 
 class _CastError extends Error implements CastError {
diff --git a/sdk_nnbd/lib/core/errors.dart b/sdk_nnbd/lib/core/errors.dart
index 9445339..8a87c8b 100644
--- a/sdk_nnbd/lib/core/errors.dart
+++ b/sdk_nnbd/lib/core/errors.dart
@@ -110,9 +110,9 @@
 }
 
 /**
- * Error thrown by the runtime system when a type assertion fails.
+ * Error thrown by the runtime system when a dynamic type error happens.
  */
-class TypeError extends AssertionError {}
+class TypeError extends Error {}
 
 /**
  * Error thrown by the runtime system when a cast operation fails.
diff --git a/tests/language/assert/assert_test.dart b/tests/language/assert/assert_test.dart
index 85d0373..b99f5d6 100644
--- a/tests/language/assert/assert_test.dart
+++ b/tests/language/assert/assert_test.dart
@@ -8,7 +8,7 @@
 
 import "package:expect/expect.dart";
 
-testTrue() {
+int testTrue() {
   int i = 0;
   try {
     assert(true);
@@ -18,7 +18,7 @@
   return i;
 }
 
-testFalse() {
+int testFalse() {
   int i = 0;
   try {
     assert(false);
@@ -32,7 +32,7 @@
   return a ? true : false;
 }
 
-testBoolean(bool value) {
+int testBoolean(bool value) {
   int i = 0;
   try {
     assert(value);
@@ -42,7 +42,7 @@
   return i;
 }
 
-testDynamic(dynamic value) {
+int testDynamic(dynamic value) {
   int i = 0;
   try {
     assert(value);
@@ -56,11 +56,10 @@
   try {
     assert(value, message);
     return null;
-  } catch (error) {
-    // Catch any type to allow the Boolean conversion to throw either
-    // AssertionError or TypeError.
+  } on AssertionError catch (error) {
     return error;
   }
+  return null;
 }
 
 main() {
@@ -72,20 +71,20 @@
   Expect.equals(1, testBoolean(false));
   Expect.equals(1, testDynamic(unknown(false)));
 
-  Expect.equals(1, testDynamic(null));
-  Expect.equals(1, testDynamic(42));
-  Expect.equals(1, testDynamic(() => true));
-  Expect.equals(1, testDynamic(() => false));
-  Expect.equals(1, testDynamic(() => 42));
-  Expect.equals(1, testDynamic(() => null));
+  Expect.throwsTypeError(() => testDynamic(null));
+  Expect.throwsTypeError(() => testDynamic(42));
+  Expect.throwsTypeError(() => testDynamic(() => true));
+  Expect.throwsTypeError(() => testDynamic(() => false));
+  Expect.throwsTypeError(() => testDynamic(() => 42));
+  Expect.throwsTypeError(() => testDynamic(() => null));
 
   Expect.equals(1234, testMessage(false, 1234).message);
   Expect.equals('hi', testMessage(false, 'hi').message);
 
-  // These errors do not have the message because boolean conversion failed.
-  Expect.notEquals(1234, testMessage(null, 1234).message);
-  Expect.notEquals('hi', testMessage(null, 'hi').message);
-  Expect.notEquals('hi', testMessage(() => null, 'hi').message);
-  Expect.notEquals('hi', testMessage(() => false, 'hi').message);
-  Expect.notEquals('hi', testMessage(() => true, 'hi').message);
+  // These assertions throw a type error because boolean conversion failed.
+  Expect.throwsTypeError(() => testMessage(null, 1234));
+  Expect.throwsTypeError(() => testMessage(null, 'hi'));
+  Expect.throwsTypeError(() => testMessage(() => null, 'hi'));
+  Expect.throwsTypeError(() => testMessage(() => false, 'hi'));
+  Expect.throwsTypeError(() => testMessage(() => true, 'hi'));
 }
diff --git a/tests/language_2/assert/assert_test.dart b/tests/language_2/assert/assert_test.dart
index 162c270..0e12116 100644
--- a/tests/language_2/assert/assert_test.dart
+++ b/tests/language_2/assert/assert_test.dart
@@ -8,7 +8,7 @@
 
 import "package:expect/expect.dart";
 
-testTrue() {
+int testTrue() {
   int i = 0;
   try {
     assert(true);
@@ -18,7 +18,7 @@
   return i;
 }
 
-testFalse() {
+int testFalse() {
   int i = 0;
   try {
     assert(false);
@@ -28,11 +28,11 @@
   return i;
 }
 
-unknown(dynamic a) {
+dynamic unknown(dynamic a) {
   return a ? true : false;
 }
 
-testBoolean(bool value) {
+int testBoolean(bool value) {
   int i = 0;
   try {
     assert(value);
@@ -42,7 +42,7 @@
   return i;
 }
 
-testDynamic(dynamic value) {
+int testDynamic(dynamic value) {
   int i = 0;
   try {
     assert(value);
@@ -52,13 +52,13 @@
   return i;
 }
 
-testMessage(value, message) {
+AssertionError testMessage(value, message) {
   try {
     assert(value, message);
-    return null;
   } on AssertionError catch (error) {
     return error;
   }
+  return null;
 }
 
 main() {
@@ -70,13 +70,13 @@
   Expect.equals(1, testBoolean(false));
   Expect.equals(1, testDynamic(unknown(false)));
 
-  Expect.equals(1, testBoolean(null));
-  Expect.equals(1, testDynamic(null));
-  Expect.equals(1, testDynamic(42));
-  Expect.equals(1, testDynamic(() => true));
-  Expect.equals(1, testDynamic(() => false));
-  Expect.equals(1, testDynamic(() => 42));
-  Expect.equals(1, testDynamic(() => null));
+  Expect.throwsTypeError(() => testBoolean(null));
+  Expect.throwsTypeError(() => testDynamic(null));
+  Expect.throwsTypeError(() => testDynamic(42));
+  Expect.throwsTypeError(() => testDynamic(() => true));
+  Expect.throwsTypeError(() => testDynamic(() => false));
+  Expect.throwsTypeError(() => testDynamic(() => 42));
+  Expect.throwsTypeError(() => testDynamic(() => null));
 
   Expect.equals(1234, testMessage(false, 1234).message);
   Expect.equals('hi', testMessage(false, 'hi').message);
diff --git a/tests/language_2/unsorted/checked_method_error_order_test.dart b/tests/language_2/unsorted/checked_method_error_order_test.dart
index 04279f8..2d35087 100644
--- a/tests/language_2/unsorted/checked_method_error_order_test.dart
+++ b/tests/language_2/unsorted/checked_method_error_order_test.dart
@@ -20,7 +20,7 @@
     dynamic y = 3;
     Expect.throws(() => new Bar().foo(i: x, a: y), (e) {
       if (e is TypeError) {
-        var m = e.message.toString();
+        var m = e.toString();
         return m.contains("is not a subtype of type 'int'") ||
             m.contains(
                 "Expected a value of type 'int', but got one of type 'String'");