blob: bc5420f1b504d4c9ad52266e0ccbacd38f34ce9c [file] [log] [blame]
// 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.
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/types.dart';
import 'package:expect/expect.dart';
import '../helpers/type_test_helper.dart';
const List<FunctionTypeData> existentialTypeData = const <FunctionTypeData>[
const FunctionTypeData('void', 'F1', '<T>(T t)'),
const FunctionTypeData('void', 'F2', '<S>(S s)'),
const FunctionTypeData('void', 'F3', '<U, V>(U u, V v)'),
const FunctionTypeData('void', 'F4', '<U, V>(V v, U u)'),
const FunctionTypeData('void', 'F5', '<W extends num>(W w)'),
const FunctionTypeData('void', 'F6', '<X extends int>(X x)'),
const FunctionTypeData('void', 'F7', '<Y extends num>(Y y, [int i])'),
const FunctionTypeData('Z', 'F8', '<Z extends num>(Z z)'),
const FunctionTypeData('T', 'F13', '<T>(T t1, T t2)'),
const FunctionTypeData('S', 'F14', '<S>(S s1, S s2)'),
];
main() {
asyncTest(() async {
var env = await TypeEnvironment.create(
createTypedefs(existentialTypeData, additionalData: """
class C1 {}
class C2 {}
class C3<T> {
factory C3.fact() => C3.gen();
C3.gen();
}
class C4 implements C3<C4> {}
void F9<U extends V, V>(U u, V v) {}
F10() {
void local<A extends B, B>(A a, B b) {}
}
void F11<Q extends C3<Q>>(Q q) {}
void F12<P extends C3<P>>(P p) {}
class C5<T> {
Map<T,A> F15<A extends B, B extends T>(A a, B b) => null;
Map<T,A> F16<A extends T, B extends A>(A a, B b) => null;
T F17<A extends List<B>, B extends Map<T,A>>(A a, B b, T t) => null;
T F18<P extends T>(
[Q Function<Q extends P>(P, Q, T) f1,
X Function<X extends P>(P, X, T) f2]) => null;
}
main() {
${createUses(existentialTypeData)}
new C1();
new C2();
new C3.fact();
new C4();
F9(null, null);
F10();
F11(null);
F12(null);
new C5<num>().F15<int, int>(1, 2);
new C5<num>().F16<int, int>(1, 2);
new C5<num>().F17(null, null, null);
new C5<num>().F18();
}
"""));
testToString(FunctionType type, String expectedToString) {
Expect.equals(expectedToString, type.toString());
}
testBounds(FunctionType type, List<DartType> expectedBounds) {
Expect.equals(expectedBounds.length, type.typeVariables.length,
"Unexpected type variable count in $type.");
for (int i = 0; i < expectedBounds.length; i++) {
Expect.equals(expectedBounds[i], type.typeVariables[i].bound,
"Unexpected ${i}th bound in $type.");
}
}
testInstantiate(FunctionType type, List<DartType> instantiation,
String expectedToString) {
DartType result = type.instantiate(instantiation);
Expect.equals(expectedToString, result.toString(),
"Unexpected instantiation of $type with $instantiation: $result");
}
void testSubst(List<DartType> arguments, List<DartType> parameters,
DartType type1, String expectedToString) {
DartType subst = type1.subst(arguments, parameters);
Expect.equals(expectedToString, subst.toString(),
"$type1.subst($arguments,$parameters)");
}
testRelations(DartType a, DartType b,
{bool areEqual: false, bool isSubtype: false}) {
if (areEqual) {
isSubtype = true;
}
Expect.equals(
areEqual,
a == b,
"Expected `$a` and `$b` to be ${areEqual ? 'equal' : 'non-equal'}, "
"but they are not.");
Expect.equals(
isSubtype,
env.isSubtype(a, b),
"Expected `$a` ${isSubtype ? '' : 'not '}to be a subtype of `$b`, "
"but it is${isSubtype ? ' not' : ''}.");
if (isSubtype) {
Expect.isTrue(env.isPotentialSubtype(a, b),
'$a <: $b but not a potential subtype.');
}
}
InterfaceType Object_ = env['Object'];
InterfaceType num_ = env['num'];
InterfaceType int_ = env['int'];
InterfaceType C1 = instantiate(env.getClass('C1'), []);
InterfaceType C2 = instantiate(env.getClass('C2'), []);
ClassEntity C3 = env.getClass('C3');
InterfaceType C4 = instantiate(env.getClass('C4'), []);
FunctionType F1 = env.getFieldType('F1');
FunctionType F2 = env.getFieldType('F2');
FunctionType F3 = env.getFieldType('F3');
FunctionType F4 = env.getFieldType('F4');
FunctionType F5 = env.getFieldType('F5');
FunctionType F6 = env.getFieldType('F6');
FunctionType F7 = env.getFieldType('F7');
FunctionType F8 = env.getFieldType('F8');
FunctionType F9 = env.getMemberType('F9');
FunctionType F10 = env.getClosureType('F10');
FunctionType F11 = env.getMemberType('F11');
FunctionType F12 = env.getMemberType('F12');
FunctionType F13 = env.getFieldType('F13');
FunctionType F14 = env.getFieldType('F14');
ClassEntity C5 = env.getClass('C5');
TypeVariableType C5_T =
(env.getElementType('C5') as InterfaceType).typeArguments.single;
FunctionType F15 = env.getMemberType('F15', C5);
FunctionType F16 = env.getMemberType('F16', C5);
FunctionType F17 = env.getMemberType('F17', C5);
FunctionType F18 = env.getMemberType('F18', C5);
List<FunctionType> all = <FunctionType>[
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
];
all.forEach(print);
testToString(F1, 'void Function<#A>(#A)');
testToString(F2, 'void Function<#A>(#A)');
testToString(F3, 'void Function<#A,#B>(#A,#B)');
testToString(F4, 'void Function<#A,#B>(#B,#A)');
testToString(F5, 'void Function<#A extends num>(#A)');
testToString(F6, 'void Function<#A extends int>(#A)');
testToString(F7, 'void Function<#A extends num>(#A,[int])');
testToString(F8, '#A Function<#A extends num>(#A)');
testToString(F9, 'void Function<#A extends #B,#B>(#A,#B)');
testToString(F10, 'void Function<#A extends #B,#B>(#A,#B)');
testToString(F11, 'void Function<#A extends C3<#A>>(#A)');
testToString(F12, 'void Function<#A extends C3<#A>>(#A)');
testToString(F13, '#A Function<#A>(#A,#A)');
testToString(F14, '#A Function<#A>(#A,#A)');
testToString(
F15, 'Map<C5.T,#A> Function<#A extends #B,#B extends C5.T>(#A,#B)');
testToString(
F16, 'Map<C5.T,#A> Function<#A extends C5.T,#B extends #A>(#A,#B)');
testToString(F17,
'C5.T Function<#A extends List<#B>,#B extends Map<C5.T,#A>>(#A,#B,Object)');
testToString(
F18,
'C5.T Function<#A extends C5.T>(['
'#A2 Function<#A2 extends #A>(#A,#A2,C5.T),'
'#A3 Function<#A3 extends #A>(#A,#A3,C5.T)])');
testBounds(F1, [Object_]);
testBounds(F2, [Object_]);
testBounds(F3, [Object_, Object_]);
testBounds(F4, [Object_, Object_]);
testBounds(F5, [num_]);
testBounds(F6, [int_]);
testBounds(F7, [num_]);
testBounds(F8, [num_]);
testBounds(F9, [F9.typeVariables.last, Object_]);
testBounds(F10, [F10.typeVariables.last, Object_]);
testBounds(F11, [
instantiate(C3, [F11.typeVariables.last])
]);
testBounds(F12, [
instantiate(C3, [F12.typeVariables.last])
]);
testBounds(F13, [Object_]);
testBounds(F14, [Object_]);
testInstantiate(F1, [C1], 'void Function(C1)');
testInstantiate(F2, [C2], 'void Function(C2)');
testInstantiate(F3, [C1, C2], 'void Function(C1,C2)');
testInstantiate(F4, [C1, C2], 'void Function(C2,C1)');
testInstantiate(F5, [num_], 'void Function(num)');
testInstantiate(F6, [int_], 'void Function(int)');
testInstantiate(F7, [int_], 'void Function(int,[int])');
testInstantiate(F8, [int_], 'int Function(int)');
testInstantiate(F9, [int_, num_], 'void Function(int,num)');
testInstantiate(F10, [int_, num_], 'void Function(int,num)');
testInstantiate(F11, [C4], 'void Function(C4)');
testInstantiate(F12, [C4], 'void Function(C4)');
testInstantiate(F13, [C1], 'C1 Function(C1,C1)');
testInstantiate(F14, [C2], 'C2 Function(C2,C2)');
testInstantiate(F15, [int_, num_], 'Map<C5.T,int> Function(int,num)');
testInstantiate(F16, [num_, int_], 'Map<C5.T,num> Function(num,int)');
testSubst([num_], [C5_T], F15,
'Map<num,#A> Function<#A extends #B,#B extends num>(#A,#B)');
testSubst([num_], [C5_T], F16,
'Map<num,#A> Function<#A extends num,#B extends #A>(#A,#B)');
testSubst([num_], [C5_T], F17,
'num Function<#A extends List<#B>,#B extends Map<num,#A>>(#A,#B,Object)');
testSubst(
[num_],
[C5_T],
F18,
'num Function<#A extends num>(['
'#A2 Function<#A2 extends #A>(#A,#A2,num),'
'#A3 Function<#A3 extends #A>(#A,#A3,num)])');
Map<FunctionType, List<FunctionType>> expectedEquals =
<FunctionType, List<FunctionType>>{
F1: [F2],
F2: [F1],
F9: [F10],
F10: [F9],
F11: [F12],
F12: [F11],
F13: [F14],
F14: [F13],
};
Map<FunctionType, List<FunctionType>> expectedSubtype =
<FunctionType, List<FunctionType>>{
F7: [F5],
F8: [F5],
};
for (FunctionType f1 in all) {
for (FunctionType f2 in all) {
testRelations(f1, f2,
areEqual: identical(f1, f2) ||
(expectedEquals[f1]?.contains(f2) ?? false),
isSubtype: expectedSubtype[f1]?.contains(f2) ?? false);
}
}
testRelations(F1.typeVariables.first, F1.typeVariables.first,
areEqual: true);
testRelations(F1.typeVariables.first, F2.typeVariables.first);
env.elementEnvironment.forEachConstructor(C3,
(ConstructorEntity constructor) {
Expect.equals(
0,
constructor.parameterStructure.typeParameters,
"Type parameters found on constructor $constructor: "
"${constructor.parameterStructure}");
List<TypeVariableType> functionTypeVariables =
env.elementEnvironment.getFunctionTypeVariables(constructor);
Expect.isTrue(
functionTypeVariables.isEmpty,
"Function type variables found on constructor $constructor: "
"$functionTypeVariables");
});
});
}