| // Copyright (c) 2017, 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. |
| |
| // @dart = 2.9 |
| |
| import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart'; |
| import 'package:kernel/ast.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(IncludesTypeParametersCovariantlyTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class IncludesTypeParametersCovariantlyTest { |
| final TypeParameter T = new TypeParameter('T'); |
| final TypeParameter U = new TypeParameter('U'); |
| final TypeParameter V = new TypeParameter('V'); |
| |
| bool check(DartType type, List<TypeParameter> typeParameters) { |
| return type.accept(new IncludesTypeParametersNonCovariantly(typeParameters, |
| initialVariance: Variance.contravariant)); |
| } |
| |
| bool checkContravariant(DartType type, List<TypeParameter> typeParameters) { |
| return check(new FunctionType([type], const VoidType(), Nullability.legacy), |
| typeParameters); |
| } |
| |
| NamedType named(String name, DartType type) => new NamedType(name, type); |
| |
| void test_function_type() { |
| expect( |
| check( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| [T]), |
| isFalse); |
| expect( |
| check( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| [U]), |
| isFalse); |
| expect( |
| check( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| []), |
| isFalse); |
| expect( |
| check( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| [T]), |
| isFalse); |
| expect( |
| check( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| [U]), |
| isFalse); |
| expect( |
| check( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| []), |
| isFalse); |
| expect( |
| check(new FunctionType([], tpt(T), Nullability.legacy), [T]), isTrue); |
| expect( |
| check(new FunctionType([], tpt(T), Nullability.legacy), [U]), isFalse); |
| expect( |
| checkContravariant( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| [T]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| [U]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new FunctionType( |
| [tpt(T), tpt(U)], const VoidType(), Nullability.legacy), |
| []), |
| isFalse); |
| expect( |
| checkContravariant( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| [T]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| [U]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new FunctionType([], const VoidType(), Nullability.legacy, |
| namedParameters: [named('a', tpt(T)), named('b', tpt(U))]), |
| []), |
| isFalse); |
| expect( |
| checkContravariant( |
| new FunctionType([], tpt(T), Nullability.legacy), [T]), |
| isFalse); |
| expect( |
| checkContravariant( |
| new FunctionType([], tpt(T), Nullability.legacy), [U]), |
| isFalse); |
| } |
| |
| void test_interface_type() { |
| Class cls = new Class(name: 'C', typeParameters: [T, U], fileUri: dummyUri); |
| expect( |
| check( |
| new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), [T]), |
| isTrue); |
| expect( |
| check( |
| new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), [U]), |
| isTrue); |
| expect( |
| check(new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), []), |
| isFalse); |
| expect( |
| checkContravariant( |
| new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), [T]), |
| isFalse); |
| expect( |
| checkContravariant( |
| new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), [U]), |
| isFalse); |
| expect( |
| checkContravariant( |
| new InterfaceType(cls, Nullability.legacy, [tpt(T), tpt(U)]), []), |
| isFalse); |
| } |
| |
| void test_other_type() { |
| expect(check(new DynamicType(), [T, U]), isFalse); |
| expect(checkContravariant(new DynamicType(), [T, U]), isFalse); |
| } |
| |
| void test_type_parameter() { |
| expect(check(tpt(T), [T, U]), isTrue); |
| expect(check(tpt(U), [T, U]), isTrue); |
| expect(check(tpt(V), [T, U]), isFalse); |
| expect(checkContravariant(tpt(T), [T, U]), isFalse); |
| expect(checkContravariant(tpt(U), [T, U]), isFalse); |
| expect(checkContravariant(tpt(V), [T, U]), isFalse); |
| |
| // Type parameters with explicit variance do not need contravariant checks |
| // if the variance position is greater or equal to the variance of the |
| // parameter on the [Variance] lattice. |
| expect(check(tpt(T, variance: Variance.covariant), [T, U]), isTrue); |
| expect(check(tpt(T, variance: Variance.contravariant), [T, U]), isFalse); |
| expect(check(tpt(T, variance: Variance.invariant), [T, U]), isFalse); |
| expect(check(tpt(V, variance: Variance.covariant), [T, U]), isFalse); |
| expect(check(tpt(V, variance: Variance.contravariant), [T, U]), isFalse); |
| expect(check(tpt(V, variance: Variance.invariant), [T, U]), isFalse); |
| expect(checkContravariant(tpt(T, variance: Variance.covariant), [T, U]), |
| isFalse); |
| expect(checkContravariant(tpt(T, variance: Variance.contravariant), [T, U]), |
| isTrue); |
| expect(checkContravariant(tpt(T, variance: Variance.invariant), [T, U]), |
| isFalse); |
| expect(checkContravariant(tpt(V, variance: Variance.covariant), [T, U]), |
| isFalse); |
| expect(checkContravariant(tpt(V, variance: Variance.contravariant), [T, U]), |
| isFalse); |
| expect(checkContravariant(tpt(V, variance: Variance.invariant), [T, U]), |
| isFalse); |
| } |
| |
| void test_typedef_type() { |
| // typedef U F<T, U>(T x); |
| var typedefNode = new Typedef( |
| 'F', new FunctionType([tpt(T)], tpt(U), Nullability.legacy), |
| typeParameters: [T, U], fileUri: dummyUri); |
| expect( |
| check( |
| new TypedefType(typedefNode, Nullability.legacy, |
| [const DynamicType(), const DynamicType()]), |
| [V]), |
| isFalse); |
| expect( |
| check( |
| new TypedefType( |
| typedefNode, Nullability.legacy, [tpt(V), const DynamicType()]), |
| [V]), |
| isFalse); |
| expect( |
| check( |
| new TypedefType( |
| typedefNode, Nullability.legacy, [const DynamicType(), tpt(V)]), |
| [V]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new TypedefType(typedefNode, Nullability.legacy, |
| [const DynamicType(), const DynamicType()]), |
| [V]), |
| isFalse); |
| expect( |
| checkContravariant( |
| new TypedefType( |
| typedefNode, Nullability.legacy, [tpt(V), const DynamicType()]), |
| [V]), |
| isTrue); |
| expect( |
| checkContravariant( |
| new TypedefType( |
| typedefNode, Nullability.legacy, [const DynamicType(), tpt(V)]), |
| [V]), |
| isFalse); |
| } |
| |
| TypeParameterType tpt(TypeParameter param, {int variance = null}) { |
| return new TypeParameterType(param, Nullability.legacy) |
| ..parameter.variance = variance; |
| } |
| } |