blob: ae46510b35db4a1404bea33b6aa47a1c956054fc [file] [log] [blame]
// Copyright (c) 2019, 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.
// Tests method signatures and return types for the `inout` variance modifier.
// SharedOptions=--enable-experiment=variance
import "package:expect/expect.dart";
typedef Cov<T> = T Function();
typedef Contra<T> = void Function(T);
Cov<int> covFunction = () => 2;
Contra<int> contraFunction = (int val) {};
Cov<num> covFunctionNum = () => 2;
Contra<num> contraFunctionNum = (num val) {};
class Covariant<out T> {}
class Contravariant<in T> {}
class Invariant<inout T> {}
class A<inout T> {
void method1(T x) {}
void method2(Cov<T> x) {}
Contra<T> method3() {
return (T val) {
Expect.equals(2, val);
};
}
T method4() => null;
void method5(Contra<T> x) {}
Cov<T> method6() {
return () => null;
}
T method7(T x) => x;
Contra<T> method8(Contra<T> x) => x;
Cov<T> method9(Cov<T> x) => x;
T method10<S extends T>(S x) => x;
void method11(Covariant<T> x) {}
Covariant<T> method12() => null;
void method13(Contravariant<T> x) {}
Contravariant<T> method14() => null;
void method15(Invariant<T> x) {}
Invariant<T> method16() => null;
void method17(covariant T x) {}
void method18(covariant Contra<T> x) {}
void method19(covariant Cov<T> x) {}
void method20(covariant Contravariant<T> x) {}
void method21(covariant Covariant<T> x) {}
void method22<S extends Contravariant<T>>() {}
void method23<S extends Covariant<T>>() {}
void method24<S extends Contra<T>>() {}
void method25<S extends Cov<T>>() {}
void method26({Contra<T> a, Cov<T> b, T c}) {}
void method27({Contravariant<T> a, Covariant<T> b}) {}
}
mixin BMixin<inout T> {
void method1(T x) {}
void method2(Cov<T> x) {}
Contra<T> method3() {
return (T val) {
Expect.equals(2, val);
};
}
T method4() => null;
void method5(Contra<T> x) {}
Cov<T> method6() {
return () => null;
}
T method7(T x) => x;
Contra<T> method8(Contra<T> x) => x;
Cov<T> method9(Cov<T> x) => x;
T method10<S extends T>(S x) => x;
void method11(Covariant<T> x) {}
Covariant<T> method12() => null;
void method13(Contravariant<T> x) {}
Contravariant<T> method14() => null;
void method15(Invariant<T> x) {}
Invariant<T> method16() => null;
void method17(covariant T x) {}
void method18(covariant Contra<T> x) {}
void method19(covariant Cov<T> x) {}
void method20(covariant Contravariant<T> x) {}
void method21(covariant Covariant<T> x) {}
void method22<S extends Contravariant<T>>() {}
void method23<S extends Covariant<T>>() {}
void method24<S extends Contra<T>>() {}
void method25<S extends Cov<T>>() {}
void method26({Contra<T> a, Cov<T> b, T c}) {}
void method27({Contravariant<T> a, Covariant<T> b}) {}
}
class B with BMixin<num> {}
class C<inout T> {
void method1(Contra<A<T>> x) {}
void method2(Cov<A<T>> x) {}
A<T> method3() {
return A<T>();
}
}
class D<T> {
T method() => null;
void method2(T x) {}
void method3(covariant T x) {}
}
class E<inout T> extends D<T> {
@override
T method() => null;
@override
void method2(T x) {}
@override
void method3(covariant T x) {}
}
abstract class F<T> {
int method(T x);
}
class G<inout T> {
final void Function(T) f;
G(this.f);
int method(T x) {
f(x);
}
}
class H<inout T> extends G<T> implements F<T> {
H(void Function(T) f) : super(f);
}
void testClass() {
A<int> a = new A();
a.method1(2);
a.method2(() => 2);
Expect.type<Contra<int>>(a.method3());
Contra<int> method3Function = a.method3();
method3Function(2);
Expect.isNull(a.method4());
a.method5((int val) {});
Expect.type<Cov<int>>(a.method6());
Cov<int> method6Function = a.method6();
Expect.isNull(method6Function());
Expect.equals(3, a.method7(3));
Expect.type<Contra<int>>(a.method8(contraFunction));
Expect.equals(contraFunction, a.method8(contraFunction));
Expect.type<Cov<int>>(a.method9(covFunction));
Expect.equals(covFunction, a.method9(covFunction));
A<num> aa = new A();
Expect.type<num>(aa.method10(3));
a.method11(Covariant<int>());
Expect.isNull(a.method12());
a.method13(Contravariant<int>());
Expect.isNull(a.method14());
a.method15(Invariant<int>());
Expect.isNull(a.method16());
a.method17(3);
a.method18(contraFunction);
a.method19(covFunction);
a.method20(Contravariant<int>());
a.method21(Covariant<int>());
a.method22<Contravariant<int>>();
a.method23<Covariant<int>>();
a.method24<Contra<int>>();
a.method25<Cov<int>>();
a.method26();
a.method27();
}
void testMixin() {
B b = new B();
b.method1(2);
b.method2(() => 2);
Expect.type<Contra<num>>(b.method3());
Contra<num> method3Function = b.method3();
method3Function(2);
Expect.isNull(b.method4());
b.method5((num val) {});
Expect.type<Cov<num>>(b.method6());
Cov<num> method6Function = b.method6();
Expect.isNull(method6Function());
Expect.equals(3, b.method7(3));
Expect.type<Contra<num>>(b.method8(contraFunctionNum));
Expect.equals(contraFunctionNum, b.method8(contraFunctionNum));
Expect.type<Cov<num>>(b.method9(covFunctionNum));
Expect.equals(covFunctionNum, b.method9(covFunctionNum));
Expect.type<num>(b.method10(3));
b.method11(Covariant<num>());
Expect.isNull(b.method12());
b.method13(Contravariant<num>());
Expect.isNull(b.method14());
b.method15(Invariant<num>());
Expect.isNull(b.method16());
b.method17(3);
b.method18(contraFunctionNum);
b.method19(covFunctionNum);
b.method20(Contravariant<num>());
b.method21(Covariant<num>());
b.method22<Contravariant<num>>();
b.method23<Covariant<num>>();
b.method24<Contra<num>>();
b.method25<Cov<num>>();
b.method26();
b.method27();
}
void testClassInMethods() {
C<int> c = new C();
c.method1((A<int> x) {});
c.method2(() => null);
Expect.type<A<int>>(c.method3());
}
void testOverrideLegacyMethods() {
E<int> e = new E();
Expect.isNull(e.method());
e.method2(3);
e.method3(3);
D<Object> d = e;
Expect.throws(() => d.method2("test"));
Expect.throws(() => d.method3("test"));
F<Object> f = new H<String>((String s) {});
Expect.throws(() => f.method(3));
// Tests reified type is the type expected for F and not G.
Expect.type<int Function(Object)>(f.method);
Expect.type<int Function(Object)>(new H<String>((String s){}).method);
}
main() {
testClass();
testMixin();
testClassInMethods();
testOverrideLegacyMethods();
}