diff --git a/tests/language/variance/syntax/variance_disabled_keyword_identifier_syntax_test.dart b/tests/language/variance/syntax/variance_disabled_keyword_identifier_syntax_test.dart new file mode 100644 index 000000000000..0d6828c30022 --- /dev/null +++ b/tests/language/variance/syntax/variance_disabled_keyword_identifier_syntax_test.dart @@ -0,0 +1,48 @@ +// 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 identifier usage of keywords `out` and `inout`, correct usage of `in`. + +import "package:expect/expect.dart"; + +class A {} + +class B {} + +class C {} + +F() {} + +mixin G {} + +typedef H = out Function(inout); + +class OutParameter { + var out = 3; + int func(int out) { + return out; + } +} + +class inout { + void out(int x) {} +} + +var out = 5; + +main() { + OutParameter x = new OutParameter(); + Expect.equals(2, x.func(2)); + Expect.equals(3, x.out); + + inout foo = inout(); + foo.out(4); + + Expect.equals(5, out); + + var collection = [0, 1, 2]; + for (var x in collection) { + Expect.isTrue(x is int); + } +} diff --git a/tests/language/variance/syntax/variance_disabled_syntax_test.dart b/tests/language/variance/syntax/variance_disabled_syntax_test.dart new file mode 100644 index 000000000000..2811208a794b --- /dev/null +++ b/tests/language/variance/syntax/variance_disabled_syntax_test.dart @@ -0,0 +1,76 @@ +// 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 with `variance` flag disabled +// Correct variance modifier usage will issue an error. + +import 'package:expect/expect.dart'; + +abstract class A { +// ^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + int foo(X bar); +} + +class B {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. +// ^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. +// ^^^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +class C extends A { +// ^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + @override + int foo(T bar) { + return 2; + } +} + +mixin D {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +class E1 {} + +mixin E {} +// ^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +class F = Object with D; +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +class G {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +class H {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED +// [cfe] This requires the 'variance' language feature to be enabled. + +main() { + B b = B(); + + C c = C(); + Expect.equals(2, c.foo(3)); + + F f = F(); + + G g = G(); + + H h = H(); +} diff --git a/tests/language/variance/syntax/variance_keyword_identifier_syntax_test.dart b/tests/language/variance/syntax/variance_keyword_identifier_syntax_test.dart new file mode 100644 index 000000000000..a0bf3d7b67d2 --- /dev/null +++ b/tests/language/variance/syntax/variance_keyword_identifier_syntax_test.dart @@ -0,0 +1,51 @@ +// 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 identifier usage of keywords `out` and `inout`, correct usage of `in` +// with the experimental flag `variance` enabled. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +class A {} + +class B {} + +class C {} + +F() {} + +mixin G {} + +typedef H = out Function(inout); + +class OutParameter { + var out = 3; + int func(int out) { + return out; + } +} + +class inout { + void out(int x) {} +} + +var out = 5; + +main() { + OutParameter x = new OutParameter(); + Expect.equals(2, x.func(2)); + Expect.equals(3, x.out); + + inout foo = inout(); + foo.out(4); + + Expect.equals(5, out); + + var collection = [0, 1, 2]; + for (var x in collection) { + Expect.isTrue(x is int); + } +} diff --git a/tests/language/variance/syntax/variance_syntax_test.dart b/tests/language/variance/syntax/variance_syntax_test.dart new file mode 100644 index 000000000000..9a40965b6648 --- /dev/null +++ b/tests/language/variance/syntax/variance_syntax_test.dart @@ -0,0 +1,45 @@ +// 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. + +// SharedOptions=--enable-experiment=variance + +import 'package:expect/expect.dart'; + +abstract class A { + int foo(X bar); +} + +class B {} + +class C extends A { + @override + int foo(T bar) { + return 2; + } +} + +mixin D {} + +class E1 {} + +mixin E {} + +class F = Object with D; + +class G {} + +class H {} + +main() { + B b = B(); + + C c = C(); + Expect.equals(2, c.foo(3)); + + F f = F(); + + G g = G(); + + H h = H(); +} diff --git a/tests/language/variance/syntax/variance_type_parameter_error_syntax_test.dart b/tests/language/variance/syntax/variance_type_parameter_error_syntax_test.dart new file mode 100644 index 000000000000..28c1add7b429 --- /dev/null +++ b/tests/language/variance/syntax/variance_type_parameter_error_syntax_test.dart @@ -0,0 +1,68 @@ +// 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 erroneous usages of variance in unapplicable type parameters. + +// SharedOptions=--enable-experiment=variance + +void A(out int foo) { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CLASS +// [cfe] 'out' isn't a type. +// ^ +// [cfe] Type 'out' not found. +// ^^^ +// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN +// [cfe] Expected ')' before this. + List bar; + // ^ + // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR + // [cfe] The operator '<' isn't defined for the class 'Type'. + // ^^^ + // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER + // [cfe] Expected ';' after this. + // ^^^ + // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN + // [cfe] Getter not found: 'out'. + // ^ + // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR + // [cfe] The operator '>' isn't defined for the class 'Type'. + // ^^^ + // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER + // [cfe] Getter not found: 'bar'. +} + +void B(out foo) {} +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CLASS +// [cfe] 'out' isn't a type. +// ^ +// [cfe] Type 'out' not found. + +class C {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. +// ^^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. + +class D {} +// ^^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. +// ^^^^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. +// ^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. +// ^^^ +// [analyzer] SYNTACTIC_ERROR.MULTIPLE_VARIANCE_MODIFIERS +// [cfe] Each type parameter can have at most one variance modifier. + +typedef E = T Function(T a); +// ^ +// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN +// [cfe] Expected ',' before this. diff --git a/tests/language/variance/variance_downwards_inference_test.dart b/tests/language/variance/variance_downwards_inference_test.dart new file mode 100644 index 000000000000..b6cd329cf635 --- /dev/null +++ b/tests/language/variance/variance_downwards_inference_test.dart @@ -0,0 +1,53 @@ +// 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 downwards inference for explicit variance modifiers. + +// SharedOptions=--enable-experiment=variance + +class A { + final T _x; + A(T x):_x = x; + T get x => _x; + void set x(Object value) {} +} + +class B { + B(List x); + void set x(T val) {} +} + +class C { + final T _x; + C(T x, S y):_x = x; + T get x => _x; + void set x(Object value) {} + void set y(S _value) {} +} + +class D { + D(T x, void Function(T) y) {} + void set x(T val) {} +} + +main() { + // int <: T <: Object + // Choose int + A a = new A(3)..x+=1; + + // int <: T + // num <: T + // Choose num + B b = new B([])..x=2.2; + + // int <: T <: Object + // Choose int + // int <: S <: Object + // Choose Object + C c = new C(3, 3)..x+=1..y="hello"; + + // int <: T <: num + // Choose num due to contravariant heuristic. + D d = new D(3, (num x) {})..x=2.2; +} diff --git a/tests/language/variance/variance_in_field_error_test.dart b/tests/language/variance/variance_in_field_error_test.dart new file mode 100644 index 000000000000..98c4af6986a1 --- /dev/null +++ b/tests/language/variance/variance_in_field_error_test.dart @@ -0,0 +1,91 @@ +// 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 erroneous field usage for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class A { + final T a = throw "uncalled"; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + final T Function() b = () => throw "uncalled"; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + T get c => throw "uncalled"; +//^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + late T d; +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + covariant late T e; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + T? f = null; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. +} + +mixin BMixin { + final T a = throw "uncalled"; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + final T Function() b = () => throw "uncalled"; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + T get c => throw "uncalled"; +//^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + late T d; +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + covariant late T e; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + T? f = null; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. +} + +abstract class C { + T get a; +//^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. +} + +class D extends C { + var a; + // ^ + // [analyzer] COMPILE_TIME_ERROR.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Field 'a' should be initialized because its type 'T' doesn't allow null. +} diff --git a/tests/language/variance/variance_in_field_test.dart b/tests/language/variance/variance_in_field_test.dart new file mode 100644 index 000000000000..2b60fbbdc709 --- /dev/null +++ b/tests/language/variance/variance_in_field_test.dart @@ -0,0 +1,56 @@ +// 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 various fields for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +typedef Int2Void = void Function(int); + +class A { + void set a(T value) => value; + final void Function(T) b = (T val) { + Expect.equals(2, val); + }; + A get c => this; +} + +mixin BMixin { + void set a(T value) => value; + final void Function(T) b = (T val) { + Expect.equals(2, val); + }; + BMixin get c => this; +} + +class B with BMixin {} + +void testClass() { + A a = new A(); + + a.a = 2; + + Expect.type(a.b); + a.b(2); + + a.c.a = 2; +} + +void testMixin() { + B b = new B(); + + b.a = 2; + + Expect.type(b.b); + b.b(2); + + b.c.a = 2; +} + +main() { + testClass(); + testMixin(); +} diff --git a/tests/language/variance/variance_in_inference_error_test.dart b/tests/language/variance/variance_in_inference_error_test.dart new file mode 100644 index 000000000000..2c220ab734db --- /dev/null +++ b/tests/language/variance/variance_in_inference_error_test.dart @@ -0,0 +1,101 @@ +// 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 local inference errors for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class ContraBound { + ContraBound(T x, void Function(T) y) {} +} + +Exactly inferCovContra(Covariant x, Contravariant y) => new Exactly(); +Exactly inferContraContra(Contravariant x, Contravariant y) => new Exactly(); +Exactly inferContraBound(ContraBound x) => new Exactly(); + +main() { + Exactly upper; + Exactly lower; + + // T <: Upper and T <: Middle. + // We choose Middle. + var inferredMiddle = inferContraContra(Contravariant(), Contravariant()); + upper = inferredMiddle; + // ^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // T <: Upper and T <: Lower. + // We choose Lower. + var inferredLower = inferContraContra(Contravariant(), Contravariant()); + upper = inferredLower; + // ^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // int <: T <: String is not a valid constraint. + inferCovContra(Covariant(), Contravariant()); +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER +// ^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. + + // String <: T <: int is not a valid constraint. + inferCovContra(Covariant(), Contravariant()); +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER +// ^^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. + + // Middle <: T <: Lower is not a valid constraint + inferCovContra(Covariant(), Contravariant()); +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER +// ^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. + + // Upper <: T <: Lower is not a valid constraint + inferCovContra(Covariant(), Contravariant()); +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER +// ^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. + + // Upper <: T <: Middle is not a valid constraint + inferCovContra(Covariant(), Contravariant()); +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER +// ^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. + + // Inference for Contrabound(...) produces Lower <: T <: Upper. + // Since T is contravariant, we choose Upper as the solution. + var inferredContraUpper = inferContraBound(ContraBound(Lower(), (Upper x) {})); + lower = inferredContraUpper; + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // Inference for Contrabound(...) produces Lower <: T <: Middle. + // Since T is contravariant, we choose Middle as the solution. + var inferredContraMiddle = inferContraBound(ContraBound(Lower(), (Middle x) {})); + lower = inferredContraMiddle; + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. +} diff --git a/tests/language/variance/variance_in_inference_test.dart b/tests/language/variance/variance_in_inference_test.dart new file mode 100644 index 000000000000..03277fb01ee8 --- /dev/null +++ b/tests/language/variance/variance_in_inference_test.dart @@ -0,0 +1,76 @@ +// 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 local inference for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class ContraBound { + ContraBound(T x, void Function(T) y) {} +} + +Exactly inferCovContra(Covariant x, Contravariant y) => new Exactly(); +Exactly inferContraContra(Contravariant x, Contravariant y) => new Exactly(); +Exactly inferContraBound(ContraBound x) => new Exactly(); + +main() { + Exactly upper; + Exactly middle; + Exactly lower; + + // Lower <: T + // T <: Lower + // Choose Lower for Lower <: T <: Lower + var inferredLower = inferCovContra(Covariant(), Contravariant()); + lower = inferredLower; + + // Lower <: T + // T <: Middle + // Choose Lower for Lower <: T <: Middle + var inferredLower2 = inferCovContra(Covariant(), Contravariant()); + lower = inferredLower2; + + // Lower <: T + // T <: Upper + // Choose Lower for Lower <: T <: Upper + var inferredLower3 = inferCovContra(Covariant(), Contravariant()); + lower = inferredLower3; + + // T <: Upper + // T <: Middle + // Choose Middle since it is the greatest lower bound of Upper and Middle. + var inferredMiddle = inferContraContra(Contravariant(), Contravariant()); + middle = inferredMiddle; + + // T <: Upper + // T <: Lower + // Choose Lower since it is the greatest lower bound of Upper and Lower. + var inferredLower4 = inferContraContra(Contravariant(), Contravariant()); + lower = inferredLower4; + + // T <: Middle + // T <: Lower + // Choose Lower since it is the greatest lower bound of Middle and Lower. + var inferredLower5 = inferContraContra(Contravariant(), Contravariant()); + lower = inferredLower5; + + // Lower <: T <: Upper + // Choose Upper. + var inferredContraUpper = inferContraBound(ContraBound(Lower(), (Upper x) {})); + upper = inferredContraUpper; + + // Lower <: T <: Middle + // Choose Middle. + var inferredContraMiddle = inferContraBound(ContraBound(Lower(), (Middle x) {})); + middle = inferredContraMiddle; +} diff --git a/tests/language/variance/variance_in_method_error_test.dart b/tests/language/variance/variance_in_method_error_test.dart new file mode 100644 index 000000000000..b06567c3955d --- /dev/null +++ b/tests/language/variance/variance_in_method_error_test.dart @@ -0,0 +1,349 @@ +// 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 erroneous method signatures and return types for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef Inv = void Function(); +typedef Cov = T Function(); +typedef Contra = void Function(T); + +class Covariant {} +class Contravariant {} +class Invariant {} + +class A { + T method1() => throw "uncalled"; +//^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method2(Contra x) {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Cov method3() { +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + return () => throw "uncalled"; + } + + void method4(Contra> x) {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method5(Cov> x) {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Contra> method6() => (Contra x) {}; +//^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + Cov> method7() { +//^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + return () { + return () => throw "uncalled"; + }; + } + + Inv method8() => throw "uncalled"; +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type. + + void method9(Inv x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + Covariant method10() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method11(Contravariant x) {} + // ^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Invariant method12() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type. + + void method13(Invariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method14(Contravariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method15(Covariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Contravariant> method16() => Contravariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + Covariant> method17() => Covariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method18() {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method19>() {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method20>() {} + // ^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method21({required Contra x}) {} + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method22({required Contravariant x}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method23({required Covariant x, required Contravariant y}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method24>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method25>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. +} + +mixin BMixin { + T method1() => throw "uncalled"; +//^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method2(Contra x) {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Cov method3() { +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + return () => throw "uncalled"; + } + + void method4(Contra> x) {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method5(Cov> x) {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Contra> method6() => (Contra x) {}; +//^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + Cov> method7() { +//^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + return () { + return () => throw "uncalled"; + }; + } + + Inv method8() => throw "uncalled"; +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type. + + void method9(Inv x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + Covariant method10() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method11(Contravariant x) {} + // ^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Invariant method12() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type. + + void method13(Invariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method14(Contravariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method15(Covariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + Contravariant> method16() => Contravariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + Covariant> method17() => Covariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + + void method18() {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method19>() {} + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method20>() {} + // ^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method21({required Contra x}) {} + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method22({required Contravariant x}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method23({required Covariant x, required Contravariant y}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + + void method24>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. + + void method25>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'in' type variable 'T' in an 'inout' position. +} + +class B { + void method1(A x) {} + // ^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. + Contra> method2() { +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type. + throw "uncalled"; + } +} + +class C { + void method(T x) {} +} + +class D extends C { + @override + void method(void Function(T) x) {} + // ^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'in' type variable 'T' in an 'out' position. +} diff --git a/tests/language/variance/variance_in_method_test.dart b/tests/language/variance/variance_in_method_test.dart new file mode 100644 index 000000000000..a0949756fdaa --- /dev/null +++ b/tests/language/variance/variance_in_method_test.dart @@ -0,0 +1,246 @@ +// 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 `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +typedef Cov = T Function(); +typedef Contra = void Function(T); + +Cov covFunction = () => 2; +Contra contraFunction = (int val) {}; + +class Covariant {} +class Contravariant {} + +class A { + void method1(T x) {} + void method2(Cov x) {} + Contra method3() { + return (T val) { + Expect.equals(2, val); + }; + } + + void method4(Cov> x) {} + Contra> method5() { + return (Cov method) { + Expect.type>(method); + }; + } + Cov> method6() { + return () { + return (T x) { + Expect.equals(2, x); + }; + }; + } + void method7(Contra> x) {} + + void method8(Covariant x) {} + Contravariant? method9() => null; + void method10(Covariant> x) {} + Contravariant>? method11() => null; + void method12(Contravariant> x) {} + Covariant>? method13() => null; + + void method14(covariant T x) {} + void method15(covariant Contra x) {} + void method16(covariant Cov x) {} + void method17(covariant Contravariant x) {} + void method18(covariant Covariant x) {} + + void method19({T? x}) {} + void method20({Covariant? x}) {} + void method21({Cov? x}) {} +} + +mixin BMixin { + void method1(T x) {} + void method2(Cov x) {} + Contra method3() { + return (T val) { + Expect.equals(2, val); + }; + } + + void method4(Cov> x) {} + Contra> method5() { + return (Cov method) { + Expect.type>(method); + }; + } + Cov> method6() { + return () { + return (T x) { + Expect.equals(2, x); + }; + }; + } + void method7(Contra> x) {} + + void method8(Covariant x) {} + Contravariant? method9() => null; + void method10(Covariant> x) {} + Contravariant>? method11() => null; + void method12(Contravariant> x) {} + Covariant>? method13() => null; + + void method14(covariant T x) {} + void method15(covariant Contra x) {} + void method16(covariant Cov x) {} + void method17(covariant Contravariant x) {} + void method18(covariant Covariant x) {} + + void method19({T? x}) {} + void method20({Covariant? x}) {} + void method21({Cov? x}) {} +} + +class B with BMixin {} + +class C { + void method1(Contra> x) {} + A method2() { + return A(); + } +} + +class D { + late T x; + T? method() => null; + void method2(T x) {} + void method3(covariant T x) {} +} + +class E extends D { + @override + void Function(T) method() => (T x) {}; + + @override + void method3(covariant void Function(T) x) {} +} + +void testClass() { + A a = new A(); + + a.method1(2); + + a.method2(covFunction); + + Expect.type>(a.method3()); + Contra method3Function = a.method3(); + method3Function(2); + + a.method4(() { + return covFunction; + }); + + Expect.type>>(a.method5()); + Contra> method5Function = a.method5(); + method5Function(covFunction); + + Expect.type>>(a.method6()); + Cov> method6Function = a.method6(); + Expect.type>(method6Function()); + Contra method6NestedFunction = method6Function(); + method6NestedFunction(2); + + a.method7((Contra x) {}); + + a.method8(Covariant()); + Expect.isNull(a.method9()); + a.method10(Covariant>()); + Expect.isNull(a.method11()); + a.method12(Contravariant>()); + Expect.isNull(a.method13()); + + a.method14(3); + a.method15(contraFunction); + a.method16(covFunction); + a.method17(Contravariant()); + a.method18(Covariant()); + + a.method19(); + a.method20(); + a.method21(); +} + +void testMixin() { + B b = new B(); + + b.method1(2); + + b.method2(covFunction); + + Expect.type>(b.method3()); + Contra method3Return = b.method3(); + method3Return(2); + + b.method4(() { + return covFunction; + }); + + Expect.type>>(b.method5()); + Contra> method5Return = b.method5(); + method5Return(covFunction); + + Expect.type>>(b.method6()); + Cov> method6Function = b.method6(); + Expect.type>(method6Function()); + Contra method6NestedFunction = method6Function(); + method6NestedFunction(2); + + b.method7((Contra x) {}); + + b.method8(Covariant()); + Expect.isNull(b.method9()); + b.method10(Covariant>()); + Expect.isNull(b.method11()); + b.method12(Contravariant>()); + Expect.isNull(b.method13()); + + b.method14(3); + b.method15(contraFunction); + b.method16(covFunction); + b.method17(Contravariant()); + b.method18(Covariant()); + + b.method19(); + b.method20(); + b.method21(); +} + +void testClassInMethods() { + C c = new C(); + + c.method1((A x) {}); + + Expect.type>(c.method2()); +} + +void testOverrideLegacyMethods() { + E e = new E(); + Expect.isTrue(e.method() is Function); + e.method2(contraFunction); + e.method3(contraFunction); + e.x = contraFunction; + + D d = e; + Expect.throws(() => d.x = "test"); + + e = new E(); + Expect.throws(() => e.method2(contraFunction)); + Expect.throws(() => e.method3(contraFunction)); +} + +main() { + testClass(); + testMixin(); + testClassInMethods(); + testOverrideLegacyMethods(); +} diff --git a/tests/language/variance/variance_in_subclass_error_test.dart b/tests/language/variance/variance_in_subclass_error_test.dart new file mode 100644 index 000000000000..123b3e568565 --- /dev/null +++ b/tests/language/variance/variance_in_subclass_error_test.dart @@ -0,0 +1,144 @@ +// 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 erroneous subclass usage for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); +typedef InvFunction = T Function(T); + +class LegacyCovariant {} +class Covariant {} +class Contravariant {} +class Invariant {} +mixin MLegacyCovariant {} +mixin MCovariant {} +mixin MContravariant {} +mixin MInvariant {} + +class A extends LegacyCovariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'LegacyCovariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class B implements LegacyCovariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'LegacyCovariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class C with MLegacyCovariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MLegacyCovariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class D extends Covariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class E implements Covariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class F with MCovariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MCovariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class G extends Invariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class H implements Invariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class I with MInvariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MInvariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class J extends Covariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class K extends Contravariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class L extends Covariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class M extends Covariant>> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class N extends Contravariant>> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class O extends Covariant>> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class P extends Covariant>> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class Q extends Invariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class R = Covariant with MContravariant; +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class S = Contravariant with MCovariant; +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MCovariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class T = Invariant with MInvariant; +// ^ +// [cfe] Can't use 'in' type variable 'X' in an 'inout' position in supertype 'Invariant'. +// ^ +// [cfe] Can't use 'in' type variable 'X' in an 'inout' position in supertype 'MInvariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE diff --git a/tests/language/variance/variance_in_subclass_test.dart b/tests/language/variance/variance_in_subclass_test.dart new file mode 100644 index 000000000000..f7a314a9b22a --- /dev/null +++ b/tests/language/variance/variance_in_subclass_test.dart @@ -0,0 +1,49 @@ +// 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 subclass usage for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); + +class Covariant {} +class Contravariant {} +mixin MContravariant {} + +class A extends Contravariant {} +class B implements Contravariant {} +class C with MContravariant {} + +class D extends Covariant> {} +class E extends Contravariant> {} + +class F extends Covariant> {} +class G extends Covariant>> {} +class H extends Covariant>> {} + +class I extends Covariant>> {} + +class J extends Contravariant>> {} + +class K = Contravariant with MContravariant; +class L = Covariant> with MContravariant; +class M = Contravariant with MContravariant>; + +main() { + A a = A(); + B b = B(); + C c = C(); + D d = D(); + E e = E(); + F f = F(); + G g = G(); + H h = H(); + I i = I(); + J j = J(); + K k = K(); + L l = L(); + M m = M(); +} diff --git a/tests/language/variance/variance_in_subtyping_error_test.dart b/tests/language/variance/variance_in_subtyping_error_test.dart new file mode 100644 index 000000000000..d5697c76c975 --- /dev/null +++ b/tests/language/variance/variance_in_subtyping_error_test.dart @@ -0,0 +1,80 @@ +// 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 erroneous subtyping for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Contravariant {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class A { + Contravariant method1() { + return new Contravariant(); + } + + void method2(Contravariant x) {} +} + +class B extends A { + @override + Contravariant method1() { + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // [cfe] The return type of the method 'B.method1' is 'Contravariant', which does not match the return type, 'Contravariant', of the overridden method, 'A.method1'. + return new Contravariant(); + } + + @override + void method2(Contravariant x) {} + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // ^ + // [cfe] The parameter 'x' of the method 'B.method2' has type 'Contravariant', which does not match the corresponding type, 'Contravariant', in the overridden method, 'A.method2'. +} + +class C> {} + +class D { + C> method1() { + //^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Contravariant' doesn't conform to the bound 'Contravariant' of the type variable 'T' on 'C' in the return type. + return C>(); + // ^ + // [cfe] Type argument 'Contravariant' doesn't conform to the bound 'Contravariant' of the type variable 'T' on 'C'. + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + } +} + +void testCall(Iterable> x) {} + +main() { + C> c = new C>(); + //^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Contravariant' doesn't conform to the bound 'Contravariant' of the type variable 'T' on 'C'. + // ^ + // [cfe] Type argument 'Contravariant' doesn't conform to the bound 'Contravariant' of the type variable 'T' on 'C'. + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + + Iterable> iterableMiddle = [new Contravariant()]; + List> listLower = [new Contravariant()]; + iterableMiddle = listLower; + // ^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'List>' can't be assigned to a variable of type 'Iterable>'. + + testCall(listLower); + // ^^^^^^^^^ + // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE + // [cfe] The argument type 'List>' can't be assigned to the parameter type 'Iterable>'. +} diff --git a/tests/language/variance/variance_in_subtyping_test.dart b/tests/language/variance/variance_in_subtyping_test.dart new file mode 100644 index 000000000000..df89b2ba2b48 --- /dev/null +++ b/tests/language/variance/variance_in_subtyping_test.dart @@ -0,0 +1,102 @@ +// 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 subtyping for the `in` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +class Contravariant {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class A { + Contravariant method1() { + return Contravariant(); + } + + void method2(Contravariant x) {} +} + +class B extends A { + @override + Contravariant method1() { + return new Contravariant(); + } + + @override + void method2(Contravariant x) {} +} + +class C extends A { + @override + Contravariant method1() { + return new Contravariant(); + } + + @override + void method2(Contravariant x) {} +} + +class D> {} + +class E { + D> method1() { + return D>(); + } +} + +class F { + D> method1() { + return D>(); + } +} + +void testCall(Iterable> x) {} + +main() { + A a = new A(); + Expect.type>(a.method1()); + Expect.type>(a.method1()); + Expect.notType>(a.method1()); + a.method2(new Contravariant()); + a.method2(new Contravariant()); + + B b = new B(); + Expect.type>(b.method1()); + Expect.type>(b.method1()); + Expect.type>(b.method1()); + b.method2(new Contravariant()); + b.method2(new Contravariant()); + + C c = new C(); + Expect.type>(c.method1()); + Expect.type>(c.method1()); + Expect.notType>(c.method1()); + c.method2(new Contravariant()); + c.method2(new Contravariant()); + + D> dUpper = new D>(); + D> dMiddle = new D>(); + + E e = new E(); + Expect.type>>(e.method1()); + Expect.type>>(e.method1()); + + F f = new F(); + Expect.type>>(e.method1()); + + Iterable> iterableLower = [new Contravariant()]; + List> listMiddle = [new Contravariant()]; + iterableLower = listMiddle; + + testCall(listMiddle); + + Expect.subtype, Contravariant>(); + Expect.subtype, Contravariant>(); + Expect.notSubtype, Contravariant>(); +} diff --git a/tests/language/variance/variance_inout_field_test.dart b/tests/language/variance/variance_inout_field_test.dart new file mode 100644 index 000000000000..4e436d48eb95 --- /dev/null +++ b/tests/language/variance/variance_inout_field_test.dart @@ -0,0 +1,99 @@ +// 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 various fields for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +typedef Void2Int = int? Function(); +typedef Int2Void = void Function(int); + +class A { + late T a; + final T? b = null; + final T? Function() c = () => null; + final void Function(T) d = (T val) { + Expect.equals(2, val); + }; + A get e => this; + covariant late T f; + T? get g => null; + void set h(T value) => value; + void set i(covariant T value) => value; +} + +mixin BMixin { + late T a; + final T? b = null; + final T? Function() c = () => null; + final void Function(T) d = (T val) { + Expect.equals(2, val); + }; + BMixin get e => this; + covariant late T f; + T? get g => null; + void set h(T value) => value; + void set i(covariant T value) => value; +} + +class B with BMixin {} + +void testClass() { + A a = new A(); + + a.a = 2; + Expect.equals(2, a.a); + + Expect.isNull(a.b); + + Expect.type(a.c); + Expect.isNull(a.c()); + + Expect.type(a.d); + a.d(2); + + a.e.a = 3; + + a.f = 2; + Expect.equals(2, a.f); + + Expect.isNull(a.g); + + a.h = 2; + + a.i = 2; +} + +void testMixin() { + B b = new B(); + + b.a = 2; + Expect.equals(2, b.a); + + Expect.isNull(b.b); + + Expect.type(b.c); + Expect.isNull(b.c()); + + Expect.type(b.d); + b.d(2); + + b.e.a = 3; + + b.f = 2; + Expect.equals(2, b.f); + + Expect.isNull(b.g); + + b.h = 2; + + b.i = 2; +} + +main() { + testClass(); + testMixin(); +} diff --git a/tests/language/variance/variance_inout_inference_error_test.dart b/tests/language/variance/variance_inout_inference_error_test.dart new file mode 100644 index 000000000000..763265801abc --- /dev/null +++ b/tests/language/variance/variance_inout_inference_error_test.dart @@ -0,0 +1,60 @@ +// 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 local inference errors for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} +class Invariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +Exactly inferInvInv(Invariant x, Invariant y) => new Exactly(); +Exactly inferInvCov(Invariant x, Covariant y) => new Exactly(); +Exactly inferInvContra(Invariant x, Contravariant y) => new Exactly(); + +main() { + // Middle <: T <: Middle and int <: T <: int are not valid constraints. + inferInvInv(Invariant(), Invariant()); +// ^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Invariant' can't be assigned to the parameter type 'Invariant'. +// ^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Invariant' can't be assigned to the parameter type 'Invariant'. + + // Middle <: T <: Middle and Upper <: T <: Upper are not valid constraints. + inferInvInv(Invariant(), Invariant()); +// ^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Invariant' can't be assigned to the parameter type 'Invariant'. + + // Middle <: T <: Middle and Lower <: T <: Lower are not valid constraints. + inferInvInv(Invariant(), Invariant()); +// ^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Invariant' can't be assigned to the parameter type 'Invariant'. + + // Upper <: T + // Middle <: T <: Middle + // Upper <: T <: Middle is not a valid constraint. + inferInvCov(Invariant(), Covariant()); +// ^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Invariant' can't be assigned to the parameter type 'Invariant'. + + // T <: Lower + // Middle <: T <: Lower + // Middle <: T <: Lower is not a valid constraint + inferInvContra(Invariant(), Contravariant()); +// ^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE +// [cfe] The argument type 'Contravariant' can't be assigned to the parameter type 'Contravariant'. +} diff --git a/tests/language/variance/variance_inout_inference_test.dart b/tests/language/variance/variance_inout_inference_test.dart new file mode 100644 index 000000000000..8a5e3c527059 --- /dev/null +++ b/tests/language/variance/variance_inout_inference_test.dart @@ -0,0 +1,54 @@ +// 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 local inference for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} +class Invariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +Exactly inferInvInv(Invariant x, Invariant y) => new Exactly(); +Exactly inferInvCov(Invariant x, Covariant y) => new Exactly(); +Exactly inferInvContra(Invariant x, Contravariant y) => new Exactly(); + +main() { + Exactly middle; + + // Middle <: T <: Middle + // Choose Middle + var inferredMiddle = inferInvInv(Invariant(), Invariant()); + middle = inferredMiddle; + + // Lower <: T + // Middle <: T <: Middle + // Choose Middle since this merges to Middle <: T <: Middle + var inferredMiddle2 = inferInvCov(Invariant(), Covariant()); + middle = inferredMiddle2; + + // Middle <: T + // Middle <: T <: Middle + // Choose Middle since this merges to Middle <: T <: Middle + var inferredMiddle3 = inferInvCov(Invariant(), Covariant()); + middle = inferredMiddle3; + + // T <: Upper + // Middle <: T <: Middle + // Choose Middle since this merges to Middle <: T <: Middle + var inferredMiddle4 = inferInvContra(Invariant(), Contravariant()); + middle = inferredMiddle4; + + // T <: Middle + // Middle <: T <: Middle + // Choose Middle since this merges to Middle <: T <: Middle + var inferredMiddle5 = inferInvContra(Invariant(), Contravariant()); + middle = inferredMiddle5; +} diff --git a/tests/language/variance/variance_inout_method_test.dart b/tests/language/variance/variance_inout_method_test.dart new file mode 100644 index 000000000000..e76f19ee32d8 --- /dev/null +++ b/tests/language/variance/variance_inout_method_test.dart @@ -0,0 +1,288 @@ +// 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 Function(); +typedef Contra = void Function(T); + +Cov covFunction = () => 2; +Contra contraFunction = (int val) {}; +Cov covFunctionNum = () => 2; +Contra contraFunctionNum = (num val) {}; + +class Covariant {} +class Contravariant {} +class Invariant {} + +class A { + void method1(T x) {} + void method2(Cov x) {} + Contra method3() { + return (T val) { + Expect.equals(2, val); + }; + } + + T? method4() => null; + void method5(Contra x) {} + Cov method6() { + return () => null; + } + + T method7(T x) => x; + Contra method8(Contra x) => x; + Cov method9(Cov x) => x; + + T method10(S x) => x; + + void method11(Covariant x) {} + Covariant? method12() => null; + void method13(Contravariant x) {} + Contravariant? method14() => null; + void method15(Invariant x) {} + Invariant? method16() => null; + + void method17(covariant T x) {} + void method18(covariant Contra x) {} + void method19(covariant Cov x) {} + void method20(covariant Contravariant x) {} + void method21(covariant Covariant x) {} + + void method22>() {} + void method23>() {} + void method24>() {} + void method25>() {} + + void method26({Contra? a, Cov? b, T? c}) {} + void method27({Contravariant? a, Covariant? b}) {} +} + +mixin BMixin { + void method1(T x) {} + void method2(Cov x) {} + Contra method3() { + return (T val) { + Expect.equals(2, val); + }; + } + + T? method4() => null; + void method5(Contra x) {} + Cov method6() { + return () => null; + } + + T method7(T x) => x; + Contra method8(Contra x) => x; + Cov method9(Cov x) => x; + + T method10(S x) => x; + + void method11(Covariant x) {} + Covariant? method12() => null; + void method13(Contravariant x) {} + Contravariant? method14() => null; + void method15(Invariant x) {} + Invariant? method16() => null; + + void method17(covariant T x) {} + void method18(covariant Contra x) {} + void method19(covariant Cov x) {} + void method20(covariant Contravariant x) {} + void method21(covariant Covariant x) {} + + void method22>() {} + void method23>() {} + void method24>() {} + void method25>() {} + + void method26({Contra? a, Cov? b, T? c}) {} + void method27({Contravariant? a, Covariant? b}) {} +} + +class B with BMixin {} + +class C { + void method1(Contra> x) {} + void method2(Cov> x) {} + A method3() { + return A(); + } +} + +class D { + T? method() => null; + void method2(T x) {} + void method3(covariant T x) {} +} + +class E extends D { + @override + T? method() => null; + + @override + void method2(T x) {} + + @override + void method3(covariant T x) {} +} + +abstract class F { + int method(T x); +} + +class G { + final void Function(T) f; + G(this.f); + int method(T x) { + f(x); + return -1; + } +} + +class H extends G implements F { + H(void Function(T) f) : super(f); +} + +void testClass() { + A a = new A(); + + a.method1(2); + + a.method2(() => 2); + + Expect.type>(a.method3()); + Contra method3Function = a.method3(); + method3Function(2); + + Expect.isNull(a.method4()); + + a.method5((int val) {}); + + Expect.type>(a.method6()); + Cov method6Function = a.method6(); + Expect.isNull(method6Function()); + + Expect.equals(3, a.method7(3)); + + Expect.type>(a.method8(contraFunction)); + Expect.equals(contraFunction, a.method8(contraFunction)); + + Expect.type>(a.method9(covFunction)); + Expect.equals(covFunction, a.method9(covFunction)); + + A aa = new A(); + Expect.type(aa.method10(3)); + + a.method11(Covariant()); + Expect.isNull(a.method12()); + a.method13(Contravariant()); + Expect.isNull(a.method14()); + a.method15(Invariant()); + Expect.isNull(a.method16()); + + a.method17(3); + a.method18(contraFunction); + a.method19(covFunction); + a.method20(Contravariant()); + a.method21(Covariant()); + + a.method22>(); + a.method23>(); + a.method24>(); + a.method25>(); + + a.method26(); + a.method27(); +} + +void testMixin() { + B b = new B(); + + b.method1(2); + + b.method2(() => 2); + + Expect.type>(b.method3()); + Contra method3Function = b.method3(); + method3Function(2); + + Expect.isNull(b.method4()); + + b.method5((num val) {}); + + Expect.type>(b.method6()); + Cov method6Function = b.method6(); + Expect.isNull(method6Function()); + + Expect.equals(3, b.method7(3)); + + Expect.type>(b.method8(contraFunctionNum)); + Expect.equals(contraFunctionNum, b.method8(contraFunctionNum)); + + Expect.type>(b.method9(covFunctionNum)); + Expect.equals(covFunctionNum, b.method9(covFunctionNum)); + + Expect.type(b.method10(3)); + + b.method11(Covariant()); + Expect.isNull(b.method12()); + b.method13(Contravariant()); + Expect.isNull(b.method14()); + b.method15(Invariant()); + Expect.isNull(b.method16()); + + b.method17(3); + b.method18(contraFunctionNum); + b.method19(covFunctionNum); + b.method20(Contravariant()); + b.method21(Covariant()); + + b.method22>(); + b.method23>(); + b.method24>(); + b.method25>(); + + b.method26(); + b.method27(); +} + +void testClassInMethods() { + C c = new C(); + + c.method1((A x) {}); + c.method2(() => throw "uncalled"); + + Expect.type>(c.method3()); +} + +void testOverrideLegacyMethods() { + E e = new E(); + Expect.isNull(e.method()); + e.method2(3); + e.method3(3); + + D d = e; + Expect.throws(() => d.method2("test")); + Expect.throws(() => d.method3("test")); + + F f = new H((String s) {}); + Expect.throws(() => f.method(3)); + + // Tests reified type is the type expected for F and not G. + Expect.type(f.method); + Expect.type(new H((String s){}).method); +} + +main() { + testClass(); + testMixin(); + testClassInMethods(); + testOverrideLegacyMethods(); +} diff --git a/tests/language/variance/variance_inout_subclass_test.dart b/tests/language/variance/variance_inout_subclass_test.dart new file mode 100644 index 000000000000..e1b7122c8052 --- /dev/null +++ b/tests/language/variance/variance_inout_subclass_test.dart @@ -0,0 +1,90 @@ +// 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 subclass usage for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); +typedef InvFunction = T Function(T); + +class LegacyCovariant {} +class Invariant{} +class Covariant {} +class Contravariant {} +mixin MLegacyCovariant {} +mixin MContravariant {} +mixin MCovariant {} +mixin MInvariant {} + +class A extends LegacyCovariant {} +class B extends Invariant {} +class C extends Covariant {} +class D extends Contravariant {} + +class E implements LegacyCovariant {} +class F implements Invariant {} +class G implements Covariant {} +class H implements Contravariant {} + +class I with MLegacyCovariant {} +class J with MInvariant {} +class K with MCovariant {} +class L with MContravariant {} + +class M extends Covariant> {} +class N extends Contravariant> {} +class O extends Covariant> {} +class P extends Covariant>> {} +class Q extends Covariant>> {} +class R extends Covariant>> {} +class S extends Contravariant>> {} + +class T extends Covariant> {} +class U extends Contravariant> {} +class V extends Covariant> {} +class W extends Covariant>> {} +class X extends Contravariant>> {} +class Y extends Covariant>> {} +class Z extends Covariant>> {} + +class AA extends Covariant> {} + +class AB = Invariant with MInvariant; +class AC = Covariant with MCovariant; +class AD = Contravariant with MContravariant; + +main() { + A a = A(); + B b = B(); + C c = C(); + D d = D(); + E e = E(); + F f = F(); + G g = G(); + H h = H(); + I i = I(); + J j = J(); + K k = K(); + L l = L(); + M m = M(); + N n = N(); + O o = O(); + P p = P(); + Q q = Q(); + R r = R(); + S s = S(); + T t = T(); + U u = U(); + V v = V(); + W w = W(); + X x = X(); + Y y = Y(); + Z z = Z(); + AA aa = AA(); + AB ab = AB(); + AC ac = AC(); + AD ad = AD(); +} diff --git a/tests/language/variance/variance_inout_subtyping_error_test.dart b/tests/language/variance/variance_inout_subtyping_error_test.dart new file mode 100644 index 000000000000..d06f3365ed2b --- /dev/null +++ b/tests/language/variance/variance_inout_subtyping_error_test.dart @@ -0,0 +1,130 @@ +// 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 erroneous subtyping for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Invariant {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class A { + Invariant method1() { + return Invariant(); + } + + void method2(Invariant x) {} +} + +class B extends A { + @override + Invariant method1() { + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // [cfe] The return type of the method 'B.method1' is 'Invariant', which does not match the return type, 'Invariant', of the overridden method, 'A.method1'. + return new Invariant(); + } + + @override + void method2(Invariant x) {} + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // ^ + // [cfe] The parameter 'x' of the method 'B.method2' has type 'Invariant', which does not match the corresponding type, 'Invariant', in the overridden method, 'A.method2'. +} + +class C extends A { + @override + Invariant method1() { + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // [cfe] The return type of the method 'C.method1' is 'Invariant', which does not match the return type, 'Invariant', of the overridden method, 'A.method1'. + return new Invariant(); + } + + @override + void method2(Invariant x) {} + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // ^ + // [cfe] The parameter 'x' of the method 'C.method2' has type 'Invariant', which does not match the corresponding type, 'Invariant', in the overridden method, 'A.method2'. +} + +class D> {} + +class E { + D> method1() { + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D' in the return type. + return D>(); + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + } + + D> method2() { + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D' in the return type. + return D>(); + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + } +} + +void testCall(Iterable> x) {} + +main() { + D> dUpper = new D>(); + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + D> dLower = new D>(); + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^ + // [cfe] Type argument 'Invariant' doesn't conform to the bound 'Invariant' of the type variable 'T' on 'D'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + + Iterable> iterableLower = [new Invariant()]; + List> listMiddle = [new Invariant()]; + iterableLower = listMiddle; + // ^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'List>' can't be assigned to a variable of type 'Iterable>'. + + Iterable> iterableMiddle = [new Invariant()]; + List> listLower = [new Invariant()]; + iterableMiddle = listLower; + // ^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'List>' can't be assigned to a variable of type 'Iterable>'. + + testCall(listMiddle); + // ^^^^^^^^^^ + // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE + // [cfe] The argument type 'List>' can't be assigned to the parameter type 'Iterable>'. + + testCall(listLower); + // ^^^^^^^^^ + // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE + // [cfe] The argument type 'List>' can't be assigned to the parameter type 'Iterable>'. +} diff --git a/tests/language/variance/variance_inout_subtyping_test.dart b/tests/language/variance/variance_inout_subtyping_test.dart new file mode 100644 index 000000000000..e4252f49a1ad --- /dev/null +++ b/tests/language/variance/variance_inout_subtyping_test.dart @@ -0,0 +1,170 @@ +// 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 subtyping for the `inout` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import 'dart:async'; + +import "package:expect/expect.dart"; + +class Invariant {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class A { + Invariant method1() { + return new Invariant(); + } + + void method2(Invariant x) {} +} + +class B extends A { + @override + Invariant method1() { + return new Invariant(); + } + + @override + void method2(Invariant x) {} +} + +class C> {} + +class D { + C> method1() { + return C>(); + } +} + +class E { + Invariant method1() { + return new Invariant(); + } + + void method2(Invariant x) {} +} + +class F extends E { + @override + Invariant method1() { + return new Invariant(); + } + + @override + void method2(Invariant x) {} +} + +class G { + Invariant method1() { + return new Invariant(); + } + + void method2(Invariant> x) {} +} + +class H extends G { + @override + Invariant> method1() { + return new Invariant>(); + } + + @override + void method2(Invariant x) {} +} + +class I { + Invariant> method1() { + return new Invariant>(); + } + + void method2(Invariant> x) {} +} + +class J extends I { + @override + Invariant> method1() { + return new Invariant>(); + } + + @override + void method2(Invariant> x) {} +} + +void testCall(Iterable> x) {} + +main() { + A a = new A(); + Expect.type>(a.method1()); + Expect.notType>(a.method1()); + Expect.notType>(a.method1()); + a.method2(new Invariant()); + + B b = new B(); + Expect.type>(b.method1()); + Expect.notType>(b.method1()); + Expect.notType>(b.method1()); + b.method2(new Invariant()); + + C> c = new C>(); + + D d = new D(); + Expect.type>>(d.method1()); + + E e = new E(); + Expect.type>(e.method1()); + e.method2(new Invariant()); + + // Invariant <:> Invariant + F f = new F(); + Expect.type>(f.method1()); + Expect.type>(f.method1()); + f.method2(new Invariant()); + f.method2(new Invariant()); + + G g = new G(); + Expect.type>(g.method1()); + g.method2(new Invariant>()); + + // Invariant> <:> Invariant + H h = new H(); + Expect.type>>(h.method1()); + Expect.type>(h.method1()); + h.method2(new Invariant>()); + h.method2(new Invariant()); + + I i = new I(); + Expect.type>>(i.method1()); + i.method2(new Invariant>()); + + // Invariant> <:> Invariant> + J j = new J(); + Expect.type>>(j.method1()); + Expect.type>>(j.method1()); + j.method2(new Invariant>()); + j.method2(new Invariant>()); + + Iterable> iterableMiddle = [new Invariant()]; + List> listMiddle = [new Invariant()]; + iterableMiddle = listMiddle; + + testCall(listMiddle); + + Expect.subtype, Invariant>(); + Expect.notSubtype, Invariant>(); + Expect.notSubtype, Invariant>(); + + Expect.subtype, Invariant>(); + Expect.subtype, Invariant>(); + + Expect.subtype>, Invariant>(); + Expect.subtype, Invariant>>(); + + Expect.subtype>, Invariant>>(); + Expect.subtype>, Invariant>>(); +} diff --git a/tests/language/variance/variance_method_tearoff_test.dart b/tests/language/variance/variance_method_tearoff_test.dart new file mode 100644 index 000000000000..1e69d797c745 --- /dev/null +++ b/tests/language/variance/variance_method_tearoff_test.dart @@ -0,0 +1,52 @@ +// 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 reified types of torn-off methods with type parameters that have +// explicit variance modifiers. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +class Contravariant { + int method(T x) { return -1; } +} + +class Invariant { + T method(T x) { return x; } +} + +class LegacyCovariant { + int method(T x) { return -1; } +} + +class NoSuchMethod implements Invariant { + noSuchMethod(_) => 3; +} + +main() { + Contravariant contraDiff = new Contravariant(); + Expect.notType(contraDiff.method); + Expect.type(contraDiff.method); + + Contravariant contraSame = new Contravariant(); + Expect.notType(contraSame.method); + Expect.type(contraSame.method); + + Invariant invSame = new Invariant(); + Expect.notType(invSame.method); + Expect.type(invSame.method); + + LegacyCovariant legacyDiff = new LegacyCovariant(); + Expect.type(legacyDiff.method); + Expect.type(legacyDiff.method); + + LegacyCovariant legacySame = new LegacyCovariant(); + Expect.type(legacySame.method); + Expect.type(legacySame.method); + + NoSuchMethod nsm = new NoSuchMethod(); + Expect.notType(nsm.method); + Expect.type(nsm.method); +} diff --git a/tests/language/variance/variance_multi_subclass_error_test.dart b/tests/language/variance/variance_multi_subclass_error_test.dart new file mode 100644 index 000000000000..ed790c7394d6 --- /dev/null +++ b/tests/language/variance/variance_multi_subclass_error_test.dart @@ -0,0 +1,84 @@ +// 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 erroneous variance usage multiple type parameters. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); + +class Covariant {} +class Contravariant {} + +class MultiTwo {} +class MultiThree {} + +class A extends Covariant {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class B extends MultiThree {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MultiThree'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class C extends MultiTwo {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'. +// ^ +// [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class D extends MultiThree {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MultiThree'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class E extends MultiThree, Covariant, Covariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiThree'. +// ^ +// [cfe] Can't use 'out' type variable 'U' in an 'inout' position in supertype 'MultiThree'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class F extends MultiTwo, Contravariant> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'. +// ^ +// [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class G extends MultiThree, CovFunction, CovFunction> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiThree'. +// ^ +// [cfe] Can't use 'out' type variable 'U' in an 'inout' position in supertype 'MultiThree'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class H extends MultiTwo, ContraFunction> {} +// ^ +// [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'. +// ^ +// [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE diff --git a/tests/language/variance/variance_multi_subclass_test.dart b/tests/language/variance/variance_multi_subclass_test.dart new file mode 100644 index 000000000000..ae4f57ae5ab2 --- /dev/null +++ b/tests/language/variance/variance_multi_subclass_test.dart @@ -0,0 +1,42 @@ +// 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 variance usage multiple type parameters. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); + +class Covariant {} +class Contravariant {} + +class A {} +class B {} + +class C extends A {} +class D extends B {} +class E extends B {} + +class F extends A, Contravariant> {} +class G extends A>, Contravariant>> {} +class H extends B, Covariant, Covariant> {} + +class I extends A, ContraFunction> {} +class J extends A>, ContraFunction>> {} +class K extends B, CovFunction, CovFunction> {} + +main() { + A a = A(); + B b = B(); + C c = C(); + D d = D(); + E e = E(); + F f = F(); + G g = G(); + H h = H(); + I i = I(); + J j = J(); + K k = K(); +} diff --git a/tests/language/variance/variance_out_field_error_test.dart b/tests/language/variance/variance_out_field_error_test.dart new file mode 100644 index 000000000000..8fc79a91e8e8 --- /dev/null +++ b/tests/language/variance/variance_out_field_error_test.dart @@ -0,0 +1,64 @@ +// 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 erroneous field usage for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class A { + void set a(T value) => value; + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + final void Function(T) b = (T val) {}; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + late T c; +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + T? d = null; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. +} + +mixin BMixin { + void set a(T value) => value; + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + final void Function(T) b = (T val) {}; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + late T c; +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + T? d = null; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. +} + +abstract class C { + void set a(T value) => value; + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. +} + +class D extends C { + late var a; + // ^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. +} diff --git a/tests/language/variance/variance_out_field_test.dart b/tests/language/variance/variance_out_field_test.dart new file mode 100644 index 000000000000..3059cb8259e1 --- /dev/null +++ b/tests/language/variance/variance_out_field_test.dart @@ -0,0 +1,72 @@ +// 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 various fields for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +typedef Void2Int = int? Function(); + +class A { + final T? a = null; + final T? Function() b = () => null; + T? get c => null; + A get d => this; + covariant late T e; + void set f(covariant T value) => value; +} + +mixin BMixin { + final T? a = null; + final T? Function() b = () => null; + T? get c => null; + BMixin get d => this; + covariant late T e; + void set f(covariant T value) => value; +} + +class B with BMixin {} + +void testClass() { + A a = new A(); + + Expect.isNull(a.a); + + Expect.type(a.b); + Expect.isNull(a.b()); + + Expect.isNull(a.c); + + Expect.isNull(a.d.a); + + a.e = 2; + Expect.equals(2, a.e); + + a.f = 2; +} + +void testMixin() { + B b = new B(); + + Expect.isNull(b.a); + + Expect.type(b.b); + Expect.isNull(b.b()); + + Expect.isNull(b.c); + + Expect.isNull(b.d.a); + + b.e = 2; + Expect.equals(2, b.e); + + b.f = 2; +} + +main() { + testClass(); + testMixin(); +} diff --git a/tests/language/variance/variance_out_inference_error_test.dart b/tests/language/variance/variance_out_inference_error_test.dart new file mode 100644 index 000000000000..809cdfb44fd7 --- /dev/null +++ b/tests/language/variance/variance_out_inference_error_test.dart @@ -0,0 +1,60 @@ +// 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 local inference errors for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class CovBound { + CovBound(T x, void Function(T) y) {} +} + +Exactly inferCovCov(Covariant x, Covariant y) => new Exactly(); +Exactly inferCovBound(CovBound x) => new Exactly(); + +main() { + Exactly upper; + Exactly middle; + Exactly lower; + + // Lower <: T <: Middle. + // We choose Middle. + var inferredMiddle = inferCovCov(Covariant(), Covariant()); + lower = inferredMiddle; + // ^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // Lower <: T <: Upper. + // We choose Upper. + var inferredUpper = inferCovCov(Covariant(), Covariant()); + lower = inferredUpper; + // ^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // Inference for Covbound(...) produces Lower <: T <: Upper. + // Since T is covariant, we choose Lower as the solution. + var inferredCovLower = inferCovBound(CovBound(Lower(), (Upper x) {})); + upper = inferredCovLower; + // ^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. + + // Inference for Covbound(...) produces Lower <: T <: Middle. + // Since T is covariant, we choose Lower as the solution. + var inferredCovLower2 = inferCovBound(CovBound(Lower(), (Middle x) {})); + middle = inferredCovLower2; + // ^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly'. +} diff --git a/tests/language/variance/variance_out_inference_test.dart b/tests/language/variance/variance_out_inference_test.dart new file mode 100644 index 000000000000..14b49e165e36 --- /dev/null +++ b/tests/language/variance/variance_out_inference_test.dart @@ -0,0 +1,55 @@ +// 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 local inference for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} + +class Exactly {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class CovBound { + CovBound(T x, void Function(T) y) {} +} + +Exactly inferCovCov(Covariant x, Covariant y) => new Exactly(); +Exactly inferCovBound(CovBound x) => new Exactly(); + +main() { + Exactly upper; + Exactly lower; + + // Upper <: T + // Upper <: T + // Choose Upper + var inferredUpper = inferCovCov(Covariant(), Covariant()); + upper = inferredUpper; + + // Upper <: T + // Middle <: T + // Choose Upper since it is the lowest upper bound of Upper and Middle. + var inferredUpper2 = inferCovCov(Covariant(), Covariant()); + upper = inferredUpper2; + + // Upper <: T + // Lower <: T + // Choose Upper since it is the lowest upper bound of Upper and Lower. + var inferredUpper3 = inferCovCov(Covariant(), Covariant()); + upper = inferredUpper3; + + // Lower <: T <: Upper + // Choose Lower. + var inferredCovLower = inferCovBound(CovBound(Lower(), (Upper x) {})); + lower = inferredCovLower; + + // Lower <: T <: Middle + // Choose Lower. + var inferredCovLower2 = inferCovBound(CovBound(Lower(), (Middle x) {})); + lower = inferredCovLower2; +} diff --git a/tests/language/variance/variance_out_method_error_test.dart b/tests/language/variance/variance_out_method_error_test.dart new file mode 100644 index 000000000000..54ebd174e26f --- /dev/null +++ b/tests/language/variance/variance_out_method_error_test.dart @@ -0,0 +1,357 @@ +// 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 erroneous method signatures and return types for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef Inv = void Function(); +typedef Cov = T Function(); +typedef Contra = void Function(T); + +class Covariant {} +class Contravariant {} +class Invariant {} + +class A { + void method1(T x) {} + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method2(Cov x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contra method3() => (T val) {}; +//^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method4(Cov> x) {} + // ^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contra> method5() => (Cov method) {}; +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + Cov> method6() { +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + return () { + return (T x) {}; + }; + } + + void method7(Contra> x) {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Inv method8() => throw "uncalled"; +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type. + + void method9(Inv x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + Contravariant method10() => throw "uncalled"; +//^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method11(Covariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Invariant method12() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type. + + void method13(Invariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method14(Covariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method15(Contravariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contravariant> method16() => Contravariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + Covariant> method17() => Covariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method18>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method19>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method20({required T x}) {} + // ^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method21({required Cov x}) {} + // ^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method22({required Covariant x}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method23({required Covariant x, required Contravariant y}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method24() {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method25>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method26>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. +} + +mixin BMixin { + void method1(T x) {} + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method2(Cov x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contra method3() => (T val) {}; +//^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method4(Cov> x) {} + // ^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contra> method5() => (Cov method) {}; +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + Cov> method6() { +//^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + return () { + return (T x) {}; + }; + } + + void method7(Contra> x) {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Inv method8() => throw "uncalled"; +//^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type. + + void method9(Inv x) {} + // ^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + Contravariant method10() => throw "uncalled"; +//^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method11(Covariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Invariant method12() => throw "uncalled"; +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type. + + void method13(Invariant x) {} + // ^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method14(Covariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method15(Contravariant> x) {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + Contravariant> method16() => Contravariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + Covariant> method17() => Covariant>(); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + + void method18>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method19>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method20({required T x}) {} + // ^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method21({required Cov x}) {} + // ^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method22({required Covariant x}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method23({required Covariant x, required Contravariant y}) {} + // ^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + + void method24() {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method25>() {} + // ^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. + + void method26>() {} + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // [cfe] Can't use 'out' type variable 'T' in an 'inout' position. +} + +class B { + void method1(Cov> x) {} + // ^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. + Contra> method2() { +//^^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type. + throw "uncalled"; + } +} + +class C { + void method(T x) {} +} + +class D extends C { + @override + void method(T x) {} + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION + // ^ + // [cfe] Can't use 'out' type variable 'T' in an 'in' position. +} diff --git a/tests/language/variance/variance_out_method_test.dart b/tests/language/variance/variance_out_method_test.dart new file mode 100644 index 000000000000..6d3a9a5bbbfe --- /dev/null +++ b/tests/language/variance/variance_out_method_test.dart @@ -0,0 +1,231 @@ +// 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 `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +typedef Cov = T Function(); +typedef Contra = void Function(T); + +Cov covFunction = () => 2; +Contra contraFunction = (int val) {}; + +class Covariant {} +class Contravariant {} + +class A { + T? method1() => null; + void method2(Contra x) {} + Cov method3() { + return () => null; + } + + void method4(Contra> x) {} + void method5(Cov> x) {} + Contra> method6() { + return (Contra x) { + Expect.type>(x); + }; + } + + Cov> method7() { + return () { + return () => null; + }; + } + + void method8(Contravariant x) {} + Covariant? method9() => null; + void method10(Contravariant> x) {} + Covariant>? method11() => null; + void method12(Covariant> x) {} + Contravariant>? method13() => null; + + void method14(covariant T x) {} + void method15(covariant Contra x) {} + void method16(covariant Cov x) {} + void method17(covariant Contravariant x) {} + void method18(covariant Covariant x) {} + + void method19({Contravariant? x}) {} + void method20({Contra? x}) {} +} + +mixin BMixin { + T? method1() => null; + void method2(Contra x) {} + Cov method3() { + return () => null; + } + + void method4(Contra> x) {} + void method5(Cov> x) {} + Contra> method6() { + return (Contra x) { + Expect.type>(x); + }; + } + + Cov> method7() { + return () { + return () => null; + }; + } + + void method8(Contravariant x) {} + Covariant? method9() => null; + void method10(Contravariant> x) {} + Covariant>? method11() => null; + void method12(Covariant> x) {} + Contravariant>? method13() => null; + + void method14(covariant T x) {} + void method15(covariant Contra x) {} + void method16(covariant Cov x) {} + void method17(covariant Contravariant x) {} + void method18(covariant Covariant x) {} + + void method19({Contravariant? x}) {} + void method20({Contra? x}) {} +} + +class B with BMixin {} + +class C { + void method1(Contra> x) {} + A method2() { + return A(); + } +} + +class D { + T? method() => null; + void method2(T x) {} + void method3(covariant T x) {} +} + +class E extends D { + @override + T? method() => null; + + @override + void method3(covariant T x) {} +} + +void testClass() { + A a = new A(); + + Expect.isNull(a.method1()); + + a.method2(contraFunction); + + Expect.type>(a.method3()); + Cov method3Function = a.method3(); + Expect.isNull(method3Function()); + + a.method4((Cov x) {}); + + a.method5(() { + return contraFunction; + }); + + Expect.type>>(a.method6()); + Contra> method6Function = a.method6(); + method6Function(contraFunction); + + Expect.type>>(a.method7()); + Cov> method7Function = a.method7(); + Expect.type>(method7Function()); + Cov method7NestedFunction = method7Function(); + Expect.isNull(method7NestedFunction()); + + a.method8(Contravariant()); + Expect.isNull(a.method9()); + a.method10(Contravariant>()); + Expect.isNull(a.method11()); + a.method12(Covariant>()); + Expect.isNull(a.method13()); + + a.method14(3); + a.method15(contraFunction); + a.method16(covFunction); + a.method17(Contravariant()); + a.method18(Covariant()); + + a.method19(); + a.method20(); +} + +void testMixin() { + B b = new B(); + + Expect.isNull(b.method1()); + + b.method2(contraFunction); + + Expect.type>(b.method3()); + Cov method3Function = b.method3(); + Expect.isNull(method3Function()); + + b.method4((Cov x) {}); + + b.method5(() { + return contraFunction; + }); + + Expect.type>>(b.method6()); + Contra> method6Function = b.method6(); + method6Function(contraFunction); + + Expect.type>>(b.method7()); + Cov> method7Function = b.method7(); + Expect.type>(method7Function()); + Cov method7NestedFunction = method7Function(); + Expect.isNull(method7NestedFunction()); + + b.method8(Contravariant()); + Expect.isNull(b.method9()); + b.method10(Contravariant>()); + Expect.isNull(b.method11()); + b.method12(Covariant>()); + Expect.isNull(b.method13()); + + b.method14(3); + b.method15(contraFunction); + b.method16(covFunction); + b.method17(Contravariant()); + b.method18(Covariant()); + + b.method19(); + b.method20(); +} + +void testClassInMethods() { + C c = new C(); + + c.method1((A x) {}); + + Expect.type>(c.method2()); +} + +void testOverrideLegacyMethods() { + E e = new E(); + Expect.isNull(e.method()); + e.method2(3); + e.method3(3); + + D d = e; + Expect.throws(() => d.method2("test")); + Expect.throws(() => d.method3("test")); +} + +main() { + testClass(); + testMixin(); + testClassInMethods(); + testOverrideLegacyMethods(); +} diff --git a/tests/language/variance/variance_out_subclass_error_test.dart b/tests/language/variance/variance_out_subclass_error_test.dart new file mode 100644 index 000000000000..046395c6b3a6 --- /dev/null +++ b/tests/language/variance/variance_out_subclass_error_test.dart @@ -0,0 +1,124 @@ +// 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 erroneous subclass usage for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); +typedef InvFunction = T Function(T); + +class Covariant {} +class Contravariant {} +class Invariant {} +mixin MCovariant {} +mixin MContravariant {} +mixin MInvariant {} + +class A extends Contravariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class B implements Contravariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class C with MContravariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MContravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class D extends Invariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class E implements Invariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class F with MInvariant {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MInvariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class G extends Covariant> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class H extends Contravariant> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class I extends Covariant> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class J extends Covariant>> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class K extends Covariant>> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class L extends Covariant>> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class M extends Contravariant>> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class N extends Covariant> {} +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Covariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class O = Covariant with MContravariant; +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MContravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class P = Contravariant with MCovariant; +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE + +class Q = Invariant with MInvariant; +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MInvariant'. +// ^ +// [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'. +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE +// ^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE diff --git a/tests/language/variance/variance_out_subclass_test.dart b/tests/language/variance/variance_out_subclass_test.dart new file mode 100644 index 000000000000..0c8861df7b61 --- /dev/null +++ b/tests/language/variance/variance_out_subclass_test.dart @@ -0,0 +1,58 @@ +// 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 subclass usage for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +typedef CovFunction = T Function(); +typedef ContraFunction = void Function(T); + +class LegacyCovariant {} +class Covariant {} +class Contravariant {} +mixin MLegacyCovariant {} +mixin MCovariant {} + +class A extends LegacyCovariant {} +class B implements LegacyCovariant {} +class C with MLegacyCovariant {} + +class D extends Covariant {} +class E implements Covariant {} +class F with MCovariant {} + +class G extends Covariant> {} +class H extends Contravariant> {} + +class I extends Covariant> {} +class J extends Covariant>> {} +class K extends Contravariant>> {} + +class L extends Covariant>> {} + +class M extends Covariant>> {} + +class N = Covariant with MCovariant; +class O = Contravariant> with MCovariant; +class P = Covariant with MCovariant>; + +main() { + A a = A(); + B b = B(); + C c = C(); + D d = D(); + E e = E(); + F f = F(); + G g = G(); + H h = H(); + I i = I(); + J j = J(); + K k = K(); + L l = L(); + M m = M(); + N n = N(); + O o = O(); + P p = P(); +} diff --git a/tests/language/variance/variance_out_subtyping_error_test.dart b/tests/language/variance/variance_out_subtyping_error_test.dart new file mode 100644 index 000000000000..a85f4cb945b7 --- /dev/null +++ b/tests/language/variance/variance_out_subtyping_error_test.dart @@ -0,0 +1,80 @@ +// 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 erroneous subtyping for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} + +class Upper {} +class Middle extends Upper {} +class Lower {} + +class A { + Covariant method1() { + return Covariant(); + } + + void method2(Covariant x) {} +} + +class B extends A { + @override + Covariant method1() { + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // [cfe] The return type of the method 'B.method1' is 'Covariant', which does not match the return type, 'Covariant', of the overridden method, 'A.method1'. + return new Covariant(); + } + + @override + void method2(Covariant x) {} + // ^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE + // ^ + // [cfe] The parameter 'x' of the method 'B.method2' has type 'Covariant', which does not match the corresponding type, 'Covariant', in the overridden method, 'A.method2'. +} + +class C> {} + +class D { + C> method1() { + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Covariant' doesn't conform to the bound 'Covariant' of the type variable 'T' on 'C' in the return type. + return C>(); + // ^ + // [cfe] Type argument 'Covariant' doesn't conform to the bound 'Covariant' of the type variable 'T' on 'C'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + } +} + +void testCall(Iterable> x) {} + +main() { + C> c = new C>(); + //^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + // ^ + // [cfe] Type argument 'Covariant' doesn't conform to the bound 'Covariant' of the type variable 'T' on 'C'. + // ^ + // [cfe] Type argument 'Covariant' doesn't conform to the bound 'Covariant' of the type variable 'T' on 'C'. + // ^^^^^^^^^^^^^^^^ + // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS + + Iterable> iterableLower = [new Covariant()]; + List> listMiddle = [new Covariant()]; + iterableLower = listMiddle; + // ^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'List>' can't be assigned to a variable of type 'Iterable>'. + + testCall(listMiddle); + // ^^^^^^^^^^ + // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE + // [cfe] The argument type 'List>' can't be assigned to the parameter type 'Iterable>'. +} diff --git a/tests/language/variance/variance_out_subtyping_test.dart b/tests/language/variance/variance_out_subtyping_test.dart new file mode 100644 index 000000000000..00f5ed3cf928 --- /dev/null +++ b/tests/language/variance/variance_out_subtyping_test.dart @@ -0,0 +1,102 @@ +// 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 subtyping for the `out` variance modifier. + +// SharedOptions=--enable-experiment=variance + +import "package:expect/expect.dart"; + +class Covariant {} + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +class A { + Covariant method1() { + return new Covariant(); + } + + void method2(Covariant x) {} +} + +class B extends A { + @override + Covariant method1() { + return new Covariant(); + } + + @override + void method2(Covariant x) {} +} + +class C extends A { + @override + Covariant method1() { + return new Covariant(); + } + + @override + void method2(Covariant x) {} +} + +class D> {} + +class E { + D> method1() { + return D>(); + } +} + +class F { + D> method1() { + return D>(); + } +} + +void testCall(Iterable> x) {} + +main() { + A a = new A(); + Expect.type>(a.method1()); + Expect.type>(a.method1()); + Expect.notType>(a.method1()); + a.method2(new Covariant()); + a.method2(new Covariant()); + + B b = new B(); + Expect.type>(b.method1()); + Expect.type>(b.method1()); + Expect.type>(b.method1()); + b.method2(new Covariant()); + b.method2(new Covariant()); + + C c = new C(); + Expect.type>(c.method1()); + Expect.type>(c.method1()); + Expect.notType>(c.method1()); + c.method2(new Covariant()); + c.method2(new Covariant()); + + D> dLower = new D>(); + D> dMiddle = new D>(); + + E e = new E(); + Expect.type>>(e.method1()); + Expect.type>>(e.method1()); + + F f = new F(); + Expect.type>>(f.method1()); + + Iterable> iterableMiddle = [new Covariant()]; + List> listLower = [new Covariant()]; + iterableMiddle = listLower; + + testCall(listLower); + + Expect.subtype, Covariant>(); + Expect.subtype, Covariant>(); + Expect.notSubtype, Covariant>(); +} diff --git a/tests/language/variance/variance_unconstrained_inference_test.dart b/tests/language/variance/variance_unconstrained_inference_test.dart new file mode 100644 index 000000000000..fed460b564a0 --- /dev/null +++ b/tests/language/variance/variance_unconstrained_inference_test.dart @@ -0,0 +1,26 @@ +// 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 unconstrained inferencing with sound variance. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} +class Invariant {} + +void covariantListInfer(Covariant> x) {} +void contravariantListInfer(Contravariant> x) {} +void invariantListInfer(Invariant> x) {} + +main() { + var cov = new Covariant(); + covariantListInfer(Covariant()); + + var contra = new Contravariant(); + contravariantListInfer(Contravariant()); + + var inv = new Invariant(); + invariantListInfer(Invariant()); +} diff --git a/tests/language/variance/variance_upper_lower_bounds_error_test.dart b/tests/language/variance/variance_upper_lower_bounds_error_test.dart new file mode 100644 index 000000000000..2c69097d9cf4 --- /dev/null +++ b/tests/language/variance/variance_upper_lower_bounds_error_test.dart @@ -0,0 +1,102 @@ +// 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 erroneous upper and lower bounds computation with respect to +// variance modifiers. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} +class Invariant {} +class LegacyCovariant {} + +class Multi {} + +class Exactly {} +Exactly exactly(T x) => new Exactly(); + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +main() { + bool condition = true; + + var contraLowerActual = + exactly(condition ? Contravariant() : Contravariant()); + Exactly> contraUpperExpected = contraLowerActual; + // ^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var contraMiddleActual = + exactly(condition ? Contravariant() : Contravariant()); + contraUpperExpected = contraMiddleActual; + // ^^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var covMiddleActual = + exactly(condition ? Covariant() : Covariant()); + Exactly> covLowerExpected = covMiddleActual; + // ^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var covUpperActual = + exactly(condition ? Covariant() : Covariant()); + covLowerExpected = covUpperActual; + // ^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var invObjectActual = + exactly(condition ? Invariant() : Invariant()); + Exactly> invMiddleExpected = invObjectActual; + // ^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly>'. + Exactly> invUpperExpected = invObjectActual; + // ^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly>'. + + var legacyCovMiddleActual = + exactly(condition ? LegacyCovariant() : LegacyCovariant()); + Exactly> legacyCovLowerExpected = + legacyCovMiddleActual; + // ^^^^^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var legacyCovUpperActual = + exactly(condition ? LegacyCovariant() : LegacyCovariant()); + legacyCovLowerExpected = legacyCovUpperActual; + // ^^^^^^^^^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var multiActual = exactly(condition + ? Multi() + : Multi()); + Exactly> multiExpected = multiActual; + // ^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly>'. + + var multiActual2 = exactly( + condition ? Multi() : Multi()); + Exactly> multiObjectExpected = multiActual2; + // ^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly' can't be assigned to a variable of type 'Exactly>'. + + var multiActual3 = exactly( + condition ? Multi() : Multi()); + Exactly multiObjectExpected2 = multiActual3; + // ^^^^^^^^^^^^ + // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT + // [cfe] A value of type 'Exactly>' can't be assigned to a variable of type 'Exactly'. +} diff --git a/tests/language/variance/variance_upper_lower_bounds_test.dart b/tests/language/variance/variance_upper_lower_bounds_test.dart new file mode 100644 index 000000000000..ceb9ac88b915 --- /dev/null +++ b/tests/language/variance/variance_upper_lower_bounds_test.dart @@ -0,0 +1,71 @@ +// 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 upper and lower bounds computation with respect to variance modifiers. + +// SharedOptions=--enable-experiment=variance + +class Covariant {} +class Contravariant {} +class Invariant {} +class LegacyCovariant {} + +class Multi {} + +class Exactly {} +Exactly exactly(T x) => new Exactly(); + +class Upper {} +class Middle extends Upper {} +class Lower extends Middle {} + +main() { + bool condition = true; + + var contraLowerActual = + exactly(condition ? Contravariant() : Contravariant()); + Exactly> contraLowerExpected = contraLowerActual; + + var contraMiddleActual = + exactly(condition ? Contravariant() : Contravariant()); + Exactly> contraMiddleExpected = contraMiddleActual; + + var covMiddleActual = + exactly(condition ? Covariant() : Covariant()); + Exactly> covMiddleExpected = covMiddleActual; + + var covUpperActual = + exactly(condition ? Covariant() : Covariant()); + Exactly> covUpperExpected = covUpperActual; + + var invMiddleActual = + exactly(condition ? Invariant() : Invariant()); + Exactly> invMiddleExpected = invMiddleActual; + + var invObjectActual = + exactly(condition ? Invariant() : Invariant()); + Exactly invObjectExpected = invObjectActual; + + var legacyCovMiddleActual = + exactly(condition ? LegacyCovariant() : LegacyCovariant()); + Exactly> legacyCovMiddleExpected = + legacyCovMiddleActual; + + var legacyCovUpperActual = + exactly(condition ? LegacyCovariant() : LegacyCovariant()); + Exactly> legacyCovUpperExpected = legacyCovUpperActual; + + var multiActual = exactly(condition + ? Multi() + : Multi()); + Exactly> multiExpected = multiActual; + + var multiActual2 = exactly( + condition ? Multi() : Multi()); + Exactly multiObjectExpected = multiActual2; + + var multiActual3 = exactly( + condition ? Multi() : Multi()); + Exactly> multiObjectExpected2 = multiActual3; +}