Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: pkg/compiler/lib/src/serialization/equivalence.dart

Issue 1856713002: Test ResolutionImpact equivalence. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// Functions for asserting equivalence across serialization.
6
7 library dart2js.serialization.equivalence;
8
9 import '../common/resolution.dart';
10 import '../constants/expressions.dart';
11 import '../dart_types.dart';
12 import '../elements/elements.dart';
13 import '../elements/visitor.dart';
14 import '../universe/selector.dart';
15 import '../universe/use.dart';
16
17 /// Equality based equivalence function.
18 bool equality(a, b) => a == b;
19
20 /// Returns `true` if the elements in [a] and [b] are pair-wise equivalent
21 /// according to [elementEquivalence].
22 bool areListsEquivalent(
23 List a,
24 List b,
25 [bool elementEquivalence(a, b) = equality]) {
26
27 if (a.length != b.length) return false;
28 for (int i = 0; i < a.length && i < b.length; i++) {
29 if (!elementEquivalence(a[i], b[i])) {
30 return false;
31 }
32 }
33 return true;
34 }
35
36 /// Returns `true` if the elements in [a] and [b] are equivalent as sets using
37 /// [elementEquivalence] to determine element equivalence.
38 bool areSetsEquivalent(
39 Iterable set1,
40 Iterable set2,
41 [bool elementEquivalence(a, b) = equality]) {
42
43 Set remaining = set2.toSet();
44 for (var element1 in set1) {
45 bool found = false;
46 for (var element2 in set2) {
47 if (elementEquivalence(element1, element2)) {
48 found = true;
49 remaining.remove(element2);
50 break;
51 }
52 }
53 if (!found) {
54 return false;
55 }
56 }
57 return remaining.isEmpty;
58 }
59
60 /// Returns `true` if elements [a] and [b] are equivalent.
61 bool areElementsEquivalent(Element a, Element b) {
62 if (identical(a, b)) return true;
63 if (a == null || b == null) return false;
64 return const ElementIdentityEquivalence().visit(a, b);
65 }
66
67 /// Returns `true` if types [a] and [b] are equivalent.
68 bool areTypesEquivalent(DartType a, DartType b) {
69 if (identical(a, b)) return true;
70 if (a == null || b == null) return false;
71 return const TypeEquivalence().visit(a, b);
72 }
73
74 /// Returns `true` if constants [a] and [b] are equivalent.
75 bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) {
76 if (identical(exp1, exp2)) return true;
77 if (exp1 == null || exp2 == null) return false;
78 return const ConstantEquivalence().visit(exp1, exp2);
79 }
80
81 /// Returns `true` if the lists of elements, [a] and [b], are equivalent.
82 bool areElementListsEquivalent(List<Element> a, List<Element> b) {
83 return areListsEquivalent(a, b, areElementsEquivalent);
84 }
85
86 /// Returns `true` if the lists of types, [a] and [b], are equivalent.
87 bool areTypeListsEquivalent(List<DartType> a, List<DartType> b) {
88 return areListsEquivalent(a, b, areTypesEquivalent);
89 }
90
91 /// Returns `true` if the lists of constants, [a] and [b], are equivalent.
92 bool areConstantListsEquivalent(List<ConstantExpression> a,
93 List<ConstantExpression> b) {
94 return areListsEquivalent(a, b, areConstantsEquivalent);
95 }
96
97 /// Returns `true` if the selectors [a] and [b] are equivalent.
98 bool areSelectorsEquivalent(Selector a, Selector b) {
99 return a.kind == b.kind &&
100 a.callStructure == b.callStructure &&
101 areNamesEquivalent(a.memberName, b.memberName);
102 }
103
104 /// Returns `true` if the names [a] and [b] are equivalent.
105 bool areNamesEquivalent(Name a, Name b) {
106 return a.text == b.text &&
107 a.isSetter == b.isSetter &&
108 areElementsEquivalent(a.library, b.library);
109 }
110
111 /// Returns `true` if the dynamic uses [a] and [b] are equivalent.
112 bool areDynamicUsesEquivalent(DynamicUse a, DynamicUse b) {
113 return areSelectorsEquivalent(a.selector, b.selector);
114 }
115
116 /// Returns `true` if the static uses [a] and [b] are equivalent.
117 bool areStaticUsesEquivalent(StaticUse a, StaticUse b) {
118 return a.kind == b.kind &&
119 areElementsEquivalent(a.element, b.element);
120 }
121
122 /// Returns `true` if the type uses [a] and [b] are equivalent.
123 bool areTypeUsesEquivalent(TypeUse a, TypeUse b) {
124 return a.kind == b.kind &&
125 areTypesEquivalent(a.type, b.type);
126 }
127
128 /// Returns `true` if the list literal uses [a] and [b] are equivalent.
129 bool areListLiteralUsesEquivalent(ListLiteralUse a, ListLiteralUse b) {
130 return areTypesEquivalent(a.type, b.type) &&
131 a.isConstant == b.isConstant &&
132 a.isEmpty == b.isEmpty;
133 }
134
135 /// Returns `true` if the map literal uses [a] and [b] are equivalent.
136 bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b) {
137 return areTypesEquivalent(a.type, b.type) &&
138 a.isConstant == b.isConstant &&
139 a.isEmpty == b.isEmpty;
140 }
141
142 /// Strategy for testing equivalence.
143 ///
144 /// Use this strategy to determine equivalence without failing on inequivalence.
145 class TestStrategy {
146 const TestStrategy();
147
148 bool test(var object1, var object2, String property, var value1, var value2) {
149 return value1 == value2;
150 }
151
152 bool testLists(
153 Object object1, Object object2, String property,
154 List list1, List list2,
155 [bool elementEquivalence(a, b) = equality]) {
156 return areListsEquivalent(list1, list2, elementEquivalence);
157 }
158
159 bool testSets(
160 var object1, var object2, String property,
161 Iterable set1, Iterable set2,
162 [bool elementEquivalence(a, b) = equality]) {
163 return areSetsEquivalent(set1, set2, elementEquivalence);
164 }
165
166 bool testElements(
167 Object object1, Object object2, String property,
168 Element element1, Element element2) {
169 return areElementsEquivalent(element1, element2);
170 }
171
172 bool testTypes(
173 Object object1, Object object2, String property,
174 DartType type1, DartType type2) {
175 return areTypesEquivalent(type1, type2);
176 }
177
178 bool testConstants(
179 Object object1, Object object2, String property,
180 ConstantExpression exp1, ConstantExpression exp2) {
181 return areConstantsEquivalent(exp1, exp2);
182 }
183
184 bool testTypeLists(
185 Object object1, Object object2, String property,
186 List<DartType> list1, List<DartType> list2) {
187 return areTypeListsEquivalent(list1, list2);
188 }
189
190 bool testConstantLists(
191 Object object1, Object object2, String property,
192 List<ConstantExpression> list1,
193 List<ConstantExpression> list2) {
194 return areConstantListsEquivalent(list1, list2);
195 }
196
197 }
198
199 /// Visitor that checks for equivalence of [Element]s.
200 class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> {
201 final TestStrategy strategy;
202
203 const ElementIdentityEquivalence([this.strategy = const TestStrategy()]);
204
205 bool visit(Element element1, Element element2) {
206 if (element1 == null && element2 == null) {
207 return true;
208 } else if (element1 == null || element2 == null) {
209 return false;
210 }
211 element1 = element1.declaration;
212 element2 = element2.declaration;
213 if (element1 == element2) {
214 return true;
215 }
216 return
217 strategy.test(
218 element1, element2, 'kind',
219 element1.kind, element2.kind) &&
220 element1.accept(this, element2);
221 }
222
223 @override
224 bool visitElement(Element e, Element arg) {
225 throw new UnsupportedError("Unsupported element $e");
226 }
227
228 @override
229 bool visitLibraryElement(LibraryElement element1, LibraryElement element2) {
230 return
231 strategy.test(element1, element2,
232 'canonicalUri',
233 element1.canonicalUri, element2.canonicalUri);
234 }
235
236 @override
237 bool visitCompilationUnitElement(CompilationUnitElement element1,
238 CompilationUnitElement element2) {
239 return
240 strategy.test(element1, element2,
241 'name',
242 element1.name, element2.name) &&
243 visit(element1.library, element2.library);
244 }
245
246 @override
247 bool visitClassElement(ClassElement element1, ClassElement element2) {
248 return
249 strategy.test(element1, element2,
250 'name',
251 element1.name, element2.name) &&
252 visit(element1.library, element2.library);
253 }
254
255 bool checkMembers(Element element1, Element element2) {
256 if (!strategy.test(element1, element2, 'name',
257 element1.name, element2.name)) {
258 return false;
259 }
260 if (element1.enclosingClass != null || element2.enclosingClass != null) {
261 return visit(element1.enclosingClass, element2.enclosingClass);
262 } else {
263 return visit(element1.library, element2.library);
264 }
265 }
266
267 @override
268 bool visitFieldElement(FieldElement element1, FieldElement element2) {
269 return checkMembers(element1, element2);
270 }
271
272 @override
273 bool visitConstructorElement(ConstructorElement element1,
274 ConstructorElement element2) {
275 return checkMembers(element1, element2);
276 }
277
278 @override
279 bool visitMethodElement(MethodElement element1,
280 MethodElement element2) {
281 return checkMembers(element1, element2);
282 }
283
284 @override
285 bool visitGetterElement(GetterElement element1,
286 GetterElement element2) {
287 return checkMembers(element1, element2);
288 }
289
290 @override
291 bool visitSetterElement(SetterElement element1,
292 SetterElement element2) {
293 return checkMembers(element1, element2);
294 }
295
296 @override
297 bool visitLocalFunctionElement(LocalFunctionElement element1,
298 LocalFunctionElement element2) {
299 // TODO(johnniwinther): Define an equivalence on locals.
300 return checkMembers(element1.memberContext, element2.memberContext);
301 }
302
303 bool visitAbstractFieldElement(AbstractFieldElement element1,
304 AbstractFieldElement element2) {
305 return checkMembers(element1, element2);
306 }
307
308 @override
309 bool visitTypeVariableElement(TypeVariableElement element1,
310 TypeVariableElement element2) {
311 return
312 strategy.test(
313 element1, element2, 'name',
314 element1.name, element2.name) &&
315 visit(element1.typeDeclaration, element2.typeDeclaration);
316 }
317
318 @override
319 bool visitTypedefElement(TypedefElement element1, TypedefElement element2) {
320 return
321 strategy.test(
322 element1, element2, 'name',
323 element1.name, element2.name) &&
324 visit(element1.library, element2.library);
325 }
326
327 @override
328 bool visitParameterElement(ParameterElement element1,
329 ParameterElement element2) {
330 return
331 strategy.test(
332 element1, element2, 'name',
333 element1.name, element2.name) &&
334 visit(element1.functionDeclaration, element2.functionDeclaration);
335 }
336
337 @override
338 bool visitImportElement(ImportElement element1, ImportElement element2) {
339 return
340 visit(element1.importedLibrary, element2.importedLibrary) &&
341 visit(element1.library, element2.library);
342 }
343
344 @override
345 bool visitExportElement(ExportElement element1, ExportElement element2) {
346 return
347 visit(element1.exportedLibrary, element2.exportedLibrary) &&
348 visit(element1.library, element2.library);
349 }
350
351 @override
352 bool visitPrefixElement(PrefixElement element1, PrefixElement element2) {
353 return
354 strategy.test(
355 element1, element2, 'name',
356 element1.name, element2.name) &&
357 visit(element1.library, element2.library);
358 }
359 }
360
361
362 /// Visitor that checks for equivalence of [DartType]s.
363 class TypeEquivalence implements DartTypeVisitor<bool, DartType> {
364 final TestStrategy strategy;
365
366 const TypeEquivalence([this.strategy = const TestStrategy()]);
367
368 bool visit(DartType type1, DartType type2) {
369 return
370 strategy.test(type1, type2, 'kind', type1.kind, type2.kind) &&
371 type1.accept(this, type2);
372 }
373
374 @override
375 bool visitDynamicType(DynamicType type, DynamicType other) => true;
376
377 @override
378 bool visitFunctionType(FunctionType type, FunctionType other) {
379 return
380 strategy.testTypeLists(
381 type, other, 'parameterTypes',
382 type.parameterTypes, other.parameterTypes) &&
383 strategy.testTypeLists(
384 type, other, 'optionalParameterTypes',
385 type.optionalParameterTypes, other.optionalParameterTypes) &&
386 strategy.testTypeLists(
387 type, other, 'namedParameterTypes',
388 type.namedParameterTypes, other.namedParameterTypes) &&
389 strategy.testLists(
390 type, other, 'namedParameters',
391 type.namedParameters, other.namedParameters);
392 }
393
394 bool visitGenericType(GenericType type, GenericType other) {
395 return
396 strategy.testElements(
397 type, other, 'element',
398 type.element, other.element) &&
399 strategy.testTypeLists(
400 type, other, 'typeArguments',
401 type.typeArguments, other.typeArguments);
402 }
403
404 @override
405 bool visitMalformedType(MalformedType type, MalformedType other) => true;
406
407 @override
408 bool visitStatementType(StatementType type, StatementType other) {
409 throw new UnsupportedError("Unsupported type: $type");
410 }
411
412 @override
413 bool visitTypeVariableType(TypeVariableType type, TypeVariableType other) {
414 return
415 strategy.testElements(
416 type, other, 'element',
417 type.element, other.element);
418 }
419
420 @override
421 bool visitVoidType(VoidType type, VoidType argument) => true;
422
423 @override
424 bool visitInterfaceType(InterfaceType type, InterfaceType other) {
425 return visitGenericType(type, other);
426 }
427
428 @override
429 bool visitTypedefType(TypedefType type, TypedefType other) {
430 return visitGenericType(type, other);
431 }
432 }
433
434 /// Visitor that checks for structural equivalence of [ConstantExpression]s.
435 class ConstantEquivalence
436 implements ConstantExpressionVisitor<bool, ConstantExpression> {
437 final TestStrategy strategy;
438
439 const ConstantEquivalence([this.strategy = const TestStrategy()]);
440
441 @override
442 bool visit(ConstantExpression exp1, ConstantExpression exp2) {
443 if (identical(exp1, exp2)) return true;
444 return
445 strategy.test(exp1, exp2, 'kind', exp1.kind, exp2.kind) &&
446 exp1.accept(this, exp2);
447 }
448
449 @override
450 bool visitBinary(BinaryConstantExpression exp1,
451 BinaryConstantExpression exp2) {
452 return
453 strategy.test(exp1, exp2, 'operator', exp1.operator, exp2.operator) &&
454 strategy.testConstants(exp1, exp2, 'left', exp1.left, exp2.left) &&
455 strategy.testConstants(exp1, exp2, 'right', exp1.right, exp2.right);
456 }
457
458 @override
459 bool visitConcatenate(ConcatenateConstantExpression exp1,
460 ConcatenateConstantExpression exp2) {
461 return
462 strategy.testConstantLists(
463 exp1, exp2, 'expressions',
464 exp1.expressions, exp2.expressions);
465 }
466
467 @override
468 bool visitConditional(ConditionalConstantExpression exp1,
469 ConditionalConstantExpression exp2) {
470 return
471 strategy.testConstants(
472 exp1, exp2, 'condition', exp1.condition, exp2.condition) &&
473 strategy.testConstants(
474 exp1, exp2, 'trueExp', exp1.trueExp, exp2.trueExp) &&
475 strategy.testConstants(
476 exp1, exp2, 'falseExp', exp1.falseExp, exp2.falseExp);
477 }
478
479 @override
480 bool visitConstructed(ConstructedConstantExpression exp1,
481 ConstructedConstantExpression exp2) {
482 return
483 strategy.testTypes(
484 exp1, exp2, 'type',
485 exp1.type, exp2.type) &&
486 strategy.testElements(
487 exp1, exp2, 'target',
488 exp1.target, exp2.target) &&
489 strategy.testConstantLists(
490 exp1, exp2, 'arguments',
491 exp1.arguments, exp2.arguments) &&
492 strategy.test(exp1, exp2, 'callStructure',
493 exp1.callStructure, exp2.callStructure);
494 }
495
496 @override
497 bool visitFunction(FunctionConstantExpression exp1,
498 FunctionConstantExpression exp2) {
499 return
500 strategy.testElements(
501 exp1, exp2, 'element',
502 exp1.element, exp2.element);
503 }
504
505 @override
506 bool visitIdentical(IdenticalConstantExpression exp1,
507 IdenticalConstantExpression exp2) {
508 return
509 strategy.testConstants(exp1, exp2, 'left', exp1.left, exp2.left) &&
510 strategy.testConstants(exp1, exp2, 'right', exp1.right, exp2.right);
511 }
512
513 @override
514 bool visitList(ListConstantExpression exp1, ListConstantExpression exp2) {
515 return
516 strategy.testTypes(
517 exp1, exp2, 'type',
518 exp1.type, exp2.type) &&
519 strategy.testConstantLists(
520 exp1, exp2, 'values',
521 exp1.values, exp2.values);
522 }
523
524 @override
525 bool visitMap(MapConstantExpression exp1, MapConstantExpression exp2) {
526 return
527 strategy.testTypes(
528 exp1, exp2, 'type',
529 exp1.type, exp2.type) &&
530 strategy.testConstantLists(
531 exp1, exp2, 'keys',
532 exp1.keys, exp2.keys) &&
533 strategy.testConstantLists(
534 exp1, exp2, 'values',
535 exp1.values, exp2.values);
536 }
537
538 @override
539 bool visitNamed(NamedArgumentReference exp1, NamedArgumentReference exp2) {
540 return strategy.test(exp1, exp2, 'name', exp1.name, exp2.name);
541 }
542
543 @override
544 bool visitPositional(PositionalArgumentReference exp1,
545 PositionalArgumentReference exp2) {
546 return strategy.test(exp1, exp2, 'index', exp1.index, exp2.index);
547 }
548
549 @override
550 bool visitSymbol(SymbolConstantExpression exp1,
551 SymbolConstantExpression exp2) {
552 // TODO: implement visitSymbol
553 return true;
554 }
555
556 @override
557 bool visitType(TypeConstantExpression exp1, TypeConstantExpression exp2) {
558 return strategy.testTypes(exp1, exp2, 'type', exp1.type, exp2.type);
559 }
560
561 @override
562 bool visitUnary(UnaryConstantExpression exp1, UnaryConstantExpression exp2) {
563 return
564 strategy.test(exp1, exp2, 'operator', exp1.operator, exp2.operator) &&
565 strategy.testConstants(
566 exp1, exp2, 'expression', exp1.expression, exp2.expression);
567 }
568
569 @override
570 bool visitVariable(VariableConstantExpression exp1,
571 VariableConstantExpression exp2) {
572 return
573 strategy.testElements(
574 exp1, exp2, 'element',
575 exp1.element, exp2.element);
576 }
577
578 @override
579 bool visitBool(BoolConstantExpression exp1, BoolConstantExpression exp2) {
580 return
581 strategy.test(
582 exp1, exp2, 'primitiveValue',
583 exp1.primitiveValue, exp2.primitiveValue);
584 }
585
586 @override
587 bool visitDouble(DoubleConstantExpression exp1,
588 DoubleConstantExpression exp2) {
589 return
590 strategy.test(
591 exp1, exp2, 'primitiveValue',
592 exp1.primitiveValue, exp2.primitiveValue);
593 }
594
595 @override
596 bool visitInt(IntConstantExpression exp1, IntConstantExpression exp2) {
597 return
598 strategy.test(
599 exp1, exp2, 'primitiveValue',
600 exp1.primitiveValue, exp2.primitiveValue);
601 }
602
603 @override
604 bool visitNull(NullConstantExpression exp1, NullConstantExpression exp2) {
605 return true;
606 }
607
608 @override
609 bool visitString(StringConstantExpression exp1,
610 StringConstantExpression exp2) {
611 return
612 strategy.test(
613 exp1, exp2, 'primitiveValue',
614 exp1.primitiveValue, exp2.primitiveValue);
615 }
616
617 @override
618 bool visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp1,
619 BoolFromEnvironmentConstantExpression exp2) {
620 return
621 strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
622 strategy.testConstants(
623 exp1, exp2, 'defaultValue',
624 exp1.defaultValue, exp2.defaultValue);
625 }
626
627 @override
628 bool visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp1,
629 IntFromEnvironmentConstantExpression exp2) {
630 return
631 strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
632 strategy.testConstants(
633 exp1, exp2, 'defaultValue',
634 exp1.defaultValue, exp2.defaultValue);
635 }
636
637 @override
638 bool visitStringFromEnvironment(
639 StringFromEnvironmentConstantExpression exp1,
640 StringFromEnvironmentConstantExpression exp2) {
641 return
642 strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
643 strategy.testConstants(
644 exp1, exp2, 'defaultValue',
645 exp1.defaultValue, exp2.defaultValue);
646 }
647
648 @override
649 bool visitStringLength(StringLengthConstantExpression exp1,
650 StringLengthConstantExpression exp2) {
651 return
652 strategy.testConstants(
653 exp1, exp2, 'expression',
654 exp1.expression, exp2.expression);
655 }
656
657 @override
658 bool visitDeferred(DeferredConstantExpression exp1,
659 DeferredConstantExpression exp2) {
660 // TODO: implement visitDeferred
661 return true;
662 }
663 }
664
665 /// Tests the equivalence of [impact1] and [impact2] using [strategy].
666 bool testResolutionImpactEquivalence(
667 ResolutionImpact impact1,
668 ResolutionImpact impact2,
669 [TestStrategy strategy = const TestStrategy()]) {
670 return
671 strategy.testSets(
672 impact1, impact2, 'constSymbolNames',
673 impact1.constSymbolNames, impact2.constSymbolNames) &&
674 strategy.testSets(
675 impact1, impact2, 'constantLiterals',
676 impact1.constantLiterals, impact2.constantLiterals,
677 areConstantsEquivalent) &&
678 strategy.testSets(
679 impact1, impact2, 'dynamicUses',
680 impact1.dynamicUses, impact2.dynamicUses,
681 areDynamicUsesEquivalent) &&
682 strategy.testSets(
683 impact1, impact2, 'features',
684 impact1.features, impact2.features) &&
685 strategy.testSets(
686 impact1, impact2, 'listLiterals',
687 impact1.listLiterals, impact2.listLiterals,
688 areListLiteralUsesEquivalent) &&
689 strategy.testSets(
690 impact1, impact2, 'mapLiterals',
691 impact1.mapLiterals, impact2.mapLiterals,
692 areMapLiteralUsesEquivalent) &&
693 strategy.testSets(
694 impact1, impact2, 'staticUses',
695 impact1.staticUses, impact2.staticUses,
696 areStaticUsesEquivalent) &&
697 strategy.testSets(
698 impact1, impact2, 'typeUses',
699 impact1.typeUses, impact2.typeUses,
700 areTypeUsesEquivalent);
701 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/elements/visitor.dart ('k') | pkg/compiler/lib/src/serialization/impact_serialization.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698