| // Copyright (c) 2013, 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 subtype_test; |
| |
| import 'type_test_helper.dart'; |
| import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart'; |
| import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart" |
| show Element, ClassElement; |
| |
| void main() { |
| testInterfaceSubtype(); |
| testCallableSubtype(); |
| testFunctionSubtyping(); |
| testTypedefSubtyping(); |
| testFunctionSubtypingOptional(); |
| testTypedefSubtypingOptional(); |
| testFunctionSubtypingNamed(); |
| testTypedefSubtypingNamed(); |
| } |
| |
| void testInterfaceSubtype() { |
| var env = new TypeEnvironment(r""" |
| class A<T> {} |
| class B<T1, T2> extends A<T1> {} |
| // TODO(johnniwinther): Inheritance with different type arguments is |
| // currently not supported by the implementation. |
| class C<T1, T2> extends B<T2, T1> /*implements A<A<T1>>*/ {} |
| """); |
| |
| void expect(bool value, DartType T, DartType S) { |
| Expect.equals(value, env.isSubtype(T, S), '$T <: $S'); |
| } |
| |
| ClassElement A = env.getElement('A'); |
| ClassElement B = env.getElement('B'); |
| ClassElement C = env.getElement('C'); |
| DartType Object_ = env['Object']; |
| DartType num_ = env['num']; |
| DartType int_ = env['int']; |
| DartType String_ = env['String']; |
| DartType dynamic_ = env['dynamic']; |
| |
| expect(true, Object_, Object_); |
| expect(true, num_, Object_); |
| expect(true, int_, Object_); |
| expect(true, String_, Object_); |
| expect(true, dynamic_, Object_); |
| |
| expect(false, Object_, num_); |
| expect(true, num_, num_); |
| expect(true, int_, num_); |
| expect(false, String_, num_); |
| expect(true, dynamic_, num_); |
| |
| expect(false, Object_, int_); |
| expect(false, num_, int_); |
| expect(true, int_, int_); |
| expect(false, String_, int_); |
| expect(true, dynamic_, int_); |
| |
| expect(false, Object_, String_); |
| expect(false, num_, String_); |
| expect(false, int_, String_); |
| expect(true, String_, String_); |
| expect(true, dynamic_, String_); |
| |
| expect(true, Object_, dynamic_); |
| expect(true, num_, dynamic_); |
| expect(true, int_, dynamic_); |
| expect(true, String_, dynamic_); |
| expect(true, dynamic_, dynamic_); |
| |
| DartType A_Object = instantiate(A, [Object_]); |
| DartType A_num = instantiate(A, [num_]); |
| DartType A_int = instantiate(A, [int_]); |
| DartType A_String = instantiate(A, [String_]); |
| DartType A_dynamic = instantiate(A, [dynamic_]); |
| |
| expect(true, A_Object, Object_); |
| expect(false, A_Object, num_); |
| expect(false, A_Object, int_); |
| expect(false, A_Object, String_); |
| expect(true, A_Object, dynamic_); |
| |
| expect(true, A_Object, A_Object); |
| expect(true, A_num, A_Object); |
| expect(true, A_int, A_Object); |
| expect(true, A_String, A_Object); |
| expect(true, A_dynamic, A_Object); |
| |
| expect(false, A_Object, A_num); |
| expect(true, A_num, A_num); |
| expect(true, A_int, A_num); |
| expect(false, A_String, A_num); |
| expect(true, A_dynamic, A_num); |
| |
| expect(false, A_Object, A_int); |
| expect(false, A_num, A_int); |
| expect(true, A_int, A_int); |
| expect(false, A_String, A_int); |
| expect(true, A_dynamic, A_int); |
| |
| expect(false, A_Object, A_String); |
| expect(false, A_num, A_String); |
| expect(false, A_int, A_String); |
| expect(true, A_String, A_String); |
| expect(true, A_dynamic, A_String); |
| |
| expect(true, A_Object, A_dynamic); |
| expect(true, A_num, A_dynamic); |
| expect(true, A_int, A_dynamic); |
| expect(true, A_String, A_dynamic); |
| expect(true, A_dynamic, A_dynamic); |
| |
| DartType B_Object_Object = instantiate(B, [Object_, Object_]); |
| DartType B_num_num = instantiate(B, [num_, num_]); |
| DartType B_int_num = instantiate(B, [int_, num_]); |
| DartType B_dynamic_dynamic = instantiate(B, [dynamic_, dynamic_]); |
| DartType B_String_dynamic = instantiate(B, [String_, dynamic_]); |
| |
| expect(true, B_Object_Object, Object_); |
| expect(true, B_Object_Object, A_Object); |
| expect(false, B_Object_Object, A_num); |
| expect(false, B_Object_Object, A_int); |
| expect(false, B_Object_Object, A_String); |
| expect(true, B_Object_Object, A_dynamic); |
| |
| expect(true, B_num_num, Object_); |
| expect(true, B_num_num, A_Object); |
| expect(true, B_num_num, A_num); |
| expect(false, B_num_num, A_int); |
| expect(false, B_num_num, A_String); |
| expect(true, B_num_num, A_dynamic); |
| |
| expect(true, B_int_num, Object_); |
| expect(true, B_int_num, A_Object); |
| expect(true, B_int_num, A_num); |
| expect(true, B_int_num, A_int); |
| expect(false, B_int_num, A_String); |
| expect(true, B_int_num, A_dynamic); |
| |
| expect(true, B_dynamic_dynamic, Object_); |
| expect(true, B_dynamic_dynamic, A_Object); |
| expect(true, B_dynamic_dynamic, A_num); |
| expect(true, B_dynamic_dynamic, A_int); |
| expect(true, B_dynamic_dynamic, A_String); |
| expect(true, B_dynamic_dynamic, A_dynamic); |
| |
| expect(true, B_String_dynamic, Object_); |
| expect(true, B_String_dynamic, A_Object); |
| expect(false, B_String_dynamic, A_num); |
| expect(false, B_String_dynamic, A_int); |
| expect(true, B_String_dynamic, A_String); |
| expect(true, B_String_dynamic, A_dynamic); |
| |
| expect(true, B_Object_Object, B_Object_Object); |
| expect(true, B_num_num, B_Object_Object); |
| expect(true, B_int_num, B_Object_Object); |
| expect(true, B_dynamic_dynamic, B_Object_Object); |
| expect(true, B_String_dynamic, B_Object_Object); |
| |
| expect(false, B_Object_Object, B_num_num); |
| expect(true, B_num_num, B_num_num); |
| expect(true, B_int_num, B_num_num); |
| expect(true, B_dynamic_dynamic, B_num_num); |
| expect(false, B_String_dynamic, B_num_num); |
| |
| expect(false, B_Object_Object, B_int_num); |
| expect(false, B_num_num, B_int_num); |
| expect(true, B_int_num, B_int_num); |
| expect(true, B_dynamic_dynamic, B_int_num); |
| expect(false, B_String_dynamic, B_int_num); |
| |
| expect(true, B_Object_Object, B_dynamic_dynamic); |
| expect(true, B_num_num, B_dynamic_dynamic); |
| expect(true, B_int_num, B_dynamic_dynamic); |
| expect(true, B_dynamic_dynamic, B_dynamic_dynamic); |
| expect(true, B_String_dynamic, B_dynamic_dynamic); |
| |
| expect(false, B_Object_Object, B_String_dynamic); |
| expect(false, B_num_num, B_String_dynamic); |
| expect(false, B_int_num, B_String_dynamic); |
| expect(true, B_dynamic_dynamic, B_String_dynamic); |
| expect(true, B_String_dynamic, B_String_dynamic); |
| |
| DartType C_Object_Object = instantiate(C, [Object_, Object_]); |
| DartType C_num_num = instantiate(C, [num_, num_]); |
| DartType C_int_String = instantiate(C, [int_, String_]); |
| DartType C_dynamic_dynamic = instantiate(C, [dynamic_, dynamic_]); |
| |
| expect(true, C_Object_Object, B_Object_Object); |
| expect(false, C_Object_Object, B_num_num); |
| expect(false, C_Object_Object, B_int_num); |
| expect(true, C_Object_Object, B_dynamic_dynamic); |
| expect(false, C_Object_Object, B_String_dynamic); |
| |
| expect(true, C_num_num, B_Object_Object); |
| expect(true, C_num_num, B_num_num); |
| expect(false, C_num_num, B_int_num); |
| expect(true, C_num_num, B_dynamic_dynamic); |
| expect(false, C_num_num, B_String_dynamic); |
| |
| expect(true, C_int_String, B_Object_Object); |
| expect(false, C_int_String, B_num_num); |
| expect(false, C_int_String, B_int_num); |
| expect(true, C_int_String, B_dynamic_dynamic); |
| expect(true, C_int_String, B_String_dynamic); |
| |
| expect(true, C_dynamic_dynamic, B_Object_Object); |
| expect(true, C_dynamic_dynamic, B_num_num); |
| expect(true, C_dynamic_dynamic, B_int_num); |
| expect(true, C_dynamic_dynamic, B_dynamic_dynamic); |
| expect(true, C_dynamic_dynamic, B_String_dynamic); |
| |
| expect(false, C_int_String, A_int); |
| expect(true, C_int_String, A_String); |
| // TODO(johnniwinther): Inheritance with different type arguments is |
| // currently not supported by the implementation. |
| //expect(true, C_int_String, instantiate(A, [A_int])); |
| expect(false, C_int_String, instantiate(A, [A_String])); |
| } |
| |
| void testCallableSubtype() { |
| |
| var env = new TypeEnvironment(r""" |
| class U {} |
| class V extends U {} |
| class W extends V {} |
| class A { |
| int call(V v, int i); |
| |
| int m1(U u, int i); |
| int m2(W w, num n); |
| U m3(V v, int i); |
| int m4(V v, U u); |
| void m5(V v, int i); |
| } |
| """); |
| |
| void expect(bool value, DartType T, DartType S) { |
| Expect.equals(value, env.isSubtype(T, S), '$T <: $S'); |
| } |
| |
| ClassElement classA = env.getElement('A'); |
| DartType A = classA.rawType; |
| DartType function = env['Function']; |
| DartType m1 = env.getMemberType(classA, 'm1'); |
| DartType m2 = env.getMemberType(classA, 'm2'); |
| DartType m3 = env.getMemberType(classA, 'm3'); |
| DartType m4 = env.getMemberType(classA, 'm4'); |
| DartType m5 = env.getMemberType(classA, 'm5'); |
| |
| expect(true, A, function); |
| expect(true, A, m1); |
| expect(true, A, m2); |
| expect(false, A, m3); |
| expect(false, A, m4); |
| expect(true, A, m5); |
| } |
| |
| testFunctionSubtyping() { |
| var env = new TypeEnvironment(r""" |
| void void_() {} |
| void void_2() {} |
| int int_() => 0; |
| int int_2() => 0; |
| Object Object_() => null; |
| double double_() => 0.0; |
| void void__int(int i) {} |
| int int__int(int i) => 0; |
| int int__int2(int i) => 0; |
| int int__Object(Object o) => 0; |
| Object Object__int(int i) => null; |
| int int__double(double d) => 0; |
| int int__int_int(int i1, int i2) => 0; |
| void inline_void_(void f()) {} |
| void inline_void__int(void f(int i)) {} |
| """); |
| functionSubtypingHelper(env); |
| } |
| |
| testTypedefSubtyping() { |
| var env = new TypeEnvironment(r""" |
| typedef void void_(); |
| typedef void void_2(); |
| typedef int int_(); |
| typedef int int_2(); |
| typedef Object Object_(); |
| typedef double double_(); |
| typedef void void__int(int i); |
| typedef int int__int(int i); |
| typedef int int__int2(int i); |
| typedef int int__Object(Object o); |
| typedef Object Object__int(int i); |
| typedef int int__double(double d); |
| typedef int int__int_int(int i1, int i2); |
| typedef void inline_void_(void f()); |
| typedef void inline_void__int(void f(int i)); |
| """); |
| functionSubtypingHelper(env); |
| } |
| |
| functionSubtypingHelper(TypeEnvironment env) { |
| void expect(bool expectedResult, String sub, String sup) { |
| DartType subtype = env.getElementType(sub); |
| DartType supertype = env.getElementType(sup); |
| Expect.equals(expectedResult, env.isSubtype(subtype, supertype), |
| '$subtype <: $supertype'); |
| } |
| |
| // () -> int <: Function |
| expect(true, 'int_', 'Function'); |
| // Function <: () -> int |
| expect(false, 'Function', 'int_'); |
| |
| // () -> int <: () -> void |
| expect(true, 'int_', 'void_'); |
| // () -> void <: () -> int |
| expect(false, 'void_', 'int_'); |
| // () -> void <: () -> void |
| expect(true, 'void_', 'void_2'); |
| // () -> int <: () -> int |
| expect(true, 'int_', 'int_2'); |
| // () -> int <: () -> Object |
| expect(true, 'int_', 'Object_'); |
| // () -> int <: () -> double |
| expect(false, 'int_', 'double_'); |
| // () -> int <: (int) -> void |
| expect(false, 'int_', 'void__int'); |
| // () -> void <: (int) -> int |
| expect(false, 'void_', 'int__int'); |
| // () -> void <: (int) -> void |
| expect(false, 'void_', 'void__int'); |
| // (int) -> int <: (int) -> int |
| expect(true, 'int__int', 'int__int2'); |
| // (Object) -> int <: (int) -> Object |
| expect(true, 'int__Object', 'Object__int'); |
| // (int) -> int <: (double) -> int |
| expect(false, 'int__int', 'int__double'); |
| // () -> int <: (int) -> int |
| expect(false, 'int_', 'int__int'); |
| // (int) -> int <: (int,int) -> int |
| expect(false, 'int__int', 'int__int_int'); |
| // (int,int) -> int <: (int) -> int |
| expect(false, 'int__int_int', 'int__int'); |
| // (()->void) -> void <: ((int)->void) -> void |
| expect(false, 'inline_void_', 'inline_void__int'); |
| // ((int)->void) -> void <: (()->void) -> void |
| expect(false, 'inline_void__int', 'inline_void_'); |
| } |
| |
| testFunctionSubtypingOptional() { |
| var env = new TypeEnvironment(r""" |
| void void_() {} |
| void void__int(int i) {} |
| void void___int([int i]) {} |
| void void___int2([int i]) {} |
| void void___Object([Object o]) {} |
| void void__int__int(int i1, [int i2]) {} |
| void void__int__int2(int i1, [int i2]) {} |
| void void___double(double d) {} |
| void void___int_int([int i1, int i2]) {} |
| void void___Object_int([Object o, int i]) {} |
| """); |
| functionSubtypingOptionalHelper(env); |
| } |
| |
| testTypedefSubtypingOptional() { |
| var env = new TypeEnvironment(r""" |
| typedef void void_(); |
| typedef void void__int(int i); |
| typedef void void___int([int i]); |
| typedef void void___int2([int i]); |
| typedef void void___Object([Object o]); |
| typedef void void__int__int(int i1, [int i2]); |
| typedef void void__int__int2(int i1, [int i2]); |
| typedef void void___double(double d); |
| typedef void void___int_int([int i1, int i2]); |
| typedef void void___Object_int([Object o, int i]); |
| """); |
| functionSubtypingOptionalHelper(env); |
| } |
| |
| functionSubtypingOptionalHelper(TypeEnvironment env) { |
| expect(bool expectedResult, String sub, String sup) { |
| DartType subtype = env.getElementType(sub); |
| DartType supertype = env.getElementType(sup); |
| Expect.equals(expectedResult, env.isSubtype(subtype, supertype), |
| '$subtype <: $supertype'); |
| } |
| |
| // Test ([int])->void <: ()->void. |
| expect(true, 'void___int', 'void_'); |
| // Test ([int])->void <: (int)->void. |
| expect(false, 'void___int', 'void__int'); |
| // Test (int)->void <: ([int])->void. |
| expect(false, 'void__int', 'void___int'); |
| // Test ([int])->void <: ([int])->void. |
| expect(true, 'void___int', 'void___int2'); |
| // Test ([Object])->void <: ([int])->void. |
| expect(true, 'void___Object', 'void___int'); |
| // Test ([int])->void <: ([Object])->void. |
| expect(true, 'void___int', 'void___Object'); |
| // Test (int,[int])->void <: (int,[int])->void. |
| expect(true, 'void__int__int', 'void__int__int2'); |
| // Test ([int])->void <: ([double])->void. |
| expect(false, 'void___int', 'void___double'); |
| // Test ([int])->void <: ([int,int])->void. |
| expect(false, 'void___int', 'void___int_int'); |
| // Test ([int,int])->void <: ([int])->void. |
| expect(true, 'void___int_int', 'void___int'); |
| // Test ([Object,int])->void <: ([int])->void. |
| expect(true, 'void___Object_int', 'void___int'); |
| } |
| |
| testFunctionSubtypingNamed() { |
| var env = new TypeEnvironment(r""" |
| void void_() {} |
| void void__int(int i) {} |
| void void___a_int({int a}) {} |
| void void___a_int2({int a}) {} |
| void void___b_int({int b}) {} |
| void void___a_Object({Object a}) {} |
| void void__int__a_int(int i1, {int a}) {} |
| void void__int__a_int2(int i1, {int a}) {} |
| void void___a_double({double a}) {} |
| void void___a_int_b_int({int a, int b}) {} |
| void void___a_int_b_int_c_int({int a, int b, int c}) {} |
| void void___a_int_c_int({int a, int c}) {} |
| void void___b_int_c_int({int b, int c}) {} |
| void void___c_int({int c}) {} |
| """); |
| functionSubtypingNamedHelper(env); |
| } |
| |
| testTypedefSubtypingNamed() { |
| var env = new TypeEnvironment(r""" |
| typedef void void_(); |
| typedef void void__int(int i); |
| typedef void void___a_int({int a}); |
| typedef void void___a_int2({int a}); |
| typedef void void___b_int({int b}); |
| typedef void void___a_Object({Object a}); |
| typedef void void__int__a_int(int i1, {int a}); |
| typedef void void__int__a_int2(int i1, {int a}); |
| typedef void void___a_double({double a}); |
| typedef void void___a_int_b_int({int a, int b}); |
| typedef void void___a_int_b_int_c_int({int a, int b, int c}); |
| typedef void void___a_int_c_int({int a, int c}); |
| typedef void void___b_int_c_int({int b, int c}); |
| typedef void void___c_int({int c}); |
| """); |
| functionSubtypingNamedHelper(env); |
| } |
| |
| functionSubtypingNamedHelper(TypeEnvironment env) { |
| expect(bool expectedResult, String sub, String sup) { |
| DartType subtype = env.getElementType(sub); |
| DartType supertype = env.getElementType(sup); |
| Expect.equals(expectedResult, env.isSubtype(subtype, supertype), |
| '$subtype <: $supertype'); |
| } |
| |
| // Test ({int a})->void <: ()->void. |
| expect(true, 'void___a_int', 'void_'); |
| // Test ({int a})->void <: (int)->void. |
| expect(false, 'void___a_int', 'void__int'); |
| // Test (int)->void <: ({int a})->void. |
| expect(false, 'void__int', 'void___a_int'); |
| // Test ({int a})->void <: ({int a})->void. |
| expect(true, 'void___a_int', 'void___a_int2'); |
| // Test ({int a})->void <: ({int b})->void. |
| expect(false, 'void___a_int', 'void___b_int'); |
| // Test ({Object a})->void <: ({int a})->void. |
| expect(true, 'void___a_Object', 'void___a_int'); |
| // Test ({int a})->void <: ({Object a})->void. |
| expect(true, 'void___a_int', 'void___a_Object'); |
| // Test (int,{int a})->void <: (int,{int a})->void. |
| expect(true, 'void__int__a_int', 'void__int__a_int2'); |
| // Test ({int a})->void <: ({double a})->void. |
| expect(false, 'void___a_int', 'void___a_double'); |
| // Test ({int a})->void <: ({int a,int b})->void. |
| expect(false, 'void___a_int', 'void___a_int_b_int'); |
| // Test ({int a,int b})->void <: ({int a})->void. |
| expect(true, 'void___a_int_b_int', 'void___a_int'); |
| // Test ({int a,int b,int c})->void <: ({int a,int c})->void. |
| expect(true, 'void___a_int_b_int_c_int', 'void___a_int_c_int'); |
| // Test ({int a,int b,int c})->void <: ({int b,int c})->void. |
| expect(true, 'void___a_int_b_int_c_int', 'void___b_int_c_int'); |
| // Test ({int a,int b,int c})->void <: ({int c})->void. |
| expect(true, 'void___a_int_b_int_c_int', 'void___c_int'); |
| } |