| 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'; |
| 11 import '../constants/expressions.dart'; | 11 import '../constants/expressions.dart'; |
| 12 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
| 13 import '../elements/resolution_types.dart'; | 13 import '../elements/resolution_types.dart'; |
| 14 import '../elements/elements.dart'; | 14 import '../elements/elements.dart'; |
| 15 import '../elements/entities.dart'; |
| 15 import '../elements/types.dart'; | 16 import '../elements/types.dart'; |
| 16 import '../elements/visitor.dart'; | 17 import '../elements/visitor.dart'; |
| 17 import '../js_backend/backend_serialization.dart' | 18 import '../js_backend/backend_serialization.dart' |
| 18 show NativeBehaviorSerialization; | 19 show NativeBehaviorSerialization; |
| 19 import '../native/native.dart' show NativeBehavior; | 20 import '../native/native.dart' show NativeBehavior; |
| 20 import '../resolution/access_semantics.dart'; | 21 import '../resolution/access_semantics.dart'; |
| 21 import '../resolution/send_structure.dart'; | 22 import '../resolution/send_structure.dart'; |
| 22 import '../resolution/tree_elements.dart'; | 23 import '../resolution/tree_elements.dart'; |
| 23 import '../tokens/token.dart'; | 24 import '../tokens/token.dart'; |
| 24 import '../tree/nodes.dart'; | 25 import '../tree/nodes.dart'; |
| 25 import '../universe/selector.dart'; | 26 import '../universe/selector.dart'; |
| 26 import '../universe/feature.dart'; | 27 import '../universe/feature.dart'; |
| 27 import '../universe/use.dart'; | 28 import '../universe/use.dart'; |
| 28 import '../util/util.dart'; | 29 import '../util/util.dart'; |
| 29 import 'resolved_ast_serialization.dart'; | 30 import 'resolved_ast_serialization.dart'; |
| 30 | 31 |
| 32 typedef bool Equivalence<E>(E a, E b, {TestStrategy strategy}); |
| 33 |
| 31 /// Equality based equivalence function. | 34 /// Equality based equivalence function. |
| 32 bool equality(a, b) => a == b; | 35 bool equality(a, b) => a == b; |
| 33 | 36 |
| 34 /// Returns `true` if the elements in [a] and [b] are pair-wise equivalent | 37 /// Returns `true` if the elements in [a] and [b] are pair-wise equivalent |
| 35 /// according to [elementEquivalence]. | 38 /// according to [elementEquivalence]. |
| 36 bool areListsEquivalent(List a, List b, | 39 bool areListsEquivalent(List a, List b, |
| 37 [bool elementEquivalence(a, b) = equality]) { | 40 [bool elementEquivalence(a, b) = equality]) { |
| 38 if (a.length != b.length) return false; | 41 if (a.length != b.length) return false; |
| 39 for (int i = 0; i < a.length && i < b.length; i++) { | 42 for (int i = 0; i < a.length && i < b.length; i++) { |
| 40 if (!elementEquivalence(a[i], b[i])) { | 43 if (!elementEquivalence(a[i], b[i])) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 } | 87 } |
| 85 } | 88 } |
| 86 if (!found) { | 89 if (!found) { |
| 87 return false; | 90 return false; |
| 88 } | 91 } |
| 89 } | 92 } |
| 90 return remaining.isEmpty; | 93 return remaining.isEmpty; |
| 91 } | 94 } |
| 92 | 95 |
| 93 /// Returns `true` if elements [a] and [b] are equivalent. | 96 /// Returns `true` if elements [a] and [b] are equivalent. |
| 94 bool areElementsEquivalent(Element a, Element b) { | 97 bool areElementsEquivalent(Element a, Element b, {TestStrategy strategy}) { |
| 95 if (identical(a, b)) return true; | 98 if (identical(a, b)) return true; |
| 96 if (a == null || b == null) return false; | 99 if (a == null || b == null) return false; |
| 97 return const ElementIdentityEquivalence().visit(a, b); | 100 return new ElementIdentityEquivalence(strategy ?? const TestStrategy()) |
| 101 .visit(a, b); |
| 98 } | 102 } |
| 99 | 103 |
| 100 /// Returns `true` if types [a] and [b] are equivalent. | 104 /// Returns `true` if types [a] and [b] are equivalent. |
| 101 bool areTypesEquivalent(DartType a, DartType b) { | 105 bool areTypesEquivalent(DartType a, DartType b, {TestStrategy strategy}) { |
| 102 if (identical(a, b)) return true; | 106 if (identical(a, b)) return true; |
| 103 if (a == null || b == null) return false; | 107 if (a == null || b == null) return false; |
| 104 return const TypeEquivalence().visit(a, b); | 108 return new TypeEquivalence(strategy ?? const TestStrategy()).visit(a, b); |
| 105 } | 109 } |
| 106 | 110 |
| 107 /// Returns `true` if constants [exp1] and [exp2] are equivalent. | 111 /// Returns `true` if constants [exp1] and [exp2] are equivalent. |
| 108 bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) { | 112 bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2, |
| 113 {TestStrategy strategy}) { |
| 109 if (identical(exp1, exp2)) return true; | 114 if (identical(exp1, exp2)) return true; |
| 110 if (exp1 == null || exp2 == null) return false; | 115 if (exp1 == null || exp2 == null) return false; |
| 111 return const ConstantEquivalence().visit(exp1, exp2); | 116 return new ConstantEquivalence(strategy ?? const TestStrategy()) |
| 117 .visit(exp1, exp2); |
| 112 } | 118 } |
| 113 | 119 |
| 114 /// Returns `true` if constant values [value1] and [value2] are equivalent. | 120 /// Returns `true` if constant values [value1] and [value2] are equivalent. |
| 115 bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2) { | 121 bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2, |
| 122 {TestStrategy strategy}) { |
| 116 if (identical(value1, value2)) return true; | 123 if (identical(value1, value2)) return true; |
| 117 if (value1 == null || value2 == null) return false; | 124 if (value1 == null || value2 == null) return false; |
| 118 return const ConstantValueEquivalence().visit(value1, value2); | 125 return new ConstantValueEquivalence(strategy ?? const TestStrategy()) |
| 126 .visit(value1, value2); |
| 119 } | 127 } |
| 120 | 128 |
| 121 /// Returns `true` if the lists of elements, [a] and [b], are equivalent. | 129 /// Returns `true` if the lists of elements, [a] and [b], are equivalent. |
| 122 bool areElementListsEquivalent(List<Element> a, List<Element> b) { | 130 bool areElementListsEquivalent(List<Element> a, List<Element> b) { |
| 123 return areListsEquivalent(a, b, areElementsEquivalent); | 131 return areListsEquivalent(a, b, areElementsEquivalent); |
| 124 } | 132 } |
| 125 | 133 |
| 126 /// Returns `true` if the lists of types, [a] and [b], are equivalent. | 134 /// Returns `true` if the lists of types, [a] and [b], are equivalent. |
| 127 bool areTypeListsEquivalent( | 135 bool areTypeListsEquivalent( |
| 128 List<ResolutionDartType> a, List<ResolutionDartType> b) { | 136 List<ResolutionDartType> a, List<ResolutionDartType> b) { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 bool areNodesEquivalent(Node node1, Node node2) { | 333 bool areNodesEquivalent(Node node1, Node node2) { |
| 326 if (identical(node1, node2)) return true; | 334 if (identical(node1, node2)) return true; |
| 327 if (node1 == null || node2 == null) return false; | 335 if (node1 == null || node2 == null) return false; |
| 328 return node1.accept1(const NodeEquivalenceVisitor(), node2); | 336 return node1.accept1(const NodeEquivalenceVisitor(), node2); |
| 329 } | 337 } |
| 330 | 338 |
| 331 /// Strategy for testing equivalence. | 339 /// Strategy for testing equivalence. |
| 332 /// | 340 /// |
| 333 /// Use this strategy to determine equivalence without failing on inequivalence. | 341 /// Use this strategy to determine equivalence without failing on inequivalence. |
| 334 class TestStrategy { | 342 class TestStrategy { |
| 335 const TestStrategy(); | 343 final Equivalence<Entity> elementEquivalence; |
| 344 final Equivalence<DartType> typeEquivalence; |
| 345 final Equivalence<ConstantExpression> constantEquivalence; |
| 346 final Equivalence<ConstantValue> constantValueEquivalence; |
| 347 |
| 348 const TestStrategy( |
| 349 {this.elementEquivalence: areElementsEquivalent, |
| 350 this.typeEquivalence: areTypesEquivalent, |
| 351 this.constantEquivalence: areConstantsEquivalent, |
| 352 this.constantValueEquivalence: areConstantValuesEquivalent}); |
| 353 |
| 354 /// An equivalence [TestStrategy] that doesn't throw on inequivalence. |
| 355 TestStrategy get testOnly => this; |
| 336 | 356 |
| 337 bool test(var object1, var object2, String property, var value1, var value2, | 357 bool test(var object1, var object2, String property, var value1, var value2, |
| 338 [bool equivalence(a, b) = equality]) { | 358 [bool equivalence(a, b) = equality]) { |
| 339 return equivalence(value1, value2); | 359 return equivalence(value1, value2); |
| 340 } | 360 } |
| 341 | 361 |
| 342 bool testLists( | 362 bool testLists( |
| 343 Object object1, Object object2, String property, List list1, List list2, | 363 Object object1, Object object2, String property, List list1, List list2, |
| 344 [bool elementEquivalence(a, b) = equality]) { | 364 [bool elementEquivalence(a, b) = equality]) { |
| 345 return areListsEquivalent(list1, list2, elementEquivalence); | 365 return areListsEquivalent(list1, list2, elementEquivalence); |
| 346 } | 366 } |
| 347 | 367 |
| 348 bool testSets( | 368 bool testSets( |
| 349 var object1, var object2, String property, Iterable set1, Iterable set2, | 369 var object1, var object2, String property, Iterable set1, Iterable set2, |
| 350 [bool elementEquivalence(a, b) = equality]) { | 370 [bool elementEquivalence(a, b) = equality]) { |
| 351 return areSetsEquivalent(set1, set2, elementEquivalence); | 371 return areSetsEquivalent(set1, set2, elementEquivalence); |
| 352 } | 372 } |
| 353 | 373 |
| 354 bool testMaps(var object1, var object2, String property, Map map1, Map map2, | 374 bool testMaps(var object1, var object2, String property, Map map1, Map map2, |
| 355 [bool keyEquivalence(a, b) = equality, | 375 [bool keyEquivalence(a, b) = equality, |
| 356 bool valueEquivalence(a, b) = equality]) { | 376 bool valueEquivalence(a, b) = equality]) { |
| 357 return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence); | 377 return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence); |
| 358 } | 378 } |
| 359 | 379 |
| 360 bool testElements(Object object1, Object object2, String property, | 380 bool testElements(Object object1, Object object2, String property, |
| 361 Element element1, Element element2) { | 381 Entity element1, Entity element2) { |
| 362 return areElementsEquivalent(element1, element2); | 382 return test(object1, object2, property, element1, element2, |
| 383 (a, b) => elementEquivalence(a, b, strategy: this)); |
| 363 } | 384 } |
| 364 | 385 |
| 365 bool testTypes(Object object1, Object object2, String property, | 386 bool testTypes(Object object1, Object object2, String property, |
| 366 ResolutionDartType type1, ResolutionDartType type2) { | 387 DartType type1, DartType type2) { |
| 367 return areTypesEquivalent(type1, type2); | 388 return test(object1, object2, property, type1, type2, |
| 389 (a, b) => typeEquivalence(a, b, strategy: this)); |
| 368 } | 390 } |
| 369 | 391 |
| 370 bool testConstants(Object object1, Object object2, String property, | 392 bool testConstants(Object object1, Object object2, String property, |
| 371 ConstantExpression exp1, ConstantExpression exp2) { | 393 ConstantExpression exp1, ConstantExpression exp2) { |
| 372 return areConstantsEquivalent(exp1, exp2); | 394 return test(object1, object2, property, exp1, exp2, |
| 395 (a, b) => constantEquivalence(a, b, strategy: this)); |
| 373 } | 396 } |
| 374 | 397 |
| 375 bool testConstantValues(Object object1, Object object2, String property, | 398 bool testConstantValues(Object object1, Object object2, String property, |
| 376 ConstantValue value1, ConstantValue value2) { | 399 ConstantValue value1, ConstantValue value2) { |
| 377 return areConstantValuesEquivalent(value1, value2); | 400 return test(object1, object2, property, value1, value2, |
| 401 (a, b) => constantValueEquivalence(a, b, strategy: this)); |
| 378 } | 402 } |
| 379 | 403 |
| 380 bool testTypeLists(Object object1, Object object2, String property, | 404 bool testTypeLists(Object object1, Object object2, String property, |
| 381 List<ResolutionDartType> list1, List<ResolutionDartType> list2) { | 405 List<DartType> list1, List<DartType> list2) { |
| 382 return areTypeListsEquivalent(list1, list2); | 406 return testLists(object1, object2, property, list1, list2, |
| 407 (a, b) => typeEquivalence(a, b, strategy: this)); |
| 383 } | 408 } |
| 384 | 409 |
| 385 bool testConstantLists(Object object1, Object object2, String property, | 410 bool testConstantLists(Object object1, Object object2, String property, |
| 386 List<ConstantExpression> list1, List<ConstantExpression> list2) { | 411 List<ConstantExpression> list1, List<ConstantExpression> list2) { |
| 387 return areConstantListsEquivalent(list1, list2); | 412 return testLists(object1, object2, property, list1, list2, |
| 413 (a, b) => constantEquivalence(a, b, strategy: this)); |
| 388 } | 414 } |
| 389 | 415 |
| 390 bool testConstantValueLists(Object object1, Object object2, String property, | 416 bool testConstantValueLists(Object object1, Object object2, String property, |
| 391 List<ConstantValue> list1, List<ConstantValue> list2) { | 417 List<ConstantValue> list1, List<ConstantValue> list2) { |
| 392 return areConstantValueListsEquivalent(list1, list2); | 418 return testLists(object1, object2, property, list1, list2, |
| 419 (a, b) => constantValueEquivalence(a, b, strategy: this)); |
| 393 } | 420 } |
| 394 | 421 |
| 395 bool testNodes( | 422 bool testNodes( |
| 396 Object object1, Object object2, String property, Node node1, Node node2) { | 423 Object object1, Object object2, String property, Node node1, Node node2) { |
| 397 return areNodesEquivalent(node1, node2); | 424 return areNodesEquivalent(node1, node2); |
| 398 } | 425 } |
| 399 } | 426 } |
| 400 | 427 |
| 401 /// Visitor that checks for equivalence of [Element]s. | 428 /// Visitor that checks for equivalence of [Element]s. |
| 402 class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> { | 429 class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> { |
| (...skipping 1645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2048 } | 2075 } |
| 2049 | 2076 |
| 2050 bool areMetadataAnnotationsEquivalent( | 2077 bool areMetadataAnnotationsEquivalent( |
| 2051 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { | 2078 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { |
| 2052 if (metadata1 == metadata2) return true; | 2079 if (metadata1 == metadata2) return true; |
| 2053 if (metadata1 == null || metadata2 == null) return false; | 2080 if (metadata1 == null || metadata2 == null) return false; |
| 2054 return areElementsEquivalent( | 2081 return areElementsEquivalent( |
| 2055 metadata1.annotatedElement, metadata2.annotatedElement) && | 2082 metadata1.annotatedElement, metadata2.annotatedElement) && |
| 2056 areConstantsEquivalent(metadata1.constant, metadata2.constant); | 2083 areConstantsEquivalent(metadata1.constant, metadata2.constant); |
| 2057 } | 2084 } |
| OLD | NEW |