blob: cfce60ab2343730cbf851d8ede21d7ac9c7c6d10 [file] [log] [blame]
// Copyright (c) 2015, 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.
// Check that the `flatten` function is implemented and applied correctly
// when applied to interfaces that have `Future` as a superinterface.
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import '../static_type_helper.dart';
mixin Base {
noSuchMethod(Invocation invocation) {
if (const {
#then,
#catchError,
#whenComplete,
}.contains(invocation.memberName)) {
// Throw a sentinel value (using the receiver since it's available)
// when one of the `Future` callback methods is called.
throw this;
}
return super.noSuchMethod(invocation);
}
}
extension on Future<void> {
Future<void> ignoreError<T>() => then((_) => null, onError: (e) {
if (e is! T) throw e;
});
}
class Derived<T> = Object with Base implements Future<T>;
class FixedPoint<T> = Object with Base implements Future<FixedPoint<T>>;
class Divergent<T> = Object
with Base
implements Future<Divergent<Divergent<T>>>;
void main() async {
asyncStart();
// ----- Test the static types of await on the non-standard futures.
bool obscureFalse = DateTime.now().millisecondsSinceEpoch < 0;
if (obscureFalse) {
var x1 = await Derived<int>();
x1.expectStaticType<Exactly<int>>();
var x2 = await FixedPoint<int>();
x2.expectStaticType<Exactly<FixedPoint<int>>>();
var x3 = await Divergent<int>();
x3.expectStaticType<Exactly<Divergent<Divergent<int>>>>();
}
// ----- flatten(Derived<int>) == int.
try {
int x = await Derived<int>();
Expect.fail("Derived did not throw");
} on Derived {
// Expected throw.
}
Future<int> f1() async => Derived<int>();
// A non-standard future which implements `Future<int>` can be returned
// in an async function with return type `Future<int>`. It does not
// implement any members, so we need to ignore the dynamic error that
// occurs when any of its future callback methods is called.
f1().ignoreError<Derived>();
Future<int> f2() async {
return Derived<int>();
}
// Like the `f1` case, using a `{}` function.
f2().ignoreError<Derived>();
Future<int> x1 = (() async => Derived<int>())();
try {
await x1;
Expect.fail("Derived did not throw");
} on Derived {
// Expected throw.
}
// ----- flatten(FixedPoint<int>) == FixedPoint<int>.
try {
FixedPoint<int> x = await FixedPoint<int>();
Expect.fail("FixedPoint did not throw");
} on FixedPoint {
// Expected throw.
}
Future<FixedPoint<int>> f3() async => FixedPoint<int>();
f3().ignoreError<FixedPoint>();
Future<FixedPoint<int>> f4() async {
return FixedPoint<int>();
}
f4().ignoreError<FixedPoint>();
Future<FixedPoint<int>> x2 = (() async => FixedPoint<int>())();
try {
await x2;
Expect.fail("FixedPoint did not throw");
} on FixedPoint {
// Expected throw.
}
// ----- flatten(Divergent<int>) == Divergent<Divergent<int>>.
try {
Divergent<Divergent<int>> x = await Divergent<int>();
Expect.fail("Divergent did not throw");
} on Divergent {
// Expected throw.
}
Future<Divergent<Divergent<int>>> f5() async => Divergent<int>();
f5().ignoreError<Divergent>();
Future<Divergent<Divergent<int>>> f6() async {
return Divergent<int>();
}
f6().ignoreError<Divergent>();
Future<Divergent<Divergent<int>>> f7() async => Divergent<int>();
Future<Divergent<Divergent<int>>> x3 = f7();
try {
await x3;
Expect.fail("Divergent did not throw");
} on Divergent {
// Expected throw.
}
asyncEnd();
}