| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'package:test/test.dart'; | |
| 6 import 'package:kernel/ast.dart'; | |
| 7 import 'package:kernel/class_hierarchy.dart'; | |
| 8 import 'package:kernel/type_environment.dart'; | |
| 9 import 'type_parser.dart'; | |
| 10 | |
| 11 /// Description of a small class hierarchy for use in subtype tests. | |
| 12 var classEnvironment = <String, List<String>>{ | |
| 13 'Comparable<T>': ['Object'], | |
| 14 'num': ['Object', 'Comparable<num>'], | |
| 15 'int': ['num'], | |
| 16 'double': ['num'], | |
| 17 'Iterable<T>': ['Object'], | |
| 18 'List<T>': ['Iterable<T>'], | |
| 19 }; | |
| 20 | |
| 21 List<TestCase> testCases = <TestCase>[ | |
| 22 subtype('int', 'num'), | |
| 23 subtype('int', 'Comparable<num>'), | |
| 24 subtype('int', 'Comparable<Object>'), | |
| 25 subtype('int', 'Object'), | |
| 26 subtype('double', 'num'), | |
| 27 | |
| 28 notSubtype('int', 'double'), | |
| 29 notSubtype('int', 'Comparable<int>'), | |
| 30 notSubtype('int', 'Iterable<int>'), | |
| 31 notSubtype('Comparable<int>', 'Iterable<int>'), | |
| 32 | |
| 33 subtype('List<int>', 'List<int>'), | |
| 34 subtype('List<int>', 'Iterable<int>'), | |
| 35 subtype('List<int>', 'List<num>'), | |
| 36 subtype('List<int>', 'Iterable<num>'), | |
| 37 subtype('List<int>', 'List<Object>'), | |
| 38 subtype('List<int>', 'Iterable<Object>'), | |
| 39 subtype('List<int>', 'Object'), | |
| 40 subtype('List<int>', 'List<Comparable<Object>>'), | |
| 41 subtype('List<int>', 'List<Comparable<num>>'), | |
| 42 subtype('List<int>', 'List<Comparable<Comparable<num>>>'), | |
| 43 | |
| 44 notSubtype('List<int>', 'List<double>'), | |
| 45 notSubtype('List<int>', 'Iterable<double>'), | |
| 46 notSubtype('List<int>', 'Comparable<int>'), | |
| 47 notSubtype('List<int>', 'List<Comparable<int>>'), | |
| 48 notSubtype('List<int>', 'List<Comparable<Comparable<int>>>'), | |
| 49 | |
| 50 subtype('(num) => num', '(int) => num'), | |
| 51 subtype('(num) => int', '(num) => num'), | |
| 52 subtype('(num) => int', '(int) => num'), | |
| 53 notSubtype('(int) => int', '(num) => num'), | |
| 54 | |
| 55 subtype('(num) => (num) => num', '(num) => (int) => num'), | |
| 56 notSubtype('(num) => (int) => int', '(num) => (num) => num'), | |
| 57 | |
| 58 subtype('(x:num) => num', '(x:int) => num'), // named parameters | |
| 59 subtype('(num,x:num) => num', '(int,x:int) => num'), | |
| 60 subtype('(x:num) => int', '(x:num) => num'), | |
| 61 notSubtype('(x:int) => int', '(x:num) => num'), | |
| 62 | |
| 63 subtype('<E>(E) => int', '<E>(E) => num'), // type parameters | |
| 64 subtype('<E>(num) => E', '<E>(int) => E'), | |
| 65 subtype('<E>(E,num) => E', '<E>(E,int) => E'), | |
| 66 notSubtype('<E>(E,num) => E', '<E>(E,E) => E'), | |
| 67 | |
| 68 subtype('<E>(E) => (E) => E', '<F>(F) => (F) => F'), | |
| 69 subtype('<E>(E, (int,E) => E) => E', '<E>(E, (int,E) => E) => E'), | |
| 70 subtype('<E>(E, (int,E) => E) => E', '<E>(E, (num,E) => E) => E'), | |
| 71 notSubtype('<E,F>(E) => (F) => E', '<E>(E) => <F>(F) => E'), | |
| 72 notSubtype('<E,F>(E) => (F) => E', '<F,E>(E) => (F) => E'), | |
| 73 | |
| 74 subtype('<E>(E,num) => E', '<E:num>(E,E) => E'), | |
| 75 subtype('<E:num>(E) => int', '<E:int>(E) => int'), | |
| 76 subtype('<E:num>(E) => E', '<E:int>(E) => E'), | |
| 77 subtype('<E:num>(int) => E', '<E:int>(int) => E'), | |
| 78 notSubtype('<E>(int) => int', '(int) => int'), | |
| 79 notSubtype('<E,F>(int) => int', '<E>(int) => int'), | |
| 80 | |
| 81 subtype('<E:List<E>>(E) => E', '<F:List<F>>(F) => F'), | |
| 82 subtype('<E:Iterable<E>>(E) => E', '<F:List<F>>(F) => F'), | |
| 83 subtype('<E>(E,List<Object>) => E', '<F:List<F>>(F,F) => F'), | |
| 84 notSubtype('<E>(E,List<Object>) => List<E>', '<F:List<F>>(F,F) => F'), | |
| 85 notSubtype('<E>(E,List<Object>) => int', '<F:List<F>>(F,F) => F'), | |
| 86 subtype('<E>(E,List<Object>) => E', '<F:List<F>>(F,F) => void'), | |
| 87 ]; | |
| 88 | |
| 89 /// Assert that [subtype] is a subtype of [supertype], and that [supertype] | |
| 90 /// is not a subtype of [subtype] (unless the two strings are equal). | |
| 91 TestCase subtype(String subtype_, String supertype) { | |
| 92 return new TestCase(subtype_, supertype, isSubtype: true); | |
| 93 } | |
| 94 | |
| 95 /// Assert that neither type is a subtype of the other. | |
| 96 TestCase notSubtype(String subtype_, String supertype) { | |
| 97 return new TestCase(subtype_, supertype, isSubtype: false); | |
| 98 } | |
| 99 | |
| 100 class TestCase { | |
| 101 String subtype; | |
| 102 String supertype; | |
| 103 bool isSubtype; | |
| 104 TestCase(this.subtype, this.supertype, {this.isSubtype}); | |
| 105 | |
| 106 String toString() => | |
| 107 isSubtype ? '$subtype <: $supertype' : '$subtype </: $supertype'; | |
| 108 } | |
| 109 | |
| 110 class MockSubtypeTester extends SubtypeTester { | |
| 111 ClassHierarchy hierarchy; | |
| 112 InterfaceType objectType; | |
| 113 InterfaceType rawFunctionType; | |
| 114 LazyTypeEnvironment environment; | |
| 115 | |
| 116 MockSubtypeTester( | |
| 117 this.hierarchy, this.objectType, this.rawFunctionType, this.environment); | |
| 118 } | |
| 119 | |
| 120 MockSubtypeTester makeSubtypeTester(Map<String, List<String>> testcase) { | |
| 121 LazyTypeEnvironment environment = new LazyTypeEnvironment(); | |
| 122 Class objectClass = environment.lookup('Object'); | |
| 123 Class functionClass = environment.lookup('Function'); | |
| 124 functionClass.supertype = objectClass.asRawSupertype; | |
| 125 for (var typeString in testcase.keys) { | |
| 126 InterfaceType type = environment.parseFresh(typeString); | |
| 127 Class class_ = type.classNode; | |
| 128 for (TypeParameterType typeArg in type.typeArguments) { | |
| 129 class_.typeParameters.add(typeArg.parameter); | |
| 130 } | |
| 131 for (var supertypeString in testcase[typeString]) { | |
| 132 if (class_.supertype == null) { | |
| 133 class_.supertype = environment.parseSuper(supertypeString); | |
| 134 } else { | |
| 135 class_.implementedTypes.add(environment.parseSuper(supertypeString)); | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 var program = new Program([environment.dummyLibrary]); | |
| 140 var hierarchy = new ClassHierarchy(program); | |
| 141 return new MockSubtypeTester( | |
| 142 hierarchy, objectClass.rawType, functionClass.rawType, environment); | |
| 143 } | |
| 144 | |
| 145 main() { | |
| 146 var tester = makeSubtypeTester(classEnvironment); | |
| 147 var environment = tester.environment; | |
| 148 for (var testCase in testCases) { | |
| 149 test('$testCase', () { | |
| 150 var subtype = environment.parseFresh(testCase.subtype); | |
| 151 var supertype = environment.parseFresh(testCase.supertype); | |
| 152 if (tester.isSubtypeOf(subtype, supertype) != testCase.isSubtype) { | |
| 153 fail('isSubtypeOf(${testCase.subtype}, ${testCase.supertype}) returned ' | |
| 154 '${!testCase.isSubtype} but should return ${testCase.isSubtype}'); | |
| 155 } | |
| 156 if (subtype != supertype && tester.isSubtypeOf(supertype, subtype)) { | |
| 157 fail('isSubtypeOf(${testCase.supertype}, ${testCase.subtype}) returned ' | |
| 158 'true but should return false'); | |
| 159 } | |
| 160 }); | |
| 161 } | |
| 162 } | |
| OLD | NEW |