| 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 |