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 |