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

Side by Side Diff: tests/compiler/dart2js/equivalence/check_helpers.dart

Issue 2879593004: Reorganize equivalence test helpers (Closed)
Patch Set: Created 3 years, 7 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
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 library dart2js.serialization_test_helper; 5 /// General equivalence test functions.
6 6
7 import 'dart:collection'; 7 library dart2js.equivalence.helpers;
8 import 'package:compiler/src/common/resolution.dart'; 8
9 import 'package:compiler/src/constants/expressions.dart'; 9 import 'package:compiler/src/constants/expressions.dart';
10 import 'package:compiler/src/constants/values.dart'; 10 import 'package:compiler/src/constants/values.dart';
11 import 'package:compiler/src/compiler.dart';
12 import 'package:compiler/src/elements/elements.dart'; 11 import 'package:compiler/src/elements/elements.dart';
13 import 'package:compiler/src/elements/entities.dart'; 12 import 'package:compiler/src/elements/entities.dart';
14 import 'package:compiler/src/elements/resolution_types.dart'; 13 import 'package:compiler/src/elements/resolution_types.dart';
15 import 'package:compiler/src/elements/types.dart'; 14 import 'package:compiler/src/elements/types.dart';
16 import 'package:compiler/src/kernel/elements.dart';
17 import 'package:compiler/src/kernel/element_map_impl.dart';
18 import 'package:compiler/src/serialization/equivalence.dart'; 15 import 'package:compiler/src/serialization/equivalence.dart';
19 import 'package:compiler/src/util/util.dart';
20 import 'package:expect/expect.dart'; 16 import 'package:expect/expect.dart';
21 import 'test_data.dart';
22 17
23 Check currentCheck; 18 Check currentCheck;
24 19
25 class Check { 20 class Check {
26 final Check parent; 21 final Check parent;
27 final Object object1; 22 final Object object1;
28 final Object object2; 23 final Object object2;
29 final String property; 24 final String property;
30 final Object value1; 25 final Object value1;
31 final Object value2; 26 final Object value2;
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 /// Checks the pair-wise equivalence of the constants values in [list1] and 334 /// Checks the pair-wise equivalence of the constants values in [list1] and
340 /// [list2]. 335 /// [list2].
341 /// 336 ///
342 /// Uses [object1], [object2] and [property] to provide context for failures. 337 /// Uses [object1], [object2] and [property] to provide context for failures.
343 bool checkConstantValueLists(Object object1, Object object2, String property, 338 bool checkConstantValueLists(Object object1, Object object2, String property,
344 List<ConstantValue> list1, List<ConstantValue> list2) { 339 List<ConstantValue> list1, List<ConstantValue> list2) {
345 return checkListEquivalence( 340 return checkListEquivalence(
346 object1, object2, property, list1, list2, checkConstantValues); 341 object1, object2, property, list1, list2, checkConstantValues);
347 } 342 }
348 343
349 /// Check member property equivalence between all members common to [compiler1]
350 /// and [compiler2].
351 void checkLoadedLibraryMembers(
352 Compiler compiler1,
353 Compiler compiler2,
354 bool hasProperty(Element member1),
355 void checkMemberProperties(Compiler compiler1, Element member1,
356 Compiler compiler2, Element member2,
357 {bool verbose}),
358 {bool verbose: false}) {
359 void checkMembers(Element member1, Element member2) {
360 if (member1.isClass && member2.isClass) {
361 ClassElement class1 = member1;
362 ClassElement class2 = member2;
363 if (!class1.isResolved) return;
364
365 if (hasProperty(member1)) {
366 if (areElementsEquivalent(member1, member2)) {
367 checkMemberProperties(compiler1, member1, compiler2, member2,
368 verbose: verbose);
369 }
370 }
371
372 class1.forEachLocalMember((m1) {
373 checkMembers(m1, class2.localLookup(m1.name));
374 });
375 ClassElement superclass1 = class1.superclass;
376 ClassElement superclass2 = class2.superclass;
377 while (superclass1 != null && superclass1.isUnnamedMixinApplication) {
378 for (ConstructorElement c1 in superclass1.constructors) {
379 checkMembers(c1, superclass2.lookupConstructor(c1.name));
380 }
381 superclass1 = superclass1.superclass;
382 superclass2 = superclass2.superclass;
383 }
384 return;
385 }
386
387 if (!hasProperty(member1)) {
388 return;
389 }
390
391 if (member2 == null) {
392 throw 'Missing member for ${member1}';
393 }
394
395 if (areElementsEquivalent(member1, member2)) {
396 checkMemberProperties(compiler1, member1, compiler2, member2,
397 verbose: verbose);
398 }
399 }
400
401 for (LibraryElement library1 in compiler1.libraryLoader.libraries) {
402 LibraryElement library2 =
403 compiler2.libraryLoader.lookupLibrary(library1.canonicalUri);
404 if (library2 != null) {
405 library1.forEachLocalMember((Element member1) {
406 checkMembers(member1, library2.localLookup(member1.name));
407 });
408 }
409 }
410 }
411
412 /// Check equivalence of all resolution impacts.
413 void checkAllImpacts(Compiler compiler1, Compiler compiler2,
414 {bool verbose: false}) {
415 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
416 return compiler1.resolution.hasResolutionImpact(member1);
417 }, checkImpacts, verbose: verbose);
418 }
419
420 /// Check equivalence of resolution impact for [member1] and [member2].
421 void checkImpacts(
422 Compiler compiler1, Element member1, Compiler compiler2, Element member2,
423 {bool verbose: false}) {
424 ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
425 ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2);
426
427 if (impact1 == null && impact2 == null) return;
428
429 if (verbose) {
430 print('Checking impacts for $member1 vs $member2');
431 }
432
433 if (impact1 == null) {
434 throw 'Missing impact for $member1. $member2 has $impact2';
435 }
436 if (impact2 == null) {
437 throw 'Missing impact for $member2. $member1 has $impact1';
438 }
439
440 testResolutionImpactEquivalence(impact1, impact2,
441 strategy: const CheckStrategy());
442 }
443
444 void checkSets( 344 void checkSets(
445 Iterable set1, Iterable set2, String messagePrefix, bool sameElement(a, b), 345 Iterable set1, Iterable set2, String messagePrefix, bool sameElement(a, b),
446 {bool failOnUnfound: true, 346 {bool failOnUnfound: true,
447 bool failOnExtra: true, 347 bool failOnExtra: true,
448 bool verbose: false, 348 bool verbose: false,
449 void onSameElement(a, b), 349 void onSameElement(a, b),
450 void onUnfoundElement(a), 350 void onUnfoundElement(a),
451 void onExtraElement(b), 351 void onExtraElement(b),
452 bool elementFilter(element), 352 bool elementFilter(element),
453 elementConverter(element), 353 elementConverter(element),
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 (mismatch.isNotEmpty && failOnMismatch) || 470 (mismatch.isNotEmpty && failOnMismatch) ||
571 remaining.isNotEmpty) { 471 remaining.isNotEmpty) {
572 Expect.fail(message); 472 Expect.fail(message);
573 } else { 473 } else {
574 print(message); 474 print(message);
575 } 475 }
576 } else if (verbose) { 476 } else if (verbose) {
577 print(message); 477 print(message);
578 } 478 }
579 } 479 }
580
581 void checkAllResolvedAsts(Compiler compiler1, Compiler compiler2,
582 {bool verbose: false}) {
583 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
584 return member1 is ExecutableElement &&
585 compiler1.resolution.hasResolvedAst(member1);
586 }, checkResolvedAsts, verbose: verbose);
587 }
588
589 /// Check equivalence of [impact1] and [impact2].
590 void checkResolvedAsts(
591 Compiler compiler1, Element member1, Compiler compiler2, Element member2,
592 {bool verbose: false}) {
593 if (!compiler2.serialization.isDeserialized(member2)) {
594 return;
595 }
596 ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
597 ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2);
598
599 if (resolvedAst1 == null || resolvedAst2 == null) return;
600
601 if (verbose) {
602 print('Checking resolved asts for $member1 vs $member2');
603 }
604
605 testResolvedAstEquivalence(resolvedAst1, resolvedAst2, const CheckStrategy());
606 }
607
608 /// Returns the test arguments for testing the [index]th skipped test. The
609 /// [skip] count is used to check that [index] is a valid index.
610 List<String> testSkipped(int index, int skip) {
611 if (index < 0 || index >= skip) {
612 throw new ArgumentError('Invalid skip index $index');
613 }
614 return ['${index}', '${index + 1}'];
615 }
616
617 /// Return the test arguments for testing the [index]th segment (1-based) of
618 /// the [TESTS] split into [count] groups. The first [skip] tests are excluded
619 /// from the automatic grouping.
620 List<String> testSegment(int index, int count, int skip) {
621 if (index < 0 || index > count) {
622 throw new ArgumentError('Invalid segment index $index');
623 }
624
625 String segmentNumber(int i) {
626 return '${skip + i * (TESTS.length - skip) ~/ count}';
627 }
628
629 if (index == 1 && skip != 0) {
630 return ['${skip}', segmentNumber(index)];
631 } else if (index == count) {
632 return [segmentNumber(index - 1)];
633 } else {
634 return [segmentNumber(index - 1), segmentNumber(index)];
635 }
636 }
637
638 class KernelEquivalence {
639 final WorldDeconstructionForTesting testing;
640
641 /// Set of mixin applications assumed to be equivalent.
642 ///
643 /// We need co-inductive reasoning because mixin applications are compared
644 /// structurally and therefore, in the case of generic mixin applications,
645 /// meet themselves through the equivalence check of their type variables.
646 Set<Pair<ClassEntity, ClassEntity>> assumedMixinApplications =
647 new Set<Pair<ClassEntity, ClassEntity>>();
648
649 KernelEquivalence(KernelToElementMapImpl builder)
650 : testing = new WorldDeconstructionForTesting(builder);
651
652 TestStrategy get defaultStrategy => new TestStrategy(
653 elementEquivalence: entityEquivalence,
654 typeEquivalence: typeEquivalence,
655 constantEquivalence: constantEquivalence,
656 constantValueEquivalence: constantValueEquivalence);
657
658 bool entityEquivalence(Element a, Entity b, {TestStrategy strategy}) {
659 if (identical(a, b)) return true;
660 if (a == null || b == null) return false;
661 strategy ??= defaultStrategy;
662 switch (a.kind) {
663 case ElementKind.GENERATIVE_CONSTRUCTOR:
664 if (b is KGenerativeConstructor) {
665 return strategy.test(a, b, 'name', a.name, b.name) &&
666 strategy.testElements(
667 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
668 }
669 return false;
670 case ElementKind.FACTORY_CONSTRUCTOR:
671 if (b is KFactoryConstructor) {
672 return strategy.test(a, b, 'name', a.name, b.name) &&
673 strategy.testElements(
674 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
675 }
676 return false;
677 case ElementKind.CLASS:
678 if (b is KClass) {
679 List<InterfaceType> aMixinTypes = [];
680 List<InterfaceType> bMixinTypes = [];
681 ClassElement aClass = a;
682 if (aClass.isUnnamedMixinApplication) {
683 if (!testing.isUnnamedMixinApplication(b)) {
684 return false;
685 }
686 while (aClass.isMixinApplication) {
687 MixinApplicationElement aMixinApplication = aClass;
688 aMixinTypes.add(aMixinApplication.mixinType);
689 aClass = aMixinApplication.superclass;
690 }
691 KClass bClass = b;
692 while (bClass != null) {
693 InterfaceType mixinType = testing.getMixinTypeForClass(bClass);
694 if (mixinType == null) break;
695 bMixinTypes.add(mixinType);
696 bClass = testing.getSuperclassForClass(bClass);
697 }
698 if (aMixinTypes.isNotEmpty || aMixinTypes.isNotEmpty) {
699 Pair<ClassEntity, ClassEntity> pair =
700 new Pair<ClassEntity, ClassEntity>(aClass, bClass);
701 if (assumedMixinApplications.contains(pair)) {
702 return true;
703 } else {
704 assumedMixinApplications.add(pair);
705 bool result = strategy.testTypeLists(
706 a, b, 'mixinTypes', aMixinTypes, bMixinTypes);
707 assumedMixinApplications.remove(pair);
708 return result;
709 }
710 }
711 } else {
712 if (testing.isUnnamedMixinApplication(b)) {
713 return false;
714 }
715 }
716 return strategy.test(a, b, 'name', a.name, b.name) &&
717 strategy.testElements(a, b, 'library', a.library, b.library);
718 }
719 return false;
720 case ElementKind.LIBRARY:
721 if (b is KLibrary) {
722 LibraryElement libraryA = a;
723 return libraryA.canonicalUri == b.canonicalUri;
724 }
725 return false;
726 case ElementKind.FUNCTION:
727 if (b is KMethod) {
728 return strategy.test(a, b, 'name', a.name, b.name) &&
729 strategy.testElements(
730 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
731 strategy.testElements(a, b, 'library', a.library, b.library);
732 } else if (b is KLocalFunction) {
733 LocalFunctionElement aLocalFunction = a;
734 return strategy.test(a, b, 'name', a.name, b.name ?? '') &&
735 strategy.testElements(a, b, 'executableContext',
736 aLocalFunction.executableContext, b.executableContext) &&
737 strategy.testElements(a, b, 'memberContext',
738 aLocalFunction.memberContext, b.memberContext);
739 }
740 return false;
741 case ElementKind.GETTER:
742 if (b is KGetter) {
743 return strategy.test(a, b, 'name', a.name, b.name) &&
744 strategy.testElements(
745 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
746 strategy.testElements(a, b, 'library', a.library, b.library);
747 }
748 return false;
749 case ElementKind.SETTER:
750 if (b is KSetter) {
751 return strategy.test(a, b, 'name', a.name, b.name) &&
752 strategy.testElements(
753 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
754 strategy.testElements(a, b, 'library', a.library, b.library);
755 }
756 return false;
757 case ElementKind.FIELD:
758 if (b is KField) {
759 return strategy.test(a, b, 'name', a.name, b.name) &&
760 strategy.testElements(
761 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
762 strategy.testElements(a, b, 'library', a.library, b.library);
763 }
764 return false;
765 case ElementKind.TYPE_VARIABLE:
766 if (b is KTypeVariable) {
767 TypeVariableElement aElement = a;
768 return strategy.test(a, b, 'index', aElement.index, b.index) &&
769 strategy.testElements(a, b, 'typeDeclaration',
770 aElement.typeDeclaration, b.typeDeclaration);
771 }
772 return false;
773 default:
774 throw new UnsupportedError('Unsupported equivalence: '
775 '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
776 }
777 }
778
779 bool typeEquivalence(ResolutionDartType a, DartType b,
780 {TestStrategy strategy}) {
781 if (identical(a, b)) return true;
782 if (a == null || b == null) return false;
783 strategy ??= defaultStrategy;
784 switch (a.kind) {
785 case ResolutionTypeKind.DYNAMIC:
786 return b is DynamicType;
787 case ResolutionTypeKind.VOID:
788 return b is VoidType;
789 case ResolutionTypeKind.INTERFACE:
790 if (b is InterfaceType) {
791 ResolutionInterfaceType aType = a;
792 return strategy.testElements(a, b, 'element', a.element, b.element) &&
793 strategy.testTypeLists(
794 a, b, 'typeArguments', aType.typeArguments, b.typeArguments);
795 }
796 return false;
797 case ResolutionTypeKind.TYPE_VARIABLE:
798 if (b is TypeVariableType) {
799 return strategy.testElements(a, b, 'element', a.element, b.element);
800 }
801 return false;
802 case ResolutionTypeKind.FUNCTION:
803 if (b is FunctionType) {
804 ResolutionFunctionType aType = a;
805 return strategy.testTypes(
806 a, b, 'returnType', aType.returnType, b.returnType) &&
807 strategy.testTypeLists(a, b, 'parameterTypes',
808 aType.parameterTypes, b.parameterTypes) &&
809 strategy.testTypeLists(a, b, 'optionalParameterTypes',
810 aType.optionalParameterTypes, b.optionalParameterTypes) &&
811 strategy.testLists(a, b, 'namedParameters', aType.namedParameters,
812 b.namedParameters) &&
813 strategy.testTypeLists(a, b, 'namedParameterTypes',
814 aType.namedParameterTypes, b.namedParameterTypes);
815 }
816 return false;
817 default:
818 throw new UnsupportedError('Unsupported equivalence: '
819 '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
820 }
821 }
822
823 bool constantEquivalence(ConstantExpression exp1, ConstantExpression exp2,
824 {TestStrategy strategy}) {
825 strategy ??= defaultStrategy;
826 return areConstantsEquivalent(exp1, exp2, strategy: strategy);
827 }
828
829 bool constantValueEquivalence(ConstantValue value1, ConstantValue value2,
830 {TestStrategy strategy}) {
831 strategy ??= defaultStrategy;
832 return areConstantValuesEquivalent(value1, value2, strategy: strategy);
833 }
834 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698