OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 /// Functions for asserting equivalence across serialization. | 5 /// Functions for asserting equivalence across serialization. |
6 | 6 |
7 library dart2js.serialization.equivalence; | 7 library dart2js.serialization.equivalence; |
8 | 8 |
9 import '../closure.dart'; | 9 import '../closure.dart'; |
10 import '../common/resolution.dart'; | 10 import '../common/resolution.dart'; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 } | 47 } |
48 } | 48 } |
49 return true; | 49 return true; |
50 } | 50 } |
51 | 51 |
52 /// Returns `true` if the elements in [a] and [b] are equivalent as sets using | 52 /// Returns `true` if the elements in [a] and [b] are equivalent as sets using |
53 /// [elementEquivalence] to determine element equivalence. | 53 /// [elementEquivalence] to determine element equivalence. |
54 bool areSetsEquivalent(Iterable set1, Iterable set2, | 54 bool areSetsEquivalent(Iterable set1, Iterable set2, |
55 [bool elementEquivalence(a, b) = equality]) { | 55 [bool elementEquivalence(a, b) = equality]) { |
56 Set remaining = set2.toSet(); | 56 Set remaining = set2.toSet(); |
57 for (var element1 in set1) { | 57 for (dynamic element1 in set1) { |
58 bool found = false; | 58 bool found = false; |
59 for (var element2 in set2) { | 59 for (dynamic element2 in set2) { |
60 if (elementEquivalence(element1, element2)) { | 60 if (elementEquivalence(element1, element2)) { |
61 found = true; | 61 found = true; |
62 remaining.remove(element2); | 62 remaining.remove(element2); |
63 break; | 63 break; |
64 } | 64 } |
65 } | 65 } |
66 if (!found) { | 66 if (!found) { |
67 return false; | 67 return false; |
68 } | 68 } |
69 } | 69 } |
70 return remaining.isEmpty; | 70 return remaining.isEmpty; |
71 } | 71 } |
72 | 72 |
73 /// Returns `true` if the content of [map1] and [map2] is equivalent using | 73 /// Returns `true` if the content of [map1] and [map2] is equivalent using |
74 /// [keyEquivalence] and [valueEquivalence] to determine key/value equivalence. | 74 /// [keyEquivalence] and [valueEquivalence] to determine key/value equivalence. |
75 bool areMapsEquivalent(Map map1, Map map2, | 75 bool areMapsEquivalent(Map map1, Map map2, |
76 [bool keyEquivalence(a, b) = equality, | 76 [bool keyEquivalence(a, b) = equality, |
77 bool valueEquivalence(a, b) = equality]) { | 77 bool valueEquivalence(a, b) = equality]) { |
78 Set remaining = map2.keys.toSet(); | 78 Set remaining = map2.keys.toSet(); |
79 for (var key1 in map1.keys) { | 79 for (dynamic key1 in map1.keys) { |
80 bool found = false; | 80 bool found = false; |
81 for (var key2 in map2.keys) { | 81 for (dynamic key2 in map2.keys) { |
82 if (keyEquivalence(key1, key2)) { | 82 if (keyEquivalence(key1, key2)) { |
83 found = true; | 83 found = true; |
84 remaining.remove(key2); | 84 remaining.remove(key2); |
85 if (!valueEquivalence(map1[key1], map2[key2])) { | 85 if (!valueEquivalence(map1[key1], map2[key2])) { |
86 return false; | 86 return false; |
87 } | 87 } |
88 break; | 88 break; |
89 } | 89 } |
90 } | 90 } |
91 if (!found) { | 91 if (!found) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 throw new UnsupportedError('Unsupported access kind: ${a.kind}'); | 258 throw new UnsupportedError('Unsupported access kind: ${a.kind}'); |
259 } | 259 } |
260 } | 260 } |
261 | 261 |
262 /// Returns `true` if the send structures [a] and [b] are equivalent. | 262 /// Returns `true` if the send structures [a] and [b] are equivalent. |
263 bool areSendStructuresEquivalent(SendStructure a, SendStructure b) { | 263 bool areSendStructuresEquivalent(SendStructure a, SendStructure b) { |
264 if (identical(a, b)) return true; | 264 if (identical(a, b)) return true; |
265 if (a == null || b == null) return false; | 265 if (a == null || b == null) return false; |
266 if (a.kind != b.kind) return false; | 266 if (a.kind != b.kind) return false; |
267 | 267 |
268 var ad = a; | 268 dynamic ad = a; |
269 var bd = b; | 269 dynamic bd = b; |
270 switch (a.kind) { | 270 switch (a.kind) { |
271 case SendStructureKind.IF_NULL: | 271 case SendStructureKind.IF_NULL: |
272 case SendStructureKind.LOGICAL_AND: | 272 case SendStructureKind.LOGICAL_AND: |
273 case SendStructureKind.LOGICAL_OR: | 273 case SendStructureKind.LOGICAL_OR: |
274 case SendStructureKind.NOT: | 274 case SendStructureKind.NOT: |
275 case SendStructureKind.INVALID_UNARY: | 275 case SendStructureKind.INVALID_UNARY: |
276 case SendStructureKind.INVALID_BINARY: | 276 case SendStructureKind.INVALID_BINARY: |
277 // No additional properties. | 277 // No additional properties. |
278 return true; | 278 return true; |
279 | 279 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 } | 315 } |
316 throw new UnsupportedError('Unexpected send structures $a vs $b'); | 316 throw new UnsupportedError('Unexpected send structures $a vs $b'); |
317 } | 317 } |
318 | 318 |
319 /// Returns `true` if the new structures [a] and [b] are equivalent. | 319 /// Returns `true` if the new structures [a] and [b] are equivalent. |
320 bool areNewStructuresEquivalent(NewStructure a, NewStructure b) { | 320 bool areNewStructuresEquivalent(NewStructure a, NewStructure b) { |
321 if (identical(a, b)) return true; | 321 if (identical(a, b)) return true; |
322 if (a == null || b == null) return false; | 322 if (a == null || b == null) return false; |
323 if (a.kind != b.kind) return false; | 323 if (a.kind != b.kind) return false; |
324 | 324 |
325 var ad = a; | 325 dynamic ad = a; |
326 var bd = b; | 326 dynamic bd = b; |
327 switch (a.kind) { | 327 switch (a.kind) { |
328 case NewStructureKind.NEW_INVOKE: | 328 case NewStructureKind.NEW_INVOKE: |
329 return ad.semantics.kind == bd.semantics.kind && | 329 return ad.semantics.kind == bd.semantics.kind && |
330 areElementsEquivalent(ad.semantics.element, bd.semantics.element) && | 330 areElementsEquivalent(ad.semantics.element, bd.semantics.element) && |
331 areTypesEquivalent(ad.semantics.type, bd.semantics.type) && | 331 areTypesEquivalent(ad.semantics.type, bd.semantics.type) && |
332 areSelectorsEquivalent(ad.selector, bd.selector); | 332 areSelectorsEquivalent(ad.selector, bd.selector); |
333 case NewStructureKind.CONST_INVOKE: | 333 case NewStructureKind.CONST_INVOKE: |
334 return ad.constantInvokeKind == bd.constantInvokeKind && | 334 return ad.constantInvokeKind == bd.constantInvokeKind && |
335 areConstantsEquivalent(ad.constant, bd.constant); | 335 areConstantsEquivalent(ad.constant, bd.constant); |
336 case NewStructureKind.LATE_CONST: | 336 case NewStructureKind.LATE_CONST: |
(...skipping 20 matching lines...) Expand all Loading... |
357 | 357 |
358 const TestStrategy( | 358 const TestStrategy( |
359 {this.elementEquivalence: areElementsEquivalent, | 359 {this.elementEquivalence: areElementsEquivalent, |
360 this.typeEquivalence: areTypesEquivalent, | 360 this.typeEquivalence: areTypesEquivalent, |
361 this.constantEquivalence: areConstantsEquivalent, | 361 this.constantEquivalence: areConstantsEquivalent, |
362 this.constantValueEquivalence: areConstantValuesEquivalent}); | 362 this.constantValueEquivalence: areConstantValuesEquivalent}); |
363 | 363 |
364 /// An equivalence [TestStrategy] that doesn't throw on inequivalence. | 364 /// An equivalence [TestStrategy] that doesn't throw on inequivalence. |
365 TestStrategy get testOnly => this; | 365 TestStrategy get testOnly => this; |
366 | 366 |
367 bool test(var object1, var object2, String property, var value1, var value2, | 367 bool test(dynamic object1, dynamic object2, String property, dynamic value1, |
| 368 dynamic value2, |
368 [bool equivalence(a, b) = equality]) { | 369 [bool equivalence(a, b) = equality]) { |
369 return equivalence(value1, value2); | 370 return equivalence(value1, value2); |
370 } | 371 } |
371 | 372 |
372 bool testLists( | 373 bool testLists( |
373 Object object1, Object object2, String property, List list1, List list2, | 374 Object object1, Object object2, String property, List list1, List list2, |
374 [bool elementEquivalence(a, b) = equality]) { | 375 [bool elementEquivalence(a, b) = equality]) { |
375 return areListsEquivalent(list1, list2, elementEquivalence); | 376 return areListsEquivalent(list1, list2, elementEquivalence); |
376 } | 377 } |
377 | 378 |
378 bool testSets( | 379 bool testSets(dynamic object1, dynamic object2, String property, |
379 var object1, var object2, String property, Iterable set1, Iterable set2, | 380 Iterable set1, Iterable set2, |
380 [bool elementEquivalence(a, b) = equality]) { | 381 [bool elementEquivalence(a, b) = equality]) { |
381 return areSetsEquivalent(set1, set2, elementEquivalence); | 382 return areSetsEquivalent(set1, set2, elementEquivalence); |
382 } | 383 } |
383 | 384 |
384 bool testMaps(var object1, var object2, String property, Map map1, Map map2, | 385 bool testMaps( |
| 386 dynamic object1, dynamic object2, String property, Map map1, Map map2, |
385 [bool keyEquivalence(a, b) = equality, | 387 [bool keyEquivalence(a, b) = equality, |
386 bool valueEquivalence(a, b) = equality]) { | 388 bool valueEquivalence(a, b) = equality]) { |
387 return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence); | 389 return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence); |
388 } | 390 } |
389 | 391 |
390 bool testElements(Object object1, Object object2, String property, | 392 bool testElements(Object object1, Object object2, String property, |
391 Entity element1, Entity element2) { | 393 Entity element1, Entity element2) { |
392 return test(object1, object2, property, element1, element2, | 394 return test(object1, object2, property, element1, element2, |
393 (a, b) => elementEquivalence(a, b, strategy: this)); | 395 (a, b) => elementEquivalence(a, b, strategy: this)); |
394 } | 396 } |
(...skipping 701 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 resolvedAst2.node) && | 1098 resolvedAst2.node) && |
1097 strategy.testNodes(resolvedAst1, resolvedAst2, 'body', resolvedAst1.body, | 1099 strategy.testNodes(resolvedAst1, resolvedAst2, 'body', resolvedAst1.body, |
1098 resolvedAst2.body) && | 1100 resolvedAst2.body) && |
1099 testTreeElementsEquivalence(resolvedAst1, resolvedAst2, strategy) && | 1101 testTreeElementsEquivalence(resolvedAst1, resolvedAst2, strategy) && |
1100 strategy.test(resolvedAst1, resolvedAst2, 'sourceUri', | 1102 strategy.test(resolvedAst1, resolvedAst2, 'sourceUri', |
1101 resolvedAst1.sourceUri, resolvedAst2.sourceUri); | 1103 resolvedAst1.sourceUri, resolvedAst2.sourceUri); |
1102 if (resolvedAst1.element is FunctionElement) { | 1104 if (resolvedAst1.element is FunctionElement) { |
1103 FunctionElement element1 = resolvedAst1.element; | 1105 FunctionElement element1 = resolvedAst1.element; |
1104 FunctionElement element2 = resolvedAst2.element; | 1106 FunctionElement element2 = resolvedAst2.element; |
1105 for (int index = 0; index < element1.parameters.length; index++) { | 1107 for (int index = 0; index < element1.parameters.length; index++) { |
1106 var parameter1 = element1.parameters[index]; | 1108 dynamic parameter1 = element1.parameters[index]; |
1107 var parameter2 = element2.parameters[index]; | 1109 dynamic parameter2 = element2.parameters[index]; |
1108 result = result && | 1110 result = result && |
1109 strategy.testNodes(parameter1, parameter2, 'node', | 1111 strategy.testNodes(parameter1, parameter2, 'node', |
1110 parameter1.implementation.node, parameter2.implementation.node) && | 1112 parameter1.implementation.node, parameter2.implementation.node) && |
1111 strategy.testNodes( | 1113 strategy.testNodes( |
1112 parameter1, | 1114 parameter1, |
1113 parameter2, | 1115 parameter2, |
1114 'initializer', | 1116 'initializer', |
1115 parameter1.implementation.initializer, | 1117 parameter1.implementation.initializer, |
1116 parameter2.implementation.initializer); | 1118 parameter2.implementation.initializer); |
1117 } | 1119 } |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1398 elements1.getLabelDefinition(node1), | 1400 elements1.getLabelDefinition(node1), |
1399 elements2.getLabelDefinition(node2)); | 1401 elements2.getLabelDefinition(node2)); |
1400 } | 1402 } |
1401 } | 1403 } |
1402 | 1404 |
1403 class NodeEquivalenceVisitor implements Visitor1<bool, Node> { | 1405 class NodeEquivalenceVisitor implements Visitor1<bool, Node> { |
1404 final TestStrategy strategy; | 1406 final TestStrategy strategy; |
1405 | 1407 |
1406 const NodeEquivalenceVisitor([this.strategy = const TestStrategy()]); | 1408 const NodeEquivalenceVisitor([this.strategy = const TestStrategy()]); |
1407 | 1409 |
1408 bool testNodes( | 1410 bool testNodes(dynamic object1, dynamic object2, String property, Node node1, |
1409 var object1, var object2, String property, Node node1, Node node2) { | 1411 Node node2) { |
1410 return strategy.test(object1, object2, property, node1, node2, | 1412 return strategy.test(object1, object2, property, node1, node2, |
1411 (Node n1, Node n2) { | 1413 (Node n1, Node n2) { |
1412 if (n1 == n2) return true; | 1414 if (n1 == n2) return true; |
1413 if (n1 == null || n2 == null) return false; | 1415 if (n1 == null || n2 == null) return false; |
1414 return n1.accept1(this, n2); | 1416 return n1.accept1(this, n2); |
1415 }); | 1417 }); |
1416 } | 1418 } |
1417 | 1419 |
1418 bool testNodeLists(var object1, var object2, String property, | 1420 bool testNodeLists(dynamic object1, dynamic object2, String property, |
1419 Link<Node> list1, Link<Node> list2) { | 1421 Link<Node> list1, Link<Node> list2) { |
1420 return strategy.test(object1, object2, property, list1, list2, | 1422 return strategy.test(object1, object2, property, list1, list2, |
1421 (Link<Node> l1, Link<Node> l2) { | 1423 (Link<Node> l1, Link<Node> l2) { |
1422 if (l1 == l2) return true; | 1424 if (l1 == l2) return true; |
1423 if (l1 == null || l2 == null) return false; | 1425 if (l1 == null || l2 == null) return false; |
1424 while (l1.isNotEmpty && l2.isNotEmpty) { | 1426 while (l1.isNotEmpty && l2.isNotEmpty) { |
1425 if (!l1.head.accept1(this, l2.head)) { | 1427 if (!l1.head.accept1(this, l2.head)) { |
1426 return false; | 1428 return false; |
1427 } | 1429 } |
1428 l1 = l1.tail; | 1430 l1 = l1.tail; |
1429 l2 = l2.tail; | 1431 l2 = l2.tail; |
1430 } | 1432 } |
1431 return l1.isEmpty && l2.isEmpty; | 1433 return l1.isEmpty && l2.isEmpty; |
1432 }); | 1434 }); |
1433 } | 1435 } |
1434 | 1436 |
1435 bool testTokens( | 1437 bool testTokens(dynamic object1, dynamic object2, String property, |
1436 var object1, var object2, String property, Token token1, Token token2) { | 1438 Token token1, Token token2) { |
1437 return strategy.test(object1, object2, property, token1, token2, | 1439 return strategy.test(object1, object2, property, token1, token2, |
1438 (Token t1, Token t2) { | 1440 (Token t1, Token t2) { |
1439 if (t1 == t2) return true; | 1441 if (t1 == t2) return true; |
1440 if (t1 == null || t2 == null) return false; | 1442 if (t1 == null || t2 == null) return false; |
1441 return strategy.test( | 1443 return strategy.test( |
1442 t1, t2, 'charOffset', t1.charOffset, t2.charOffset) && | 1444 t1, t2, 'charOffset', t1.charOffset, t2.charOffset) && |
1443 strategy.test(t1, t2, 'info', t1.type, t2.type) && | 1445 strategy.test(t1, t2, 'info', t1.type, t2.type) && |
1444 strategy.test(t1, t2, 'value', t1.lexeme, t2.lexeme); | 1446 strategy.test(t1, t2, 'value', t1.lexeme, t2.lexeme); |
1445 }); | 1447 }); |
1446 } | 1448 } |
(...skipping 688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2135 } | 2137 } |
2136 | 2138 |
2137 bool areMetadataAnnotationsEquivalent( | 2139 bool areMetadataAnnotationsEquivalent( |
2138 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { | 2140 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { |
2139 if (metadata1 == metadata2) return true; | 2141 if (metadata1 == metadata2) return true; |
2140 if (metadata1 == null || metadata2 == null) return false; | 2142 if (metadata1 == null || metadata2 == null) return false; |
2141 return areElementsEquivalent( | 2143 return areElementsEquivalent( |
2142 metadata1.annotatedElement, metadata2.annotatedElement) && | 2144 metadata1.annotatedElement, metadata2.annotatedElement) && |
2143 areConstantsEquivalent(metadata1.constant, metadata2.constant); | 2145 areConstantsEquivalent(metadata1.constant, metadata2.constant); |
2144 } | 2146 } |
OLD | NEW |