| // 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. |
| |
| // TODO(johnniwinther): Port this test to be frontend agnostic. |
| |
| library type_substitution_test; |
| |
| import 'package:expect/expect.dart'; |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/common_elements.dart'; |
| import 'package:compiler/src/elements/entities.dart'; |
| import 'package:compiler/src/elements/types.dart'; |
| import '../type_test_helper.dart'; |
| |
| DartType getType(ElementEnvironment elementEnvironment, String name) { |
| ClassEntity cls = |
| elementEnvironment.lookupClass(elementEnvironment.mainLibrary, 'Class'); |
| FunctionEntity element = elementEnvironment.lookupClassMember(cls, name); |
| Expect.isNotNull(element); |
| FunctionType type = elementEnvironment.getFunctionType(element); |
| |
| // 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 (type.parameterTypes.isEmpty) { |
| // If parameters is empty, use return type. |
| return type.returnType; |
| } else { |
| // Otherwise use the first argument type. |
| return type.parameterTypes.first; |
| } |
| } |
| |
| void main() { |
| asyncTest(() async { |
| await testAsInstanceOf(); |
| await testTypeSubstitution(); |
| }); |
| } |
| |
| testAsInstanceOf() async { |
| var env = await 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>> {} |
| ''', mainSource: ''' |
| main() { |
| new A(); |
| new B(); |
| new C(); |
| new D(); |
| new E(); |
| new F(); |
| } |
| '''); |
| ClassEntity A = env.getElement("A"); |
| ClassEntity B = env.getElement("B"); |
| ClassEntity C = env.getElement("C"); |
| ClassEntity D = env.getElement("D"); |
| ClassEntity E = env.getElement("E"); |
| ClassEntity F = env.getElement("F"); |
| |
| 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]), env.types.asInstanceOf(C_int, A)); |
| |
| InterfaceType D_int = instantiate(D, [stringType]); |
| Expect.equals(instantiate(A, [intType]), env.types.asInstanceOf(D_int, A)); |
| |
| InterfaceType E_int = instantiate(E, [intType]); |
| Expect.equals( |
| instantiate(A, [ |
| instantiate(A, [intType]) |
| ]), |
| env.types.asInstanceOf(E_int, A)); |
| |
| InterfaceType F_int_string = instantiate(F, [intType, stringType]); |
| Expect.equals( |
| instantiate(B, [ |
| instantiate(F, [intType, stringType]) |
| ]), |
| env.types.asInstanceOf(F_int_string, B)); |
| Expect.equals( |
| instantiate(A, [ |
| instantiate(F, [ |
| instantiate(B, [stringType]), |
| intType |
| ]) |
| ]), |
| env.types.asInstanceOf(F_int_string, 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( |
| ElementEnvironment elementEnvironment, |
| List<DartType> arguments, |
| List<DartType> parameters, |
| String name1, |
| String name2) { |
| DartType type1 = getType(elementEnvironment, name1); |
| DartType type2 = getType(elementEnvironment, name2); |
| DartType subst = type1.subst(arguments, parameters); |
| Expect.equals( |
| type2, subst, "$type1.subst($arguments,$parameters)=$subst != $type2"); |
| } |
| |
| testTypeSubstitution() async { |
| var env = await 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) {} |
| } |
| """); |
| InterfaceType Class_T_S = env["Class"]; |
| Expect.isNotNull(Class_T_S); |
| Expect.isTrue(Class_T_S.isInterfaceType); |
| Expect.equals(2, Class_T_S.typeArguments.length); |
| |
| DartType T = Class_T_S.typeArguments[0]; |
| Expect.isNotNull(T); |
| Expect.isTrue(T.isTypeVariable); |
| |
| DartType S = Class_T_S.typeArguments[1]; |
| Expect.isNotNull(S); |
| Expect.isTrue(S.isTypeVariable); |
| |
| DartType intType = env['int']; //getType(compiler, "int1"); |
| Expect.isNotNull(intType); |
| Expect.isTrue(intType.isInterfaceType); |
| |
| DartType StringType = env['String']; //getType(compiler, "String1"); |
| Expect.isNotNull(StringType); |
| Expect.isTrue(StringType.isInterfaceType); |
| |
| List<DartType> parameters = <DartType>[T, S]; |
| List<DartType> arguments = <DartType>[intType, StringType]; |
| |
| // TODO(johnniwinther): Create types directly from strings to improve |
| // test readability. |
| |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "void1", "void2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "dynamic1", "dynamic2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "int1", "int2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "String1", "String2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "ListInt1", "ListInt2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "ListT1", "ListT2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "ListS1", "ListS2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, "ListListT1", |
| "ListListT2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "ListRaw1", "ListRaw2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, |
| "ListDynamic1", "ListDynamic2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, |
| "MapIntString1", "MapIntString2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, "MapTString1", |
| "MapTString2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, |
| "MapDynamicString1", "MapDynamicString2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "TypeVarT1", "TypeVarT2"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "TypeVarS1", "TypeVarS2"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, "Function1a", |
| "Function2a"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, "Function1b", |
| "Function2b"); |
| testSubstitution(env.elementEnvironment, arguments, parameters, "Function1c", |
| "Function2c"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "Typedef1a", "Typedef2a"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "Typedef1b", "Typedef2b"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "Typedef1c", "Typedef2c"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "Typedef1d", "Typedef2d"); |
| testSubstitution( |
| env.elementEnvironment, arguments, parameters, "Typedef1e", "Typedef2e"); |
| |
| // Substitution in unalias. |
| DartType Typedef2_int_String = getType(env.elementEnvironment, "Typedef2a"); |
| Expect.isNotNull(Typedef2_int_String); |
| DartType Function_int_String = getType(env.elementEnvironment, "Function2b"); |
| Expect.isNotNull(Function_int_String); |
| DartType unalias1 = Typedef2_int_String.unaliased; |
| Expect.equals(Function_int_String, unalias1, |
| '$Typedef2_int_String.unalias=$unalias1 != $Function_int_String'); |
| |
| DartType Typedef1 = getType(env.elementEnvironment, "Typedef1c"); |
| Expect.isNotNull(Typedef1); |
| DartType Function_dynamic_dynamic = |
| getType(env.elementEnvironment, "Function1c"); |
| Expect.isNotNull(Function_dynamic_dynamic); |
| DartType unalias2 = Typedef1.unaliased; |
| Expect.equals(Function_dynamic_dynamic, unalias2, |
| '$Typedef1.unalias=$unalias2 != $Function_dynamic_dynamic'); |
| } |