| Index: tests/compiler/dart2js/equivalence/check_functions.dart
|
| diff --git a/tests/compiler/dart2js/equivalence/check_functions.dart b/tests/compiler/dart2js/equivalence/check_functions.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4f82bde0ff62a82929215ac5616a924934a7047a
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js/equivalence/check_functions.dart
|
| @@ -0,0 +1,612 @@
|
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +/// Equivalence test functions for data objects.
|
| +
|
| +library dart2js.equivalence.functions;
|
| +
|
| +import 'package:expect/expect.dart';
|
| +import 'package:compiler/src/common/resolution.dart';
|
| +import 'package:compiler/src/common_elements.dart';
|
| +import 'package:compiler/src/compiler.dart';
|
| +import 'package:compiler/src/elements/types.dart';
|
| +import 'package:compiler/src/elements/elements.dart';
|
| +import 'package:compiler/src/elements/entities.dart';
|
| +import 'package:compiler/src/enqueue.dart';
|
| +import 'package:compiler/src/js_backend/backend_usage.dart';
|
| +import 'package:compiler/src/js_backend/native_data.dart';
|
| +import 'package:compiler/src/js_backend/interceptor_data.dart';
|
| +import 'package:compiler/src/serialization/equivalence.dart';
|
| +import 'package:compiler/src/universe/class_set.dart';
|
| +import 'package:compiler/src/universe/world_builder.dart';
|
| +import 'package:compiler/src/world.dart';
|
| +import 'check_helpers.dart';
|
| +
|
| +void checkClosedWorlds(ClosedWorld closedWorld1, ClosedWorld closedWorld2,
|
| + {TestStrategy strategy: const TestStrategy(),
|
| + bool allowExtra: false,
|
| + bool verbose: false}) {
|
| + if (verbose) {
|
| + print(closedWorld1.dump());
|
| + print(closedWorld2.dump());
|
| + }
|
| + checkClassHierarchyNodes(
|
| + closedWorld1,
|
| + closedWorld2,
|
| + closedWorld1
|
| + .getClassHierarchyNode(closedWorld1.commonElements.objectClass),
|
| + closedWorld2
|
| + .getClassHierarchyNode(closedWorld2.commonElements.objectClass),
|
| + strategy.elementEquivalence,
|
| + verbose: verbose);
|
| +
|
| + checkNativeData(closedWorld1.nativeData, closedWorld2.nativeData,
|
| + strategy: strategy, allowExtra: allowExtra, verbose: verbose);
|
| + checkInterceptorData(closedWorld1.interceptorData,
|
| + closedWorld2.interceptorData, strategy.elementEquivalence,
|
| + verbose: verbose);
|
| +}
|
| +
|
| +void checkNativeData(NativeDataImpl data1, NativeDataImpl data2,
|
| + {TestStrategy strategy: const TestStrategy(),
|
| + bool allowExtra: false,
|
| + bool verbose: false}) {
|
| + checkMapEquivalence(data1, data2, 'nativeMemberName', data1.nativeMemberName,
|
| + data2.nativeMemberName, strategy.elementEquivalence, equality,
|
| + allowExtra: allowExtra);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'nativeMethodBehavior',
|
| + data1.nativeMethodBehavior,
|
| + data2.nativeMethodBehavior,
|
| + strategy.elementEquivalence,
|
| + (a, b) => testNativeBehavior(a, b, strategy: strategy),
|
| + allowExtra: allowExtra);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'nativeFieldLoadBehavior',
|
| + data1.nativeFieldLoadBehavior,
|
| + data2.nativeFieldLoadBehavior,
|
| + strategy.elementEquivalence,
|
| + (a, b) => testNativeBehavior(a, b, strategy: strategy),
|
| + allowExtra: allowExtra);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'nativeFieldStoreBehavior',
|
| + data1.nativeFieldStoreBehavior,
|
| + data2.nativeFieldStoreBehavior,
|
| + strategy.elementEquivalence,
|
| + (a, b) => testNativeBehavior(a, b, strategy: strategy),
|
| + allowExtra: allowExtra);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'jsInteropLibraryNames',
|
| + data1.jsInteropLibraryNames,
|
| + data2.jsInteropLibraryNames,
|
| + strategy.elementEquivalence,
|
| + equality);
|
| +
|
| + checkSetEquivalence(
|
| + data1,
|
| + data2,
|
| + 'anonymousJsInteropClasses',
|
| + data1.anonymousJsInteropClasses,
|
| + data2.anonymousJsInteropClasses,
|
| + strategy.elementEquivalence);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'jsInteropClassNames',
|
| + data1.jsInteropClassNames,
|
| + data2.jsInteropClassNames,
|
| + strategy.elementEquivalence,
|
| + equality);
|
| +
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'jsInteropMemberNames',
|
| + data1.jsInteropMemberNames,
|
| + data2.jsInteropMemberNames,
|
| + strategy.elementEquivalence,
|
| + equality);
|
| +}
|
| +
|
| +void checkInterceptorData(InterceptorDataImpl data1, InterceptorDataImpl data2,
|
| + bool elementEquivalence(Entity a, Entity b),
|
| + {bool verbose: false}) {
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'interceptedElements',
|
| + data1.interceptedElementsForTesting,
|
| + data2.interceptedElementsForTesting,
|
| + equality,
|
| + (a, b) => areSetsEquivalent(a, b, elementEquivalence));
|
| +
|
| + checkSetEquivalence(data1, data2, 'interceptedClasses',
|
| + data1.interceptedClasses, data2.interceptedClasses, elementEquivalence);
|
| +
|
| + checkSetEquivalence(
|
| + data1,
|
| + data2,
|
| + 'classesMixedIntoInterceptedClasses',
|
| + data1.classesMixedIntoInterceptedClassesForTesting,
|
| + data2.classesMixedIntoInterceptedClassesForTesting,
|
| + elementEquivalence);
|
| +}
|
| +
|
| +void checkClassHierarchyNodes(
|
| + ClosedWorld closedWorld1,
|
| + ClosedWorld closedWorld2,
|
| + ClassHierarchyNode node1,
|
| + ClassHierarchyNode node2,
|
| + bool elementEquivalence(Entity a, Entity b),
|
| + {bool verbose: false}) {
|
| + if (verbose) {
|
| + print('Checking $node1 vs $node2');
|
| + }
|
| + ClassEntity cls1 = node1.cls;
|
| + ClassEntity cls2 = node2.cls;
|
| + Expect.isTrue(elementEquivalence(cls1, cls2),
|
| + "Element identity mismatch for ${cls1} vs ${cls2}.");
|
| + Expect.equals(
|
| + node1.isDirectlyInstantiated,
|
| + node2.isDirectlyInstantiated,
|
| + "Value mismatch for 'isDirectlyInstantiated' "
|
| + "for ${cls1} vs ${cls2}.");
|
| + Expect.equals(
|
| + node1.isIndirectlyInstantiated,
|
| + node2.isIndirectlyInstantiated,
|
| + "Value mismatch for 'isIndirectlyInstantiated' "
|
| + "for ${node1.cls} vs ${node2.cls}.");
|
| + // TODO(johnniwinther): Enforce a canonical and stable order on direct
|
| + // subclasses.
|
| + for (ClassHierarchyNode child in node1.directSubclasses) {
|
| + bool found = false;
|
| + for (ClassHierarchyNode other in node2.directSubclasses) {
|
| + ClassEntity child1 = child.cls;
|
| + ClassEntity child2 = other.cls;
|
| + if (elementEquivalence(child1, child2)) {
|
| + checkClassHierarchyNodes(
|
| + closedWorld1, closedWorld2, child, other, elementEquivalence,
|
| + verbose: verbose);
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!found) {
|
| + if (child.isInstantiated) {
|
| + print('Missing subclass ${child.cls} of ${node1.cls} '
|
| + 'in ${node2.directSubclasses}');
|
| + print(closedWorld1.dump(
|
| + verbose ? closedWorld1.commonElements.objectClass : node1.cls));
|
| + print(closedWorld2.dump(
|
| + verbose ? closedWorld2.commonElements.objectClass : node2.cls));
|
| + }
|
| + Expect.isFalse(
|
| + child.isInstantiated,
|
| + 'Missing subclass ${child.cls} of ${node1.cls} in '
|
| + '${node2.directSubclasses}');
|
| + }
|
| + }
|
| + checkMixinUses(
|
| + closedWorld1, closedWorld2, node1.cls, node2.cls, elementEquivalence,
|
| + verbose: verbose);
|
| +}
|
| +
|
| +void checkMixinUses(
|
| + ClosedWorld closedWorld1,
|
| + ClosedWorld closedWorld2,
|
| + ClassEntity class1,
|
| + ClassEntity class2,
|
| + bool elementEquivalence(Entity a, Entity b),
|
| + {bool verbose: false}) {
|
| + checkSets(closedWorld1.mixinUsesOf(class1), closedWorld2.mixinUsesOf(class2),
|
| + "Mixin uses of $class1 vs $class2", elementEquivalence,
|
| + verbose: verbose);
|
| +}
|
| +
|
| +/// Check member property equivalence between all members common to [compiler1]
|
| +/// and [compiler2].
|
| +void checkLoadedLibraryMembers(
|
| + Compiler compiler1,
|
| + Compiler compiler2,
|
| + bool hasProperty(Element member1),
|
| + void checkMemberProperties(Compiler compiler1, Element member1,
|
| + Compiler compiler2, Element member2,
|
| + {bool verbose}),
|
| + {bool verbose: false}) {
|
| + void checkMembers(Element member1, Element member2) {
|
| + if (member1.isClass && member2.isClass) {
|
| + ClassElement class1 = member1;
|
| + ClassElement class2 = member2;
|
| + if (!class1.isResolved) return;
|
| +
|
| + if (hasProperty(member1)) {
|
| + if (areElementsEquivalent(member1, member2)) {
|
| + checkMemberProperties(compiler1, member1, compiler2, member2,
|
| + verbose: verbose);
|
| + }
|
| + }
|
| +
|
| + class1.forEachLocalMember((m1) {
|
| + checkMembers(m1, class2.localLookup(m1.name));
|
| + });
|
| + ClassElement superclass1 = class1.superclass;
|
| + ClassElement superclass2 = class2.superclass;
|
| + while (superclass1 != null && superclass1.isUnnamedMixinApplication) {
|
| + for (ConstructorElement c1 in superclass1.constructors) {
|
| + checkMembers(c1, superclass2.lookupConstructor(c1.name));
|
| + }
|
| + superclass1 = superclass1.superclass;
|
| + superclass2 = superclass2.superclass;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + if (!hasProperty(member1)) {
|
| + return;
|
| + }
|
| +
|
| + if (member2 == null) {
|
| + throw 'Missing member for ${member1}';
|
| + }
|
| +
|
| + if (areElementsEquivalent(member1, member2)) {
|
| + checkMemberProperties(compiler1, member1, compiler2, member2,
|
| + verbose: verbose);
|
| + }
|
| + }
|
| +
|
| + for (LibraryElement library1 in compiler1.libraryLoader.libraries) {
|
| + LibraryElement library2 =
|
| + compiler2.libraryLoader.lookupLibrary(library1.canonicalUri);
|
| + if (library2 != null) {
|
| + library1.forEachLocalMember((Element member1) {
|
| + checkMembers(member1, library2.localLookup(member1.name));
|
| + });
|
| + }
|
| + }
|
| +}
|
| +
|
| +/// Check equivalence of all resolution impacts.
|
| +void checkAllImpacts(Compiler compiler1, Compiler compiler2,
|
| + {bool verbose: false}) {
|
| + checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
|
| + return compiler1.resolution.hasResolutionImpact(member1);
|
| + }, checkImpacts, verbose: verbose);
|
| +}
|
| +
|
| +/// Check equivalence of resolution impact for [member1] and [member2].
|
| +void checkImpacts(
|
| + Compiler compiler1, Element member1, Compiler compiler2, Element member2,
|
| + {bool verbose: false}) {
|
| + ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
|
| + ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2);
|
| +
|
| + if (impact1 == null && impact2 == null) return;
|
| +
|
| + if (verbose) {
|
| + print('Checking impacts for $member1 vs $member2');
|
| + }
|
| +
|
| + if (impact1 == null) {
|
| + throw 'Missing impact for $member1. $member2 has $impact2';
|
| + }
|
| + if (impact2 == null) {
|
| + throw 'Missing impact for $member2. $member1 has $impact1';
|
| + }
|
| +
|
| + testResolutionImpactEquivalence(impact1, impact2,
|
| + strategy: const CheckStrategy());
|
| +}
|
| +
|
| +void checkAllResolvedAsts(Compiler compiler1, Compiler compiler2,
|
| + {bool verbose: false}) {
|
| + checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
|
| + return member1 is ExecutableElement &&
|
| + compiler1.resolution.hasResolvedAst(member1);
|
| + }, checkResolvedAsts, verbose: verbose);
|
| +}
|
| +
|
| +/// Check equivalence of [impact1] and [impact2].
|
| +void checkResolvedAsts(
|
| + Compiler compiler1, Element member1, Compiler compiler2, Element member2,
|
| + {bool verbose: false}) {
|
| + if (!compiler2.serialization.isDeserialized(member2)) {
|
| + return;
|
| + }
|
| + ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
|
| + ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2);
|
| +
|
| + if (resolvedAst1 == null || resolvedAst2 == null) return;
|
| +
|
| + if (verbose) {
|
| + print('Checking resolved asts for $member1 vs $member2');
|
| + }
|
| +
|
| + testResolvedAstEquivalence(resolvedAst1, resolvedAst2, const CheckStrategy());
|
| +}
|
| +
|
| +void checkNativeClasses(
|
| + Compiler compiler1, Compiler compiler2, TestStrategy strategy) {
|
| + Iterable<ClassEntity> nativeClasses1 = compiler1
|
| + .backend.nativeResolutionEnqueuerForTesting.nativeClassesForTesting;
|
| + Iterable<ClassEntity> nativeClasses2 = compiler2
|
| + .backend.nativeResolutionEnqueuerForTesting.nativeClassesForTesting;
|
| +
|
| + checkSetEquivalence(compiler1, compiler2, 'nativeClasses', nativeClasses1,
|
| + nativeClasses2, strategy.elementEquivalence);
|
| +
|
| + Iterable<ClassEntity> registeredClasses1 = compiler1
|
| + .backend.nativeResolutionEnqueuerForTesting.registeredClassesForTesting;
|
| + Iterable<ClassEntity> registeredClasses2 = compiler2
|
| + .backend.nativeResolutionEnqueuerForTesting.registeredClassesForTesting;
|
| +
|
| + checkSetEquivalence(compiler1, compiler2, 'registeredClasses',
|
| + registeredClasses1, registeredClasses2, strategy.elementEquivalence);
|
| +}
|
| +
|
| +void checkNativeBasicData(NativeBasicDataImpl data1, NativeBasicDataImpl data2,
|
| + TestStrategy strategy) {
|
| + checkMapEquivalence(
|
| + data1,
|
| + data2,
|
| + 'nativeClassTagInfo',
|
| + data1.nativeClassTagInfo,
|
| + data2.nativeClassTagInfo,
|
| + strategy.elementEquivalence,
|
| + (a, b) => a == b);
|
| + // TODO(johnniwinther): Check the remaining properties.
|
| +}
|
| +
|
| +void checkBackendUsage(
|
| + BackendUsageImpl usage1, BackendUsageImpl usage2, TestStrategy strategy) {
|
| + checkSetEquivalence(
|
| + usage1,
|
| + usage2,
|
| + 'globalClassDependencies',
|
| + usage1.globalClassDependencies,
|
| + usage2.globalClassDependencies,
|
| + strategy.elementEquivalence);
|
| + checkSetEquivalence(
|
| + usage1,
|
| + usage2,
|
| + 'globalFunctionDependencies',
|
| + usage1.globalFunctionDependencies,
|
| + usage2.globalFunctionDependencies,
|
| + strategy.elementEquivalence);
|
| + checkSetEquivalence(
|
| + usage1,
|
| + usage2,
|
| + 'helperClassesUsed',
|
| + usage1.helperClassesUsed,
|
| + usage2.helperClassesUsed,
|
| + strategy.elementEquivalence);
|
| + checkSetEquivalence(
|
| + usage1,
|
| + usage2,
|
| + 'helperFunctionsUsed',
|
| + usage1.helperFunctionsUsed,
|
| + usage2.helperFunctionsUsed,
|
| + strategy.elementEquivalence);
|
| + check(
|
| + usage1,
|
| + usage2,
|
| + 'needToInitializeIsolateAffinityTag',
|
| + usage1.needToInitializeIsolateAffinityTag,
|
| + usage2.needToInitializeIsolateAffinityTag);
|
| + check(
|
| + usage1,
|
| + usage2,
|
| + 'needToInitializeDispatchProperty',
|
| + usage1.needToInitializeDispatchProperty,
|
| + usage2.needToInitializeDispatchProperty);
|
| + check(usage1, usage2, 'requiresPreamble', usage1.requiresPreamble,
|
| + usage2.requiresPreamble);
|
| + check(usage1, usage2, 'isInvokeOnUsed', usage1.isInvokeOnUsed,
|
| + usage2.isInvokeOnUsed);
|
| + check(usage1, usage2, 'isRuntimeTypeUsed', usage1.isRuntimeTypeUsed,
|
| + usage2.isRuntimeTypeUsed);
|
| + check(usage1, usage2, 'isIsolateInUse', usage1.isIsolateInUse,
|
| + usage2.isIsolateInUse);
|
| + check(usage1, usage2, 'isFunctionApplyUsed', usage1.isFunctionApplyUsed,
|
| + usage2.isFunctionApplyUsed);
|
| + check(usage1, usage2, 'isNoSuchMethodUsed', usage1.isNoSuchMethodUsed,
|
| + usage2.isNoSuchMethodUsed);
|
| +}
|
| +
|
| +checkElementEnvironment(
|
| + ElementEnvironment env1, ElementEnvironment env2, TestStrategy strategy) {
|
| + checkMembers(MemberEntity member1, MemberEntity member2) {
|
| + Expect.equals(env1.isDeferredLoadLibraryGetter(member1),
|
| + env2.isDeferredLoadLibraryGetter(member2));
|
| +
|
| + checkListEquivalence(
|
| + member1,
|
| + member2,
|
| + 'metadata',
|
| + env1.getMemberMetadata(member1),
|
| + env2.getMemberMetadata(member2),
|
| + strategy.testConstantValues);
|
| + }
|
| +
|
| + checkSetEquivalence(env1, env2, 'libraries', env1.libraries, env2.libraries,
|
| + strategy.elementEquivalence,
|
| + onSameElement: (LibraryEntity lib1, LibraryEntity lib2) {
|
| + Expect.identical(lib1, env1.lookupLibrary(lib1.canonicalUri));
|
| + Expect.identical(lib2, env2.lookupLibrary(lib2.canonicalUri));
|
| +
|
| + List<ClassEntity> classes2 = <ClassEntity>[];
|
| + env1.forEachClass(lib1, (ClassEntity cls1) {
|
| + Expect.identical(cls1, env1.lookupClass(lib1, cls1.name));
|
| +
|
| + String className = cls1.name;
|
| + ClassEntity cls2 = env2.lookupClass(lib2, className);
|
| + Expect.isNotNull(cls2, 'Missing class $className in $lib2');
|
| + Expect.identical(cls2, env2.lookupClass(lib2, cls2.name));
|
| +
|
| + check(lib1, lib2, 'class:${className}', cls1, cls2,
|
| + strategy.elementEquivalence);
|
| +
|
| + Expect.equals(env1.isGenericClass(cls1), env2.isGenericClass(cls2));
|
| +
|
| + check(
|
| + cls1,
|
| + cls2,
|
| + 'superclass',
|
| + env1.getSuperClass(cls1, skipUnnamedMixinApplications: false),
|
| + env2.getSuperClass(cls2, skipUnnamedMixinApplications: false),
|
| + strategy.elementEquivalence);
|
| + check(
|
| + cls1,
|
| + cls2,
|
| + 'superclass',
|
| + env1.getSuperClass(cls1, skipUnnamedMixinApplications: true),
|
| + env2.getSuperClass(cls2, skipUnnamedMixinApplications: true),
|
| + strategy.elementEquivalence);
|
| +
|
| + List<InterfaceType> supertypes1 = <InterfaceType>[];
|
| + env1.forEachSupertype(cls1, supertypes1.add);
|
| + List<InterfaceType> supertypes2 = <InterfaceType>[];
|
| + env2.forEachSupertype(cls2, supertypes1.add);
|
| + strategy.testTypeLists(
|
| + cls1, cls2, 'supertypes', supertypes1, supertypes2);
|
| +
|
| + List<ClassEntity> mixins1 = <ClassEntity>[];
|
| + env1.forEachMixin(cls1, mixins1.add);
|
| + List<ClassEntity> mixins2 = <ClassEntity>[];
|
| + env2.forEachMixin(cls2, mixins2.add);
|
| + strategy.testLists(
|
| + cls1, cls2, 'mixins', mixins1, mixins2, strategy.elementEquivalence);
|
| +
|
| + Map<MemberEntity, ClassEntity> members1 = <MemberEntity, ClassEntity>{};
|
| + Map<MemberEntity, ClassEntity> members2 = <MemberEntity, ClassEntity>{};
|
| + env1.forEachClassMember(cls1,
|
| + (ClassEntity declarer1, MemberEntity member1) {
|
| + if (cls1 == declarer1) {
|
| + Expect.identical(
|
| + member1,
|
| + env1.lookupClassMember(cls1, member1.name,
|
| + setter: member1.isSetter));
|
| + }
|
| + members1[member1] = declarer1;
|
| + });
|
| + env2.forEachClassMember(cls2,
|
| + (ClassEntity declarer2, MemberEntity member2) {
|
| + if (cls2 == declarer2) {
|
| + Expect.identical(
|
| + member2,
|
| + env2.lookupClassMember(cls2, member2.name,
|
| + setter: member2.isSetter));
|
| + }
|
| + members2[member2] = declarer2;
|
| + });
|
| + checkMapEquivalence(cls1, cls2, 'members', members1, members2, (a, b) {
|
| + bool result = strategy.elementEquivalence(a, b);
|
| + if (result) checkMembers(a, b);
|
| + return result;
|
| + }, strategy.elementEquivalence);
|
| +
|
| + classes2.add(cls2);
|
| + });
|
| + env2.forEachClass(lib2, (ClassEntity cls2) {
|
| + Expect.isTrue(classes2.contains(cls2), "Extra class $cls2 in $lib2");
|
| + });
|
| + });
|
| + // TODO(johnniwinther): Test the remaining properties of [ElementEnvironment].
|
| +}
|
| +
|
| +bool areInstantiationInfosEquivalent(
|
| + InstantiationInfo info1,
|
| + InstantiationInfo info2,
|
| + bool elementEquivalence(Entity a, Entity b),
|
| + bool typeEquivalence(DartType a, DartType b)) {
|
| + checkMaps(
|
| + info1.instantiationMap,
|
| + info2.instantiationMap,
|
| + 'instantiationMap of\n '
|
| + '${info1.instantiationMap}\nvs ${info2.instantiationMap}',
|
| + elementEquivalence,
|
| + (a, b) => areSetsEquivalent(
|
| + a, b, (a, b) => areInstancesEquivalent(a, b, typeEquivalence)));
|
| + return true;
|
| +}
|
| +
|
| +bool areInstancesEquivalent(Instance instance1, Instance instance2,
|
| + bool typeEquivalence(DartType a, DartType b)) {
|
| + InterfaceType type1 = instance1.type;
|
| + InterfaceType type2 = instance2.type;
|
| + return typeEquivalence(type1, type2) &&
|
| + instance1.kind == instance2.kind &&
|
| + instance1.isRedirection == instance2.isRedirection;
|
| +}
|
| +
|
| +void checkResolutionEnqueuers(
|
| + BackendUsage backendUsage1,
|
| + BackendUsage backendUsage2,
|
| + ResolutionEnqueuer enqueuer1,
|
| + ResolutionEnqueuer enqueuer2,
|
| + {bool elementEquivalence(Entity a, Entity b): areElementsEquivalent,
|
| + bool typeEquivalence(DartType a, DartType b): areTypesEquivalent,
|
| + bool elementFilter(Element element),
|
| + bool verbose: false}) {
|
| + ResolutionWorldBuilderBase worldBuilder1 = enqueuer1.worldBuilder;
|
| + ResolutionWorldBuilderBase worldBuilder2 = enqueuer2.worldBuilder;
|
| +
|
| + checkSets(
|
| + enqueuer1.worldBuilder.instantiatedTypes,
|
| + enqueuer2.worldBuilder.instantiatedTypes,
|
| + "Instantiated types mismatch",
|
| + typeEquivalence,
|
| + verbose: verbose);
|
| +
|
| + checkSets(
|
| + enqueuer1.worldBuilder.directlyInstantiatedClasses,
|
| + enqueuer2.worldBuilder.directlyInstantiatedClasses,
|
| + "Directly instantiated classes mismatch",
|
| + elementEquivalence,
|
| + verbose: verbose);
|
| +
|
| + checkMaps(
|
| + worldBuilder1.getInstantiationMap(),
|
| + worldBuilder2.getInstantiationMap(),
|
| + "Instantiated classes mismatch",
|
| + elementEquivalence,
|
| + (a, b) => areInstantiationInfosEquivalent(
|
| + a, b, elementEquivalence, typeEquivalence),
|
| + verbose: verbose);
|
| +
|
| + checkSets(enqueuer1.processedEntities, enqueuer2.processedEntities,
|
| + "Processed element mismatch", elementEquivalence, elementFilter: (e) {
|
| + return elementFilter != null ? elementFilter(e) : true;
|
| + }, verbose: verbose);
|
| +
|
| + checkSets(enqueuer1.worldBuilder.isChecks, enqueuer2.worldBuilder.isChecks,
|
| + "Is-check mismatch", typeEquivalence,
|
| + verbose: verbose);
|
| +
|
| + Expect.equals(backendUsage1.isInvokeOnUsed, backendUsage2.isInvokeOnUsed,
|
| + "JavaScriptBackend.hasInvokeOnSupport mismatch");
|
| + Expect.equals(
|
| + backendUsage1.isFunctionApplyUsed,
|
| + backendUsage1.isFunctionApplyUsed,
|
| + "JavaScriptBackend.hasFunctionApplySupport mismatch");
|
| + Expect.equals(
|
| + backendUsage1.isRuntimeTypeUsed,
|
| + backendUsage2.isRuntimeTypeUsed,
|
| + "JavaScriptBackend.hasRuntimeTypeSupport mismatch");
|
| + Expect.equals(backendUsage1.isIsolateInUse, backendUsage2.isIsolateInUse,
|
| + "JavaScriptBackend.hasIsolateSupport mismatch");
|
| +}
|
|
|