|  | // 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); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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(() => throw "uncalled"); | 
|  |  | 
|  | 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(); | 
|  | } |