| 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.dart'; | 10 import '../common.dart'; |
| 11 import '../common/resolution.dart'; | 11 import '../common/resolution.dart'; |
| 12 import '../constants/expressions.dart'; | 12 import '../constants/expressions.dart'; |
| 13 import '../constants/values.dart'; |
| 13 import '../dart_types.dart'; | 14 import '../dart_types.dart'; |
| 14 import '../elements/elements.dart'; | 15 import '../elements/elements.dart'; |
| 15 import '../elements/visitor.dart'; | 16 import '../elements/visitor.dart'; |
| 16 import '../js_backend/backend_serialization.dart' | 17 import '../js_backend/backend_serialization.dart' |
| 17 show NativeBehaviorSerialization; | 18 show NativeBehaviorSerialization; |
| 18 import '../native/native.dart' show NativeBehavior; | 19 import '../native/native.dart' show NativeBehavior; |
| 19 import '../resolution/access_semantics.dart'; | 20 import '../resolution/access_semantics.dart'; |
| 20 import '../resolution/send_structure.dart'; | 21 import '../resolution/send_structure.dart'; |
| 21 import '../resolution/tree_elements.dart'; | 22 import '../resolution/tree_elements.dart'; |
| 22 import '../tokens/token.dart'; | 23 import '../tokens/token.dart'; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 break; | 57 break; |
| 57 } | 58 } |
| 58 } | 59 } |
| 59 if (!found) { | 60 if (!found) { |
| 60 return false; | 61 return false; |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 return remaining.isEmpty; | 64 return remaining.isEmpty; |
| 64 } | 65 } |
| 65 | 66 |
| 67 /// Returns `true` if the content of [map1] and [map2] is equivalent using |
| 68 /// [keyEquivalence] and [valueEquivalence] to determine key/value equivalence. |
| 69 bool areMapsEquivalent(Map map1, Map map2, |
| 70 [bool keyEquivalence(a, b) = equality, |
| 71 bool valueEquivalence(a, b) = equality]) { |
| 72 Set remaining = map2.keys.toSet(); |
| 73 for (var key1 in map1.keys) { |
| 74 bool found = false; |
| 75 for (var key2 in map2.keys) { |
| 76 if (keyEquivalence(key2, key2)) { |
| 77 found = true; |
| 78 remaining.remove(key2); |
| 79 if (!valueEquivalence(map1[key1], map2[key2])) { |
| 80 return false; |
| 81 } |
| 82 break; |
| 83 } |
| 84 } |
| 85 if (!found) { |
| 86 return false; |
| 87 } |
| 88 } |
| 89 return remaining.isEmpty; |
| 90 } |
| 91 |
| 66 /// Returns `true` if elements [a] and [b] are equivalent. | 92 /// Returns `true` if elements [a] and [b] are equivalent. |
| 67 bool areElementsEquivalent(Element a, Element b) { | 93 bool areElementsEquivalent(Element a, Element b) { |
| 68 if (identical(a, b)) return true; | 94 if (identical(a, b)) return true; |
| 69 if (a == null || b == null) return false; | 95 if (a == null || b == null) return false; |
| 70 return const ElementIdentityEquivalence().visit(a, b); | 96 return const ElementIdentityEquivalence().visit(a, b); |
| 71 } | 97 } |
| 72 | 98 |
| 73 /// Returns `true` if types [a] and [b] are equivalent. | 99 /// Returns `true` if types [a] and [b] are equivalent. |
| 74 bool areTypesEquivalent(DartType a, DartType b) { | 100 bool areTypesEquivalent(DartType a, DartType b) { |
| 75 if (identical(a, b)) return true; | 101 if (identical(a, b)) return true; |
| 76 if (a == null || b == null) return false; | 102 if (a == null || b == null) return false; |
| 77 return const TypeEquivalence().visit(a, b); | 103 return const TypeEquivalence().visit(a, b); |
| 78 } | 104 } |
| 79 | 105 |
| 80 /// Returns `true` if constants [a] and [b] are equivalent. | 106 /// Returns `true` if constants [exp1] and [exp2] are equivalent. |
| 81 bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) { | 107 bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) { |
| 82 if (identical(exp1, exp2)) return true; | 108 if (identical(exp1, exp2)) return true; |
| 83 if (exp1 == null || exp2 == null) return false; | 109 if (exp1 == null || exp2 == null) return false; |
| 84 return const ConstantEquivalence().visit(exp1, exp2); | 110 return const ConstantEquivalence().visit(exp1, exp2); |
| 85 } | 111 } |
| 86 | 112 |
| 113 /// Returns `true` if constant values [value1] and [value2] are equivalent. |
| 114 bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2) { |
| 115 if (identical(value1, value2)) return true; |
| 116 if (value1 == null || value2 == null) return false; |
| 117 return const ConstantValueEquivalence().visit(value1, value2); |
| 118 } |
| 119 |
| 87 /// Returns `true` if the lists of elements, [a] and [b], are equivalent. | 120 /// Returns `true` if the lists of elements, [a] and [b], are equivalent. |
| 88 bool areElementListsEquivalent(List<Element> a, List<Element> b) { | 121 bool areElementListsEquivalent(List<Element> a, List<Element> b) { |
| 89 return areListsEquivalent(a, b, areElementsEquivalent); | 122 return areListsEquivalent(a, b, areElementsEquivalent); |
| 90 } | 123 } |
| 91 | 124 |
| 92 /// Returns `true` if the lists of types, [a] and [b], are equivalent. | 125 /// Returns `true` if the lists of types, [a] and [b], are equivalent. |
| 93 bool areTypeListsEquivalent(List<DartType> a, List<DartType> b) { | 126 bool areTypeListsEquivalent(List<DartType> a, List<DartType> b) { |
| 94 return areListsEquivalent(a, b, areTypesEquivalent); | 127 return areListsEquivalent(a, b, areTypesEquivalent); |
| 95 } | 128 } |
| 96 | 129 |
| 97 /// Returns `true` if the lists of constants, [a] and [b], are equivalent. | 130 /// Returns `true` if the lists of constants, [a] and [b], are equivalent. |
| 98 bool areConstantListsEquivalent( | 131 bool areConstantListsEquivalent( |
| 99 List<ConstantExpression> a, List<ConstantExpression> b) { | 132 List<ConstantExpression> a, List<ConstantExpression> b) { |
| 100 return areListsEquivalent(a, b, areConstantsEquivalent); | 133 return areListsEquivalent(a, b, areConstantsEquivalent); |
| 101 } | 134 } |
| 102 | 135 |
| 136 /// Returns `true` if the lists of constant values, [a] and [b], are equivalent. |
| 137 bool areConstantValueListsEquivalent( |
| 138 List<ConstantValue> a, List<ConstantValue> b) { |
| 139 return areListsEquivalent(a, b, areConstantValuesEquivalent); |
| 140 } |
| 141 |
| 103 /// Returns `true` if the selectors [a] and [b] are equivalent. | 142 /// Returns `true` if the selectors [a] and [b] are equivalent. |
| 104 bool areSelectorsEquivalent(Selector a, Selector b) { | 143 bool areSelectorsEquivalent(Selector a, Selector b) { |
| 105 if (identical(a, b)) return true; | 144 if (identical(a, b)) return true; |
| 106 if (a == null || b == null) return false; | 145 if (a == null || b == null) return false; |
| 107 return a.kind == b.kind && | 146 return a.kind == b.kind && |
| 108 a.callStructure == b.callStructure && | 147 a.callStructure == b.callStructure && |
| 109 areNamesEquivalent(a.memberName, b.memberName); | 148 areNamesEquivalent(a.memberName, b.memberName); |
| 110 } | 149 } |
| 111 | 150 |
| 112 /// Returns `true` if the names [a] and [b] are equivalent. | 151 /// Returns `true` if the names [a] and [b] are equivalent. |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 [bool elementEquivalence(a, b) = equality]) { | 339 [bool elementEquivalence(a, b) = equality]) { |
| 301 return areListsEquivalent(list1, list2, elementEquivalence); | 340 return areListsEquivalent(list1, list2, elementEquivalence); |
| 302 } | 341 } |
| 303 | 342 |
| 304 bool testSets( | 343 bool testSets( |
| 305 var object1, var object2, String property, Iterable set1, Iterable set2, | 344 var object1, var object2, String property, Iterable set1, Iterable set2, |
| 306 [bool elementEquivalence(a, b) = equality]) { | 345 [bool elementEquivalence(a, b) = equality]) { |
| 307 return areSetsEquivalent(set1, set2, elementEquivalence); | 346 return areSetsEquivalent(set1, set2, elementEquivalence); |
| 308 } | 347 } |
| 309 | 348 |
| 349 bool testMaps(var object1, var object2, String property, Map map1, Map map2, |
| 350 [bool keyEquivalence(a, b) = equality, |
| 351 bool valueEquivalence(a, b) = equality]) { |
| 352 return areMapsEquivalent(map1, map2, keyEquivalence, valueEquivalence); |
| 353 } |
| 354 |
| 310 bool testElements(Object object1, Object object2, String property, | 355 bool testElements(Object object1, Object object2, String property, |
| 311 Element element1, Element element2) { | 356 Element element1, Element element2) { |
| 312 return areElementsEquivalent(element1, element2); | 357 return areElementsEquivalent(element1, element2); |
| 313 } | 358 } |
| 314 | 359 |
| 315 bool testTypes(Object object1, Object object2, String property, | 360 bool testTypes(Object object1, Object object2, String property, |
| 316 DartType type1, DartType type2) { | 361 DartType type1, DartType type2) { |
| 317 return areTypesEquivalent(type1, type2); | 362 return areTypesEquivalent(type1, type2); |
| 318 } | 363 } |
| 319 | 364 |
| 320 bool testConstants(Object object1, Object object2, String property, | 365 bool testConstants(Object object1, Object object2, String property, |
| 321 ConstantExpression exp1, ConstantExpression exp2) { | 366 ConstantExpression exp1, ConstantExpression exp2) { |
| 322 return areConstantsEquivalent(exp1, exp2); | 367 return areConstantsEquivalent(exp1, exp2); |
| 323 } | 368 } |
| 324 | 369 |
| 370 bool testConstantValues(Object object1, Object object2, String property, |
| 371 ConstantValue value1, ConstantValue value2) { |
| 372 return areConstantValuesEquivalent(value1, value2); |
| 373 } |
| 374 |
| 325 bool testTypeLists(Object object1, Object object2, String property, | 375 bool testTypeLists(Object object1, Object object2, String property, |
| 326 List<DartType> list1, List<DartType> list2) { | 376 List<DartType> list1, List<DartType> list2) { |
| 327 return areTypeListsEquivalent(list1, list2); | 377 return areTypeListsEquivalent(list1, list2); |
| 328 } | 378 } |
| 329 | 379 |
| 330 bool testConstantLists(Object object1, Object object2, String property, | 380 bool testConstantLists(Object object1, Object object2, String property, |
| 331 List<ConstantExpression> list1, List<ConstantExpression> list2) { | 381 List<ConstantExpression> list1, List<ConstantExpression> list2) { |
| 332 return areConstantListsEquivalent(list1, list2); | 382 return areConstantListsEquivalent(list1, list2); |
| 333 } | 383 } |
| 334 | 384 |
| 385 bool testConstantValueLists(Object object1, Object object2, String property, |
| 386 List<ConstantValue> list1, List<ConstantValue> list2) { |
| 387 return areConstantValueListsEquivalent(list1, list2); |
| 388 } |
| 389 |
| 335 bool testNodes( | 390 bool testNodes( |
| 336 Object object1, Object object2, String property, Node node1, Node node2) { | 391 Object object1, Object object2, String property, Node node1, Node node2) { |
| 337 return areNodesEquivalent(node1, node2); | 392 return areNodesEquivalent(node1, node2); |
| 338 } | 393 } |
| 339 } | 394 } |
| 340 | 395 |
| 341 /// Visitor that checks for equivalence of [Element]s. | 396 /// Visitor that checks for equivalence of [Element]s. |
| 342 class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> { | 397 class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> { |
| 343 final TestStrategy strategy; | 398 final TestStrategy strategy; |
| 344 | 399 |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 @override | 828 @override |
| 774 bool visitStringLength(StringLengthConstantExpression exp1, | 829 bool visitStringLength(StringLengthConstantExpression exp1, |
| 775 StringLengthConstantExpression exp2) { | 830 StringLengthConstantExpression exp2) { |
| 776 return strategy.testConstants( | 831 return strategy.testConstants( |
| 777 exp1, exp2, 'expression', exp1.expression, exp2.expression); | 832 exp1, exp2, 'expression', exp1.expression, exp2.expression); |
| 778 } | 833 } |
| 779 | 834 |
| 780 @override | 835 @override |
| 781 bool visitDeferred( | 836 bool visitDeferred( |
| 782 DeferredConstantExpression exp1, DeferredConstantExpression exp2) { | 837 DeferredConstantExpression exp1, DeferredConstantExpression exp2) { |
| 783 // TODO(johnniwinther): Implement this. | 838 return strategy.testElements( |
| 839 exp1, exp2, 'prefix', exp1.prefix, exp2.prefix) && |
| 840 strategy.testConstants( |
| 841 exp1, exp2, 'expression', exp1.expression, exp2.expression); |
| 842 } |
| 843 } |
| 844 |
| 845 /// Visitor that checks for structural equivalence of [ConstantValue]s. |
| 846 class ConstantValueEquivalence |
| 847 implements ConstantValueVisitor<bool, ConstantValue> { |
| 848 final TestStrategy strategy; |
| 849 |
| 850 const ConstantValueEquivalence([this.strategy = const TestStrategy()]); |
| 851 |
| 852 bool visit(ConstantValue value1, ConstantValue value2) { |
| 853 if (identical(value1, value2)) return true; |
| 854 return strategy.test(value1, value2, 'kind', value1.kind, value2.kind) && |
| 855 value1.accept(this, value2); |
| 856 } |
| 857 |
| 858 @override |
| 859 bool visitConstructed( |
| 860 ConstructedConstantValue value1, ConstructedConstantValue value2) { |
| 861 return strategy.testTypes( |
| 862 value1, value2, 'type', value1.type, value2.type) && |
| 863 strategy.testMaps( |
| 864 value1, |
| 865 value2, |
| 866 'fields', |
| 867 value1.fields, |
| 868 value2.fields, |
| 869 areElementsEquivalent, |
| 870 (a, b) => strategy.testConstantValues( |
| 871 value1, value2, 'fields.values', a, b)); |
| 872 } |
| 873 |
| 874 @override |
| 875 bool visitFunction( |
| 876 FunctionConstantValue value1, FunctionConstantValue value2) { |
| 877 return strategy.testElements( |
| 878 value1, value2, 'element', value1.element, value2.element); |
| 879 } |
| 880 |
| 881 @override |
| 882 bool visitList(ListConstantValue value1, ListConstantValue value2) { |
| 883 return strategy.testTypes( |
| 884 value1, value2, 'type', value1.type, value2.type) && |
| 885 strategy.testConstantValueLists( |
| 886 value1, value2, 'entries', value1.entries, value2.entries); |
| 887 } |
| 888 |
| 889 @override |
| 890 bool visitMap(MapConstantValue value1, MapConstantValue value2) { |
| 891 return strategy.testTypes( |
| 892 value1, value2, 'type', value1.type, value2.type) && |
| 893 strategy.testConstantValueLists( |
| 894 value1, value2, 'keys', value1.keys, value2.keys) && |
| 895 strategy.testConstantValueLists( |
| 896 value1, value2, 'values', value1.values, value2.values); |
| 897 } |
| 898 |
| 899 @override |
| 900 bool visitType(TypeConstantValue value1, TypeConstantValue value2) { |
| 901 return strategy.testTypes(value1, value2, 'type', value1.type, value2.type); |
| 902 } |
| 903 |
| 904 @override |
| 905 bool visitBool(BoolConstantValue value1, BoolConstantValue value2) { |
| 906 return strategy.test(value1, value2, 'primitiveValue', |
| 907 value1.primitiveValue, value2.primitiveValue); |
| 908 } |
| 909 |
| 910 @override |
| 911 bool visitDouble(DoubleConstantValue value1, DoubleConstantValue value2) { |
| 912 return strategy.test(value1, value2, 'primitiveValue', |
| 913 value1.primitiveValue, value2.primitiveValue); |
| 914 } |
| 915 |
| 916 @override |
| 917 bool visitInt(IntConstantValue value1, IntConstantValue value2) { |
| 918 return strategy.test(value1, value2, 'primitiveValue', |
| 919 value1.primitiveValue, value2.primitiveValue); |
| 920 } |
| 921 |
| 922 @override |
| 923 bool visitNull(NullConstantValue value1, NullConstantValue value2) { |
| 784 return true; | 924 return true; |
| 785 } | 925 } |
| 926 |
| 927 @override |
| 928 bool visitString(StringConstantValue value1, StringConstantValue value2) { |
| 929 return strategy.test(value1, value2, 'primitiveValue', |
| 930 value1.primitiveValue, value2.primitiveValue); |
| 931 } |
| 932 |
| 933 @override |
| 934 bool visitDeferred( |
| 935 DeferredConstantValue value1, DeferredConstantValue value2) { |
| 936 return strategy.testElements( |
| 937 value1, value2, 'prefix', value1.prefix, value2.prefix) && |
| 938 strategy.testConstantValues( |
| 939 value1, value2, 'referenced', value1.referenced, value2.referenced); |
| 940 } |
| 941 |
| 942 @override |
| 943 bool visitNonConstant(NonConstantValue value1, NonConstantValue value2) { |
| 944 return true; |
| 945 } |
| 946 |
| 947 @override |
| 948 bool visitSynthetic( |
| 949 SyntheticConstantValue value1, SyntheticConstantValue value2) { |
| 950 return strategy.test( |
| 951 value1, value2, 'payload', value1.payload, value2.payload) && |
| 952 strategy.test( |
| 953 value1, value2, 'valueKind', value1.valueKind, value2.valueKind); |
| 954 } |
| 955 |
| 956 @override |
| 957 bool visitInterceptor( |
| 958 InterceptorConstantValue value1, InterceptorConstantValue value2) { |
| 959 return strategy.testTypes(value1, value2, 'dispatchedType', |
| 960 value1.dispatchedType, value2.dispatchedType); |
| 961 } |
| 786 } | 962 } |
| 787 | 963 |
| 788 /// Tests the equivalence of [impact1] and [impact2] using [strategy]. | 964 /// Tests the equivalence of [impact1] and [impact2] using [strategy]. |
| 789 bool testResolutionImpactEquivalence( | 965 bool testResolutionImpactEquivalence( |
| 790 ResolutionImpact impact1, ResolutionImpact impact2, | 966 ResolutionImpact impact1, ResolutionImpact impact2, |
| 791 [TestStrategy strategy = const TestStrategy()]) { | 967 [TestStrategy strategy = const TestStrategy()]) { |
| 792 return strategy.testSets(impact1, impact2, 'constSymbolNames', | 968 return strategy.testSets(impact1, impact2, 'constSymbolNames', |
| 793 impact1.constSymbolNames, impact2.constSymbolNames) && | 969 impact1.constSymbolNames, impact2.constSymbolNames) && |
| 794 strategy.testSets( | 970 strategy.testSets( |
| 795 impact1, | 971 impact1, |
| (...skipping 1054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1850 } | 2026 } |
| 1851 | 2027 |
| 1852 bool areMetadataAnnotationsEquivalent( | 2028 bool areMetadataAnnotationsEquivalent( |
| 1853 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { | 2029 MetadataAnnotation metadata1, MetadataAnnotation metadata2) { |
| 1854 if (metadata1 == metadata2) return true; | 2030 if (metadata1 == metadata2) return true; |
| 1855 if (metadata1 == null || metadata2 == null) return false; | 2031 if (metadata1 == null || metadata2 == null) return false; |
| 1856 return areElementsEquivalent( | 2032 return areElementsEquivalent( |
| 1857 metadata1.annotatedElement, metadata2.annotatedElement) && | 2033 metadata1.annotatedElement, metadata2.annotatedElement) && |
| 1858 areConstantsEquivalent(metadata1.constant, metadata2.constant); | 2034 areConstantsEquivalent(metadata1.constant, metadata2.constant); |
| 1859 } | 2035 } |
| OLD | NEW |