このAsyncError、AsyncErrorだけどAsyncErrorじゃない

```dart
import "dart:async";
import "package:riverpod/riverpod.dart";

Future<void> asyncTask1() async => print("async task 1");
Future<void> asyncTask2() async => throw Exception("exception sample");

Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError catch (e) {
    final (error1, error2) = e.errors;
    print(error2.runtimeType.toString());
    if (error2 is AsyncError) {
      print(error2.error);
    }
  }
}
```

このコードを実行してみましょう。

```
async task 1
AsyncError
```

と表示されるかと思います。`error2 is AsyncError`が通っていないのに、`error2.runtimeType`は`AsyncError`？？？？？

## ParallelWaitErrorの癖

`dart:async`における、`(a, b).wait`というメソッドは便利ですが、エラーハンドリングに癖があります。

```dart
Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError catch (e) {
    final (error1, error2) = e.errors;
    print(e.errors.runtimeType.toString());
    print(e.values.runtimeType.toString());
  }
}

```

この結果からわかるように、`ParallelWaitError`はジェネリクスを解決すると、`ParallelWaitError<(Null, Null), (AsyncError?, AsyncError?)>`という型であるとわかります。

つまり、エラーの値を取得するには、

```dart
import "dart:async";

Future<void> asyncTask1() async => print("async task 1");
Future<void> asyncTask2() async => throw Exception("exception sample");

Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError<dynamic, (AsyncError?, AsyncError?)> catch (e) {
    final (error1,error2) = e.errors;
    print(error1?.error);
    print(error2?.error);
  }
}
```
このように、`AsyncError`からさらに値を取得する必要があります。これであれば、

```dart
async task 1
null
Exception: exception sample
```

と出力されるので、期待通りエラーの結果が取得できました。

あらためて最初のコードに振り返りましょう。

```dart
import "dart:async";
import "package:riverpod/riverpod.dart";

Future<void> asyncTask1() async => print("async task 1");
Future<void> asyncTask2() async => throw Exception("exception sample");

Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError catch (e) {
    final (error1, error2) = e.errors;
    print(error2.runtimeType.toString());
    if (error2 is AsyncError) {
      print(error2.error);
    }
  }
}
```

うーん。動きそうなものですが。

## 実は…

実際のところ、簡潔に説明するためのコードなので最初の時点で気づく人は気付いていると思いますが…

```dart
import "dart:async";
import "package:riverpod/riverpod.dart";

Future<void> asyncTask1() async => print("async task 1");
Future<void> asyncTask2() async => throw Exception("exception sample");

Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError catch (error, stackTrace) {
    final (error1, error2) = error.errors;
    print(error2.runtimeType);
    print(error2.runtimeType.hashCode);
    
    final asyncError = AsyncError(error, stackTrace);
    print(asyncError.runtimeType);
    print(asyncError.runtimeType.hashCode);
    
  }
}
```

このコードを実行してみましょう。

```
async task 1
AsyncError
478785560
AsyncError<dynamic>
129899266
```

１つめのAsyncErrorと2つめのAsyncErrorは異なり、後者には`AsyncError<dynamic>`になっています。なぜ？

そう、これが落とし穴なのですが、

```dart
import "package:riverpod/riverpod.dart";
```

riverpodをインポートしています。そしてなんと、PararellWaitErrorが解決するAsyncErrorは、

[AsyncError implements Error(dart:async)](https://api.flutter.dev/flutter/dart-async/AsyncError/AsyncError.html)

なのですが、上記のコードでは

[AsyncError&lt;T&gt; extends AsyncValue&lt;T&gt; (riverpod) ](https://pub.dev/documentation/riverpod/latest/riverpod/AsyncError-class.html)

の`AsyncError`が優先されます。そんなあ。というか何事もなくビルド通って実行時エラーになったりすらしないんです。

というわけで上記のコードの本来の正解は、`dart:async`を使うために明示的に名前を設定して、

```dart
import "dart:async" as dart_async;
import "package:riverpod/riverpod.dart";

Future<void> asyncTask1() async => print("async task 1");
Future<void> asyncTask2() async => throw Exception("exception sample");

Future<void> main() async {
  try {
    await (asyncTask1(), asyncTask2()).wait;
  } on ParallelWaitError catch (e) {
    final (error1, error2) = e.errors;
    print(error2.runtimeType.toString());
    if (error2 is dart_async.AsyncError) {
      print(error2.error);
    }
  }
}
```

`dart_async.AsyncError`を明示することで、

```
async task 1
AsyncError
Exception: exception sample
```

期待通りの出力を得ることができました。riverpodはここでは使っていないので、Lintが未使用のインポートを警告するようにもなりました。 ~~これに3時間くらい費やしました~~

### 余談

これってパッケージシステムのセキュリティ的にどうなんでしょうね。悪意のあるパッケージが`dart:async`とかと同じ名前のクラスとかを定義できてしまったりしないんでしょうか…？