| // 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(); |
| } |