| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'package:async_helper/async_helper.dart'; | 5 import 'package:async_helper/async_helper.dart'; |
| 6 import 'package:expect/expect.dart'; | 6 import 'package:expect/expect.dart'; |
| 7 import 'package:compiler/src/types/types.dart'; | 7 import 'package:compiler/src/types/types.dart'; |
| 8 | 8 |
| 9 import 'compiler_helper.dart'; | 9 import 'compiler_helper.dart'; |
| 10 | 10 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 new H(), new I(), new J(), new K(), new M(), new N()]); | 33 new H(), new I(), new J(), new K(), new M(), new N()]); |
| 34 } | 34 } |
| 35 """; | 35 """; |
| 36 | 36 |
| 37 Uri uri = new Uri(scheme: 'source'); | 37 Uri uri = new Uri(scheme: 'source'); |
| 38 var compiler = compilerFor(CODE, uri); | 38 var compiler = compilerFor(CODE, uri); |
| 39 var world = compiler.world; | 39 var world = compiler.world; |
| 40 | 40 |
| 41 main() { | 41 main() { |
| 42 asyncTest(() => compiler.run(uri).then((_) { | 42 asyncTest(() => compiler.run(uri).then((_) { |
| 43 // Empty |
| 44 check(' ! ', ' ! '); // both non-null |
| 45 check(' ! ', ' '); // one non-null |
| 46 check(' ', ' ! '); // one non-null |
| 47 check(' ', ' ', areDisjoint: false); // null is common |
| 43 | 48 |
| 44 // Empty | 49 // Exact |
| 45 check(' ! ', ' ! '); // both non-null | 50 check('A!=', 'A!=', areDisjoint: false); |
| 46 check(' ! ', ' '); // one non-null | 51 check('A!=', 'B!='); |
| 47 check(' ', ' ! '); // one non-null | 52 check('A!=', 'E!='); |
| 48 check(' ', ' ', areDisjoint: false); // null is common | 53 check('A =', 'E =', areDisjoint: false); // null is common |
| 54 check('M!=', 'K!='); |
| 55 check('M!=', 'A!='); |
| 49 | 56 |
| 50 // Exact | 57 // Exact with subclass |
| 51 check('A!=', 'A!=', areDisjoint: false); | 58 check('A!=', 'A!<', areDisjoint: false); |
| 52 check('A!=', 'B!='); | 59 check('B!=', 'A!<', areDisjoint: false); |
| 53 check('A!=', 'E!='); | 60 check('A!=', 'B!<'); |
| 54 check('A =', 'E =', areDisjoint: false); // null is common | 61 check('A!=', 'E!<'); |
| 55 check('M!=', 'K!='); | 62 check('A =', 'E!<'); |
| 56 check('M!=', 'A!='); | 63 check('A =', 'E <', areDisjoint: false); |
| 64 check('M!=', 'K!<', areDisjoint: false); |
| 65 check('M!=', 'A!<'); |
| 57 | 66 |
| 58 // Exact with subclass | 67 // Exact with subtype |
| 59 check('A!=', 'A!<', areDisjoint: false); | 68 check('A!=', 'A!*', areDisjoint: false); |
| 60 check('B!=', 'A!<', areDisjoint: false); | 69 check('B!=', 'A!*', areDisjoint: false); |
| 61 check('A!=', 'B!<'); | 70 check('A!=', 'B!*'); |
| 62 check('A!=', 'E!<'); | 71 check('A!=', 'E!*'); |
| 63 check('A =', 'E!<'); | 72 check('A!=', 'I!*'); |
| 64 check('A =', 'E <', areDisjoint: false); | 73 check('J!=', 'H!*', areDisjoint: false); |
| 65 check('M!=', 'K!<', areDisjoint: false); | 74 check('M!=', 'K!*', areDisjoint: false); |
| 66 check('M!=', 'A!<'); | 75 check('M!=', 'A!*', areDisjoint: false); |
| 67 | 76 |
| 68 // Exact with subtype | 77 // Subclass with subclass |
| 69 check('A!=', 'A!*', areDisjoint: false); | 78 check('A!<', 'A!<', areDisjoint: false); |
| 70 check('B!=', 'A!*', areDisjoint: false); | 79 check('A!<', 'B!<', areDisjoint: false); |
| 71 check('A!=', 'B!*'); | 80 check('A!<', 'E!<'); |
| 72 check('A!=', 'E!*'); | 81 check('A!<', 'H!<'); |
| 73 check('A!=', 'I!*'); | 82 check('D!<', 'I!<'); |
| 74 check('J!=', 'H!*', areDisjoint: false); | 83 check('H!<', 'I!*', areDisjoint: false); |
| 75 check('M!=', 'K!*', areDisjoint: false); | |
| 76 check('M!=', 'A!*', areDisjoint: false); | |
| 77 | 84 |
| 78 // Subclass with subclass | 85 // Subclass with subtype |
| 79 check('A!<', 'A!<', areDisjoint: false); | 86 check('A!<', 'A!*', areDisjoint: false); |
| 80 check('A!<', 'B!<', areDisjoint: false); | 87 check('A!<', 'B!*', areDisjoint: false); |
| 81 check('A!<', 'E!<'); | 88 check('A!<', 'E!*'); |
| 82 check('A!<', 'H!<'); | 89 check('A!<', 'H!*'); |
| 83 check('D!<', 'I!<'); | 90 check('D!<', 'I!*', areDisjoint: false); |
| 84 check('H!<', 'I!*', areDisjoint: false); | |
| 85 | 91 |
| 86 // Subclass with subtype | 92 // Subtype with subtype |
| 87 check('A!<', 'A!*', areDisjoint: false); | 93 check('A!*', 'A!*', areDisjoint: false); |
| 88 check('A!<', 'B!*', areDisjoint: false); | 94 check('A!*', 'B!*', areDisjoint: false); |
| 89 check('A!<', 'E!*'); | 95 check('A!*', 'E!*'); |
| 90 check('A!<', 'H!*'); | 96 check('A!*', 'H!*', areDisjoint: false); |
| 91 check('D!<', 'I!*', areDisjoint: false); | 97 check('D!*', 'I!*', areDisjoint: false); |
| 92 | 98 |
| 93 // Subtype with subtype | 99 // Unions! |
| 94 check('A!*', 'A!*', areDisjoint: false); | 100 checkUnions(['B!=', 'C!='], ['A!=']); |
| 95 check('A!*', 'B!*', areDisjoint: false); | 101 checkUnions(['B!=', 'C!='], ['A =']); |
| 96 check('A!*', 'E!*'); | 102 checkUnions(['B!=', 'C ='], ['A ='], areDisjoint: false); |
| 97 check('A!*', 'H!*', areDisjoint: false); | |
| 98 check('D!*', 'I!*', areDisjoint: false); | |
| 99 | 103 |
| 100 // Unions! | 104 checkUnions(['B!=', 'C!='], ['A!<'], areDisjoint: false); |
| 101 checkUnions(['B!=', 'C!='], ['A!=']); | 105 checkUnions(['B!=', 'C!='], ['B!='], areDisjoint: false); |
| 102 checkUnions(['B!=', 'C!='], ['A =']); | 106 checkUnions(['A!<', 'E!<'], ['C!='], areDisjoint: false); |
| 103 checkUnions(['B!=', 'C ='], ['A ='], areDisjoint: false); | 107 checkUnions(['A!<', 'E!<'], ['F!='], areDisjoint: false); |
| 104 | 108 |
| 105 checkUnions(['B!=', 'C!='], ['A!<'], areDisjoint: false); | 109 checkUnions(['A!=', 'E!='], ['C!=', 'F!=']); |
| 106 checkUnions(['B!=', 'C!='], ['B!='], areDisjoint: false); | 110 checkUnions(['A!=', 'E!='], ['A!=', 'F!='], areDisjoint: false); |
| 107 checkUnions(['A!<', 'E!<'], ['C!='], areDisjoint: false); | 111 checkUnions(['B!=', 'E!='], ['A!<', 'F!='], areDisjoint: false); |
| 108 checkUnions(['A!<', 'E!<'], ['F!='], areDisjoint: false); | 112 checkUnions(['A!<', 'E!<'], ['C!=', 'F!='], areDisjoint: false); |
| 109 | 113 checkUnions(['A!=', 'E!='], ['C!=', 'F!=']); |
| 110 checkUnions(['A!=', 'E!='], ['C!=', 'F!=']); | 114 })); |
| 111 checkUnions(['A!=', 'E!='], ['A!=', 'F!='], areDisjoint: false); | |
| 112 checkUnions(['B!=', 'E!='], ['A!<', 'F!='], areDisjoint: false); | |
| 113 checkUnions(['A!<', 'E!<'], ['C!=', 'F!='], areDisjoint: false); | |
| 114 checkUnions(['A!=', 'E!='], ['C!=', 'F!=']); | |
| 115 })); | |
| 116 } | 115 } |
| 117 | 116 |
| 118 /// Checks the expectation of `isDisjoint` for two mask. Also checks that the | 117 /// Checks the expectation of `isDisjoint` for two mask. Also checks that the |
| 119 /// result is consistent with an equivalent (but slower) implementation based on | 118 /// result is consistent with an equivalent (but slower) implementation based on |
| 120 /// intersection. | 119 /// intersection. |
| 121 checkMask(TypeMask m1, TypeMask m2, {areDisjoint: false}) { | 120 checkMask(TypeMask m1, TypeMask m2, {areDisjoint: false}) { |
| 122 print('masks: $m1 $m2'); | 121 print('masks: $m1 $m2'); |
| 123 Expect.equals(areDisjoint, m1.isDisjoint(m2, world)); | 122 Expect.equals(areDisjoint, m1.isDisjoint(m2, world)); |
| 124 Expect.equals(areDisjoint, m2.isDisjoint(m1, world)); | 123 Expect.equals(areDisjoint, m2.isDisjoint(m1, world)); |
| 125 var i1 = m1.intersection(m2, world); | 124 var i1 = m1.intersection(m2, world); |
| 126 Expect.equals(areDisjoint, i1.isEmpty && !i1.isNullable); | 125 Expect.equals(areDisjoint, i1.isEmpty && !i1.isNullable); |
| 127 var i2 = m2.intersection(m1, world); | 126 var i2 = m2.intersection(m1, world); |
| 128 Expect.equals(areDisjoint, i2.isEmpty && !i2.isNullable); | 127 Expect.equals(areDisjoint, i2.isEmpty && !i2.isNullable); |
| 129 } | 128 } |
| 130 | 129 |
| 131 /// Checks the expectation of `isDisjoint` for two mask descriptors (see | 130 /// Checks the expectation of `isDisjoint` for two mask descriptors (see |
| 132 /// [maskOf] for details). | 131 /// [maskOf] for details). |
| 133 check(String typeMaskDescriptor1, String typeMaskDescriptor2, | 132 check(String typeMaskDescriptor1, String typeMaskDescriptor2, |
| 134 {areDisjoint: true}) { | 133 {areDisjoint: true}) { |
| 135 print('[$typeMaskDescriptor1] & [$typeMaskDescriptor2]'); | 134 print('[$typeMaskDescriptor1] & [$typeMaskDescriptor2]'); |
| 136 checkMask(maskOf(typeMaskDescriptor1), maskOf(typeMaskDescriptor2), | 135 checkMask(maskOf(typeMaskDescriptor1), maskOf(typeMaskDescriptor2), |
| 137 areDisjoint: areDisjoint); | 136 areDisjoint: areDisjoint); |
| 138 } | 137 } |
| 139 | 138 |
| 140 | |
| 141 checkUnions(List descriptors1, List descriptors2, {areDisjoint: true}) { | 139 checkUnions(List descriptors1, List descriptors2, {areDisjoint: true}) { |
| 142 print('[$descriptors1] & [$descriptors2]'); | 140 print('[$descriptors1] & [$descriptors2]'); |
| 143 var m1 = new TypeMask.unionOf(descriptors1.map(maskOf).toList(), world); | 141 var m1 = new TypeMask.unionOf(descriptors1.map(maskOf).toList(), world); |
| 144 var m2 = new TypeMask.unionOf(descriptors2.map(maskOf).toList(), world); | 142 var m2 = new TypeMask.unionOf(descriptors2.map(maskOf).toList(), world); |
| 145 checkMask(m1, m2, areDisjoint: areDisjoint); | 143 checkMask(m1, m2, areDisjoint: areDisjoint); |
| 146 } | 144 } |
| 147 | 145 |
| 148 Map _maskCache = {}; | 146 Map _maskCache = {}; |
| 149 Map _elementCache = {}; | 147 Map _elementCache = {}; |
| 150 | 148 |
| 151 /// Parses a descriptor of a flat mask. A descriptor is of the form "AXY" where: | 149 /// Parses a descriptor of a flat mask. A descriptor is of the form "AXY" where: |
| 152 /// A: either a type T or " " (base class or empty) | 150 /// A: either a type T or " " (base class or empty) |
| 153 /// X: can be either ! or " " (nullable/nonnullable) | 151 /// X: can be either ! or " " (nullable/nonnullable) |
| 154 /// Y: can be either " " (no flag), = (exact), < (subclass), * (subtype) | 152 /// Y: can be either " " (no flag), = (exact), < (subclass), * (subtype) |
| 155 /// | 153 /// |
| 156 /// Examples: | 154 /// Examples: |
| 157 /// "-! " - empty, non-null | 155 /// "-! " - empty, non-null |
| 158 /// "- " - null | 156 /// "- " - null |
| 159 /// "Type!=" - non-null exact Type | 157 /// "Type!=" - non-null exact Type |
| 160 /// "Type =" - nullable exact Type | 158 /// "Type =" - nullable exact Type |
| 161 /// "Type!<" - non-null subclass of Type | 159 /// "Type!<" - non-null subclass of Type |
| 162 /// "Type!*" - non-null subtype of Type | 160 /// "Type!*" - non-null subtype of Type |
| 163 TypeMask maskOf(String descriptor) => | 161 TypeMask maskOf(String descriptor) => _maskCache.putIfAbsent(descriptor, () { |
| 164 _maskCache.putIfAbsent(descriptor, () { | 162 Expect.isTrue(descriptor.length >= 3); |
| 165 Expect.isTrue(descriptor.length >= 3); | 163 var type = descriptor.substring(0, descriptor.length - 2); |
| 166 var type = descriptor.substring(0, descriptor.length - 2); | 164 bool isNullable = descriptor[descriptor.length - 2] != '!'; |
| 167 bool isNullable = descriptor[descriptor.length - 2] != '!'; | 165 bool isExact = descriptor[descriptor.length - 1] == '='; |
| 168 bool isExact = descriptor[descriptor.length - 1] == '='; | 166 bool isSubclass = descriptor[descriptor.length - 1] == '<'; |
| 169 bool isSubclass = descriptor[descriptor.length - 1] == '<'; | 167 bool isSubtype = descriptor[descriptor.length - 1] == '*'; |
| 170 bool isSubtype = descriptor[descriptor.length - 1] == '*'; | |
| 171 | 168 |
| 172 if (type == " ") { | 169 if (type == " ") { |
| 173 Expect.isFalse(isExact || isSubclass || isSubtype); | 170 Expect.isFalse(isExact || isSubclass || isSubtype); |
| 174 return isNullable ? new TypeMask.empty() : new TypeMask.nonNullEmpty(); | 171 return isNullable ? new TypeMask.empty() : new TypeMask.nonNullEmpty(); |
| 175 } | 172 } |
| 176 | 173 |
| 177 Expect.isTrue(isExact || isSubclass || isSubtype); | 174 Expect.isTrue(isExact || isSubclass || isSubtype); |
| 178 var element = _elementCache.putIfAbsent(type, | 175 var element = _elementCache.putIfAbsent( |
| 179 () => type == " " ? null : findElement(compiler, type)); | 176 type, () => type == " " ? null : findElement(compiler, type)); |
| 180 | 177 |
| 181 var mask = isExact | 178 var mask = isExact |
| 182 ? new TypeMask.nonNullExact(element, world) | 179 ? new TypeMask.nonNullExact(element, world) |
| 183 : (isSubclass | 180 : (isSubclass |
| 184 ? new TypeMask.nonNullSubclass(element, world) | 181 ? new TypeMask.nonNullSubclass(element, world) |
| 185 : new TypeMask.nonNullSubtype(element, world)); | 182 : new TypeMask.nonNullSubtype(element, world)); |
| 186 return isNullable ? mask.nullable() : mask; | 183 return isNullable ? mask.nullable() : mask; |
| 187 }); | 184 }); |
| OLD | NEW |