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 |