[dart2wasm] Maintain types of `Error`s being thrown

Strictly speaking we do not promise the specific subtypes of
`Error` being thrown in the core libraries. The subtypes of
`Error` are there for better messages & debugging purposes.

Though some apps may rely on specific subtypes being thrown via
`try { ... } on IndexError {}`. So this CL changes our errors in
optimized mode to use the same `Error` subtype as in development
mode.

Though we do not expose details on the errors. Fields that expose
details will either return `null` or throw.

This makes various tests running under dart2wasm-minified mode
pass.

Issue https://github.com/dart-lang/sdk/issues/60397

Change-Id: Ie7be448b101473b18c2782457175ea163e71d5f6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435783
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/sdk/lib/_internal/wasm/lib/error_utils.dart b/sdk/lib/_internal/wasm/lib/error_utils.dart
index f2c8408..8e1dc1d 100644
--- a/sdk/lib/_internal/wasm/lib/error_utils.dart
+++ b/sdk/lib/_internal/wasm/lib/error_utils.dart
@@ -211,22 +211,20 @@
   throw ReachabilityError(_message);
 }
 
-const _indexErrorWithoutDetails = _ErrorWithoutDetails(
-  'IndexError (details omitted due to --minify)',
-);
-const _rangeErrorWithoutDetails = _ErrorWithoutDetails(
+const _indexErrorWithoutDetails = _IndexErrorWithoutDetails();
+const _rangeErrorWithoutDetails = _RangeErrorWithoutDetails(
   'RangeError (details omitted due to --minify)',
 );
-const _alignmentErrorWithoutDetails = _ErrorWithoutDetails(
+const _alignmentErrorWithoutDetails = _RangeErrorWithoutDetails(
   'Offset had incorrect alignment (details omitted due to --minify)',
 );
-const _negativeValueErrorWithoutDetails = _ErrorWithoutDetails(
+const _negativeValueErrorWithoutDetails = _RangeErrorWithoutDetails(
   'Value was negative (details omitted due to --minify)',
 );
-const _negativeOrZeroValueErrorWithoutDetails = _ErrorWithoutDetails(
+const _negativeOrZeroValueErrorWithoutDetails = _RangeErrorWithoutDetails(
   'Value was negative or zero (details omitted due to --minify)',
 );
-const _nullErrorWithoutDetails = _LateErrorWithoutDetails(
+const _nullErrorWithoutDetails = _ArgumentErrorWithoutDetails(
   'Value must not be null (details omitted due to --minify)',
 );
 
@@ -258,14 +256,13 @@
   'ReachabilityError (details omitted due to --minify)',
 );
 
-const _NoSuchMethodErrorWithoutDetails _noSuchMethodErrorWithoutDetails =
-    _NoSuchMethodErrorWithoutDetails();
+const _noSuchMethodErrorWithoutDetails = _NoSuchMethodErrorWithoutDetails();
 
-const _TypeErrorWithoutDetails typeErrorWithoutDetails =
-    _TypeErrorWithoutDetails();
+const typeErrorWithoutDetails = _TypeErrorWithoutDetails();
 
 class _ErrorWithoutDetails implements Error {
   final String _message;
+
   const _ErrorWithoutDetails(this._message);
 
   StackTrace? get stackTrace => null;
@@ -273,29 +270,68 @@
   String toString() => _message;
 }
 
-class _TypeErrorWithoutDetails implements TypeError {
-  const _TypeErrorWithoutDetails();
+class _ArgumentErrorWithoutDetails extends _ErrorWithoutDetails
+    implements ArgumentError {
+  const _ArgumentErrorWithoutDetails(String message) : super(message);
 
-  StackTrace? get stackTrace => null;
+  @override
+  String? get name => null;
 
-  String toString() =>
-      'Runtime type check failed (details omitted due to --minify)';
+  @override
+  String get message => toString();
+
+  @override
+  dynamic get invalidValue => null;
 }
 
-class _NoSuchMethodErrorWithoutDetails implements NoSuchMethodError {
-  const _NoSuchMethodErrorWithoutDetails();
+class _IndexErrorWithoutDetails extends _ArgumentErrorWithoutDetails
+    implements IndexError {
+  const _IndexErrorWithoutDetails()
+    : super('IndexError (details omitted due to --minify)');
 
-  StackTrace? get stackTrace => null;
+  @override
+  int get start => throw 'no details';
 
-  String toString() => 'NoSuchMethodError (details omitted due to --minify)';
+  @override
+  int get end => throw 'no details';
+
+  @override
+  int get length => throw 'no details';
+
+  @override
+  int get invalidValue => throw 'no details';
+
+  @override
+  Object? get indexable => null;
 }
 
-class _LateErrorWithoutDetails implements LateError {
-  final String _message;
+class _RangeErrorWithoutDetails extends _ArgumentErrorWithoutDetails
+    implements RangeError {
+  const _RangeErrorWithoutDetails(String message) : super(message);
 
-  const _LateErrorWithoutDetails(this._message);
+  @override
+  num? get start => null;
 
-  StackTrace? get stackTrace => null;
+  @override
+  num? get end => null;
 
-  String toString() => _message;
+  @override
+  num? get invalidValue => null;
+}
+
+class _TypeErrorWithoutDetails extends _ErrorWithoutDetails
+    implements TypeError {
+  const _TypeErrorWithoutDetails()
+    : super('Runtime type check failed (details omitted due to --minify)');
+}
+
+class _NoSuchMethodErrorWithoutDetails extends _ErrorWithoutDetails
+    implements NoSuchMethodError {
+  const _NoSuchMethodErrorWithoutDetails()
+    : super('NoSuchMethodError (details omitted due to --minify)');
+}
+
+class _LateErrorWithoutDetails extends _ErrorWithoutDetails
+    implements LateError {
+  const _LateErrorWithoutDetails(String message) : super(message);
 }