| // 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 '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart'; |
| import "compiler_helper.dart"; |
| import "parser_helper.dart"; |
| import "type_test_helper.dart"; |
| |
| DartType getType(compiler, String name) { |
| var clazz = findElement(compiler, "Class"); |
| clazz.ensureResolved(compiler); |
| var element = clazz.buildScope().lookup(name); |
| Expect.isNotNull(element); |
| Expect.equals(element.kind, ElementKind.FUNCTION); |
| FunctionSignature signature = element.computeSignature(compiler); |
| |
| // Function signatures are used to be to provide void types (only occuring as |
| // as return types) and (inlined) function types (only occuring 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.head.computeType(compiler); |
| } |
| } |
| |
| int length(Link link) { |
| int count = 0; |
| while (!link.isEmpty) { |
| count++; |
| link = link.tail; |
| } |
| return count; |
| } |
| |
| 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) { |
| var compiler = env.compiler; |
| |
| 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"); |
| |
| DartType numType = env['num']; |
| DartType intType = env['int']; |
| DartType stringType = env['String']; |
| |
| InterfaceType C_int = instantiate(C, [intType]); |
| Expect.equals(instantiate(C, [intType]), C_int); |
| Expect.equals(instantiate(A, [intType]), C_int.asInstanceOf(A)); |
| |
| InterfaceType D_int = instantiate(D, [stringType]); |
| Expect.equals(instantiate(A, [intType]), D_int.asInstanceOf(A)); |
| |
| InterfaceType E_int = instantiate(E, [intType]); |
| Expect.equals(instantiate(A, [instantiate(A, [intType])]), |
| E_int.asInstanceOf(A)); |
| |
| InterfaceType 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]. |
| */ |
| bool testSubstitution(compiler, arguments, parameters, |
| String name1, String name2) { |
| DartType type1 = getType(compiler, name1); |
| DartType type2 = getType(compiler, name2); |
| DartType 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; |
| |
| InterfaceType Class_T_S = env["Class"]; |
| Expect.isNotNull(Class_T_S); |
| Expect.identical(Class_T_S.kind, TypeKind.INTERFACE); |
| Expect.equals(2, length(Class_T_S.typeArguments)); |
| |
| DartType T = Class_T_S.typeArguments.head; |
| Expect.isNotNull(T); |
| Expect.identical(T.kind, TypeKind.TYPE_VARIABLE); |
| |
| DartType S = Class_T_S.typeArguments.tail.head; |
| Expect.isNotNull(S); |
| Expect.identical(S.kind, TypeKind.TYPE_VARIABLE); |
| |
| DartType intType = env['int'];//getType(compiler, "int1"); |
| Expect.isNotNull(intType); |
| Expect.identical(intType.kind, TypeKind.INTERFACE); |
| |
| DartType StringType = env['String'];//getType(compiler, "String1"); |
| Expect.isNotNull(StringType); |
| Expect.identical(StringType.kind, TypeKind.INTERFACE); |
| |
| var parameters = new Link<DartType>.fromList(<DartType>[T, S]); |
| var arguments = new Link<DartType>.fromList(<DartType>[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. |
| DartType Typedef2_int_String = getType(compiler, "Typedef2a"); |
| Expect.isNotNull(Typedef2_int_String); |
| DartType Function_int_String = getType(compiler, "Function2b"); |
| Expect.isNotNull(Function_int_String); |
| DartType unalias1 = Typedef2_int_String.unalias(compiler); |
| Expect.equals(Function_int_String, unalias1, |
| '$Typedef2_int_String.unalias=$unalias1 != $Function_int_String'); |
| |
| DartType Typedef1 = getType(compiler, "Typedef1c"); |
| Expect.isNotNull(Typedef1); |
| DartType Function_dynamic_dynamic = getType(compiler, "Function1c"); |
| Expect.isNotNull(Function_dynamic_dynamic); |
| DartType unalias2 = Typedef1.unalias(compiler); |
| Expect.equals(Function_dynamic_dynamic, unalias2, |
| '$Typedef1.unalias=$unalias2 != $Function_dynamic_dynamic'); |
| })); |
| } |