blob: fcdae4cdfa5c8eb67b21214e875514a64d06bc7b [file] [log] [blame]
// Copyright (c) 2012, 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.
library type_substitution_test;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/elements/resolution_types.dart';
import 'compiler_helper.dart';
import 'type_test_helper.dart';
ResolutionDartType getType(compiler, String name) {
dynamic clazz = findElement(compiler, "Class");
clazz.ensureResolved(compiler.resolution);
dynamic element = clazz.buildScope().lookup(name);
Expect.isNotNull(element);
Expect.equals(element.kind, ElementKind.FUNCTION);
element.computeType(compiler.resolution);
FunctionSignature signature = element.functionSignature;
// Function signatures are used to be to provide void types (only occurring as
// as return types) and (inlined) function types (only occurring as method
// parameter types).
//
// Only a single type is used from each signature. That is, it is not the
// intention to check the whole signatures against eachother.
if (signature.requiredParameterCount == 0) {
// If parameters is empty, use return type.
return signature.type.returnType;
} else {
// Otherwise use the first argument type.
return signature.requiredParameters.first.type;
}
}
void main() {
testAsInstanceOf();
testTypeSubstitution();
}
void testAsInstanceOf() {
asyncTest(() => TypeEnvironment.create('''
class A<T> {}
class B<T> {}
class C<T> extends A<T> {}
class D<T> extends A<int> {}
class E<T> extends A<A<T>> {}
class F<T, U> extends B<F<T, String>> implements A<F<B<U>, int>> {}
''').then((env) {
ClassElement A = env.getElement("A");
ClassElement B = env.getElement("B");
ClassElement C = env.getElement("C");
ClassElement D = env.getElement("D");
ClassElement E = env.getElement("E");
ClassElement F = env.getElement("F");
ResolutionDartType intType = env['int'];
ResolutionDartType stringType = env['String'];
ResolutionInterfaceType C_int = instantiate(C, [intType]);
Expect.equals(instantiate(C, [intType]), C_int);
Expect.equals(instantiate(A, [intType]), C_int.asInstanceOf(A));
ResolutionInterfaceType D_int = instantiate(D, [stringType]);
Expect.equals(instantiate(A, [intType]), D_int.asInstanceOf(A));
ResolutionInterfaceType E_int = instantiate(E, [intType]);
Expect.equals(
instantiate(A, [
instantiate(A, [intType])
]),
E_int.asInstanceOf(A));
ResolutionInterfaceType F_int_string =
instantiate(F, [intType, stringType]);
Expect.equals(
instantiate(B, [
instantiate(F, [intType, stringType])
]),
F_int_string.asInstanceOf(B));
Expect.equals(
instantiate(A, [
instantiate(F, [
instantiate(B, [stringType]),
intType
])
]),
F_int_string.asInstanceOf(A));
}));
}
/**
* Test that substitution of [parameters] by [arguments] in the type found
* through [name1] is the same as the type found through [name2].
*/
void testSubstitution(
compiler, arguments, parameters, String name1, String name2) {
ResolutionDartType type1 = getType(compiler, name1);
ResolutionDartType type2 = getType(compiler, name2);
ResolutionDartType subst = type1.subst(arguments, parameters);
Expect.equals(
type2, subst, "$type1.subst($arguments,$parameters)=$subst != $type2");
}
void testTypeSubstitution() {
asyncTest(() => TypeEnvironment.create(r"""
typedef void Typedef1<X,Y>(X x1, Y y2);
typedef void Typedef2<Z>(Z z1);
class Class<T,S> {
void void1() {}
void void2() {}
void dynamic1(dynamic a) {}
void dynamic2(dynamic b) {}
void int1(int a) {}
void int2(int a) {}
void String1(String a) {}
void String2(String a) {}
void ListInt1(List<int> a) {}
void ListInt2(List<int> b) {}
void ListT1(List<T> a) {}
void ListT2(List<int> b) {}
void ListS1(List<S> a) {}
void ListS2(List<String> b) {}
void ListListT1(List<List<T>> a) {}
void ListListT2(List<List<int>> b) {}
void ListRaw1(List a) {}
void ListRaw2(List b) {}
void ListDynamic1(List<dynamic> a) {}
void ListDynamic2(List<dynamic> b) {}
void MapIntString1(Map<T,S> a) {}
void MapIntString2(Map<int,String> b) {}
void MapTString1(Map<T,String> a) {}
void MapTString2(Map<int,String> b) {}
void MapDynamicString1(Map<dynamic,String> a) {}
void MapDynamicString2(Map<dynamic,String> b) {}
void TypeVarT1(T t1) {}
void TypeVarT2(int t2) {}
void TypeVarS1(S s1) {}
void TypeVarS2(String s2) {}
void Function1a(int a(String s1)) {}
void Function2a(int b(String s2)) {}
void Function1b(void a(T t1, S s1)) {}
void Function2b(void b(int t2, String s2)) {}
void Function1c(void a(dynamic t1, dynamic s1)) {}
void Function2c(void b(dynamic t2, dynamic s2)) {}
void Typedef1a(Typedef1<T,S> a) {}
void Typedef2a(Typedef1<int,String> b) {}
void Typedef1b(Typedef1<dynamic,dynamic> a) {}
void Typedef2b(Typedef1<dynamic,dynamic> b) {}
void Typedef1c(Typedef1 a) {}
void Typedef2c(Typedef1 b) {}
void Typedef1d(Typedef2<T> a) {}
void Typedef2d(Typedef2<int> b) {}
void Typedef1e(Typedef2<S> a) {}
void Typedef2e(Typedef2<String> b) {}
}
""").then((env) {
var compiler = env.compiler;
ResolutionInterfaceType Class_T_S = env["Class"];
Expect.isNotNull(Class_T_S);
Expect.identical(Class_T_S.kind, ResolutionTypeKind.INTERFACE);
Expect.equals(2, Class_T_S.typeArguments.length);
ResolutionDartType T = Class_T_S.typeArguments[0];
Expect.isNotNull(T);
Expect.identical(T.kind, ResolutionTypeKind.TYPE_VARIABLE);
ResolutionDartType S = Class_T_S.typeArguments[1];
Expect.isNotNull(S);
Expect.identical(S.kind, ResolutionTypeKind.TYPE_VARIABLE);
ResolutionDartType intType = env['int']; //getType(compiler, "int1");
Expect.isNotNull(intType);
Expect.identical(intType.kind, ResolutionTypeKind.INTERFACE);
ResolutionDartType StringType =
env['String']; //getType(compiler, "String1");
Expect.isNotNull(StringType);
Expect.identical(StringType.kind, ResolutionTypeKind.INTERFACE);
List<ResolutionDartType> parameters = <ResolutionDartType>[T, S];
List<ResolutionDartType> arguments = <ResolutionDartType>[
intType,
StringType
];
// TODO(johnniwinther): Create types directly from strings to improve test
// readability.
testSubstitution(compiler, arguments, parameters, "void1", "void2");
testSubstitution(
compiler, arguments, parameters, "dynamic1", "dynamic2");
testSubstitution(compiler, arguments, parameters, "int1", "int2");
testSubstitution(compiler, arguments, parameters, "String1", "String2");
testSubstitution(
compiler, arguments, parameters, "ListInt1", "ListInt2");
testSubstitution(compiler, arguments, parameters, "ListT1", "ListT2");
testSubstitution(compiler, arguments, parameters, "ListS1", "ListS2");
testSubstitution(
compiler, arguments, parameters, "ListListT1", "ListListT2");
testSubstitution(
compiler, arguments, parameters, "ListRaw1", "ListRaw2");
testSubstitution(
compiler, arguments, parameters, "ListDynamic1", "ListDynamic2");
testSubstitution(
compiler, arguments, parameters, "MapIntString1", "MapIntString2");
testSubstitution(
compiler, arguments, parameters, "MapTString1", "MapTString2");
testSubstitution(compiler, arguments, parameters, "MapDynamicString1",
"MapDynamicString2");
testSubstitution(
compiler, arguments, parameters, "TypeVarT1", "TypeVarT2");
testSubstitution(
compiler, arguments, parameters, "TypeVarS1", "TypeVarS2");
testSubstitution(
compiler, arguments, parameters, "Function1a", "Function2a");
testSubstitution(
compiler, arguments, parameters, "Function1b", "Function2b");
testSubstitution(
compiler, arguments, parameters, "Function1c", "Function2c");
testSubstitution(
compiler, arguments, parameters, "Typedef1a", "Typedef2a");
testSubstitution(
compiler, arguments, parameters, "Typedef1b", "Typedef2b");
testSubstitution(
compiler, arguments, parameters, "Typedef1c", "Typedef2c");
testSubstitution(
compiler, arguments, parameters, "Typedef1d", "Typedef2d");
testSubstitution(
compiler, arguments, parameters, "Typedef1e", "Typedef2e");
// Substitution in unalias.
ResolutionDartType Typedef2_int_String = getType(compiler, "Typedef2a");
Expect.isNotNull(Typedef2_int_String);
ResolutionDartType Function_int_String =
getType(compiler, "Function2b");
Expect.isNotNull(Function_int_String);
ResolutionDartType unalias1 = Typedef2_int_String.unaliased;
Expect.equals(Function_int_String, unalias1,
'$Typedef2_int_String.unalias=$unalias1 != $Function_int_String');
ResolutionDartType Typedef1 = getType(compiler, "Typedef1c");
Expect.isNotNull(Typedef1);
ResolutionDartType Function_dynamic_dynamic =
getType(compiler, "Function1c");
Expect.isNotNull(Function_dynamic_dynamic);
ResolutionDartType unalias2 = Typedef1.unaliased;
Expect.equals(Function_dynamic_dynamic, unalias2,
'$Typedef1.unalias=$unalias2 != $Function_dynamic_dynamic');
}));
}