| Index: tests/compiler/dart2js/equivalence/check_helpers.dart
|
| diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/equivalence/check_helpers.dart
|
| similarity index 55%
|
| copy from tests/compiler/dart2js/serialization/test_helper.dart
|
| copy to tests/compiler/dart2js/equivalence/check_helpers.dart
|
| index 0e5c36668f463980d23ff3823ea754f9c9680a47..a38b06ad3f40cefacab2c2d075eb72148b6e03ab 100644
|
| --- a/tests/compiler/dart2js/serialization/test_helper.dart
|
| +++ b/tests/compiler/dart2js/equivalence/check_helpers.dart
|
| @@ -1,24 +1,19 @@
|
| -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// 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.
|
|
|
| -library dart2js.serialization_test_helper;
|
| +/// General equivalence test functions.
|
| +
|
| +library dart2js.equivalence.helpers;
|
|
|
| -import 'dart:collection';
|
| -import 'package:compiler/src/common/resolution.dart';
|
| import 'package:compiler/src/constants/expressions.dart';
|
| import 'package:compiler/src/constants/values.dart';
|
| -import 'package:compiler/src/compiler.dart';
|
| import 'package:compiler/src/elements/elements.dart';
|
| import 'package:compiler/src/elements/entities.dart';
|
| import 'package:compiler/src/elements/resolution_types.dart';
|
| import 'package:compiler/src/elements/types.dart';
|
| -import 'package:compiler/src/kernel/elements.dart';
|
| -import 'package:compiler/src/kernel/element_map_impl.dart';
|
| import 'package:compiler/src/serialization/equivalence.dart';
|
| -import 'package:compiler/src/util/util.dart';
|
| import 'package:expect/expect.dart';
|
| -import 'test_data.dart';
|
|
|
| Check currentCheck;
|
|
|
| @@ -346,101 +341,6 @@ bool checkConstantValueLists(Object object1, Object object2, String property,
|
| object1, object2, property, list1, list2, checkConstantValues);
|
| }
|
|
|
| -/// 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 checkSets(
|
| Iterable set1, Iterable set2, String messagePrefix, bool sameElement(a, b),
|
| {bool failOnUnfound: true,
|
| @@ -577,258 +477,3 @@ void checkMaps(Map map1, Map map2, String messagePrefix, bool sameKey(a, b),
|
| print(message);
|
| }
|
| }
|
| -
|
| -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());
|
| -}
|
| -
|
| -/// Returns the test arguments for testing the [index]th skipped test. The
|
| -/// [skip] count is used to check that [index] is a valid index.
|
| -List<String> testSkipped(int index, int skip) {
|
| - if (index < 0 || index >= skip) {
|
| - throw new ArgumentError('Invalid skip index $index');
|
| - }
|
| - return ['${index}', '${index + 1}'];
|
| -}
|
| -
|
| -/// Return the test arguments for testing the [index]th segment (1-based) of
|
| -/// the [TESTS] split into [count] groups. The first [skip] tests are excluded
|
| -/// from the automatic grouping.
|
| -List<String> testSegment(int index, int count, int skip) {
|
| - if (index < 0 || index > count) {
|
| - throw new ArgumentError('Invalid segment index $index');
|
| - }
|
| -
|
| - String segmentNumber(int i) {
|
| - return '${skip + i * (TESTS.length - skip) ~/ count}';
|
| - }
|
| -
|
| - if (index == 1 && skip != 0) {
|
| - return ['${skip}', segmentNumber(index)];
|
| - } else if (index == count) {
|
| - return [segmentNumber(index - 1)];
|
| - } else {
|
| - return [segmentNumber(index - 1), segmentNumber(index)];
|
| - }
|
| -}
|
| -
|
| -class KernelEquivalence {
|
| - final WorldDeconstructionForTesting testing;
|
| -
|
| - /// Set of mixin applications assumed to be equivalent.
|
| - ///
|
| - /// We need co-inductive reasoning because mixin applications are compared
|
| - /// structurally and therefore, in the case of generic mixin applications,
|
| - /// meet themselves through the equivalence check of their type variables.
|
| - Set<Pair<ClassEntity, ClassEntity>> assumedMixinApplications =
|
| - new Set<Pair<ClassEntity, ClassEntity>>();
|
| -
|
| - KernelEquivalence(KernelToElementMapImpl builder)
|
| - : testing = new WorldDeconstructionForTesting(builder);
|
| -
|
| - TestStrategy get defaultStrategy => new TestStrategy(
|
| - elementEquivalence: entityEquivalence,
|
| - typeEquivalence: typeEquivalence,
|
| - constantEquivalence: constantEquivalence,
|
| - constantValueEquivalence: constantValueEquivalence);
|
| -
|
| - bool entityEquivalence(Element a, Entity b, {TestStrategy strategy}) {
|
| - if (identical(a, b)) return true;
|
| - if (a == null || b == null) return false;
|
| - strategy ??= defaultStrategy;
|
| - switch (a.kind) {
|
| - case ElementKind.GENERATIVE_CONSTRUCTOR:
|
| - if (b is KGenerativeConstructor) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
|
| - }
|
| - return false;
|
| - case ElementKind.FACTORY_CONSTRUCTOR:
|
| - if (b is KFactoryConstructor) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
|
| - }
|
| - return false;
|
| - case ElementKind.CLASS:
|
| - if (b is KClass) {
|
| - List<InterfaceType> aMixinTypes = [];
|
| - List<InterfaceType> bMixinTypes = [];
|
| - ClassElement aClass = a;
|
| - if (aClass.isUnnamedMixinApplication) {
|
| - if (!testing.isUnnamedMixinApplication(b)) {
|
| - return false;
|
| - }
|
| - while (aClass.isMixinApplication) {
|
| - MixinApplicationElement aMixinApplication = aClass;
|
| - aMixinTypes.add(aMixinApplication.mixinType);
|
| - aClass = aMixinApplication.superclass;
|
| - }
|
| - KClass bClass = b;
|
| - while (bClass != null) {
|
| - InterfaceType mixinType = testing.getMixinTypeForClass(bClass);
|
| - if (mixinType == null) break;
|
| - bMixinTypes.add(mixinType);
|
| - bClass = testing.getSuperclassForClass(bClass);
|
| - }
|
| - if (aMixinTypes.isNotEmpty || aMixinTypes.isNotEmpty) {
|
| - Pair<ClassEntity, ClassEntity> pair =
|
| - new Pair<ClassEntity, ClassEntity>(aClass, bClass);
|
| - if (assumedMixinApplications.contains(pair)) {
|
| - return true;
|
| - } else {
|
| - assumedMixinApplications.add(pair);
|
| - bool result = strategy.testTypeLists(
|
| - a, b, 'mixinTypes', aMixinTypes, bMixinTypes);
|
| - assumedMixinApplications.remove(pair);
|
| - return result;
|
| - }
|
| - }
|
| - } else {
|
| - if (testing.isUnnamedMixinApplication(b)) {
|
| - return false;
|
| - }
|
| - }
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(a, b, 'library', a.library, b.library);
|
| - }
|
| - return false;
|
| - case ElementKind.LIBRARY:
|
| - if (b is KLibrary) {
|
| - LibraryElement libraryA = a;
|
| - return libraryA.canonicalUri == b.canonicalUri;
|
| - }
|
| - return false;
|
| - case ElementKind.FUNCTION:
|
| - if (b is KMethod) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
|
| - strategy.testElements(a, b, 'library', a.library, b.library);
|
| - } else if (b is KLocalFunction) {
|
| - LocalFunctionElement aLocalFunction = a;
|
| - return strategy.test(a, b, 'name', a.name, b.name ?? '') &&
|
| - strategy.testElements(a, b, 'executableContext',
|
| - aLocalFunction.executableContext, b.executableContext) &&
|
| - strategy.testElements(a, b, 'memberContext',
|
| - aLocalFunction.memberContext, b.memberContext);
|
| - }
|
| - return false;
|
| - case ElementKind.GETTER:
|
| - if (b is KGetter) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
|
| - strategy.testElements(a, b, 'library', a.library, b.library);
|
| - }
|
| - return false;
|
| - case ElementKind.SETTER:
|
| - if (b is KSetter) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
|
| - strategy.testElements(a, b, 'library', a.library, b.library);
|
| - }
|
| - return false;
|
| - case ElementKind.FIELD:
|
| - if (b is KField) {
|
| - return strategy.test(a, b, 'name', a.name, b.name) &&
|
| - strategy.testElements(
|
| - a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) &&
|
| - strategy.testElements(a, b, 'library', a.library, b.library);
|
| - }
|
| - return false;
|
| - case ElementKind.TYPE_VARIABLE:
|
| - if (b is KTypeVariable) {
|
| - TypeVariableElement aElement = a;
|
| - return strategy.test(a, b, 'index', aElement.index, b.index) &&
|
| - strategy.testElements(a, b, 'typeDeclaration',
|
| - aElement.typeDeclaration, b.typeDeclaration);
|
| - }
|
| - return false;
|
| - default:
|
| - throw new UnsupportedError('Unsupported equivalence: '
|
| - '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
|
| - }
|
| - }
|
| -
|
| - bool typeEquivalence(ResolutionDartType a, DartType b,
|
| - {TestStrategy strategy}) {
|
| - if (identical(a, b)) return true;
|
| - if (a == null || b == null) return false;
|
| - strategy ??= defaultStrategy;
|
| - switch (a.kind) {
|
| - case ResolutionTypeKind.DYNAMIC:
|
| - return b is DynamicType;
|
| - case ResolutionTypeKind.VOID:
|
| - return b is VoidType;
|
| - case ResolutionTypeKind.INTERFACE:
|
| - if (b is InterfaceType) {
|
| - ResolutionInterfaceType aType = a;
|
| - return strategy.testElements(a, b, 'element', a.element, b.element) &&
|
| - strategy.testTypeLists(
|
| - a, b, 'typeArguments', aType.typeArguments, b.typeArguments);
|
| - }
|
| - return false;
|
| - case ResolutionTypeKind.TYPE_VARIABLE:
|
| - if (b is TypeVariableType) {
|
| - return strategy.testElements(a, b, 'element', a.element, b.element);
|
| - }
|
| - return false;
|
| - case ResolutionTypeKind.FUNCTION:
|
| - if (b is FunctionType) {
|
| - ResolutionFunctionType aType = a;
|
| - return strategy.testTypes(
|
| - a, b, 'returnType', aType.returnType, b.returnType) &&
|
| - strategy.testTypeLists(a, b, 'parameterTypes',
|
| - aType.parameterTypes, b.parameterTypes) &&
|
| - strategy.testTypeLists(a, b, 'optionalParameterTypes',
|
| - aType.optionalParameterTypes, b.optionalParameterTypes) &&
|
| - strategy.testLists(a, b, 'namedParameters', aType.namedParameters,
|
| - b.namedParameters) &&
|
| - strategy.testTypeLists(a, b, 'namedParameterTypes',
|
| - aType.namedParameterTypes, b.namedParameterTypes);
|
| - }
|
| - return false;
|
| - default:
|
| - throw new UnsupportedError('Unsupported equivalence: '
|
| - '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
|
| - }
|
| - }
|
| -
|
| - bool constantEquivalence(ConstantExpression exp1, ConstantExpression exp2,
|
| - {TestStrategy strategy}) {
|
| - strategy ??= defaultStrategy;
|
| - return areConstantsEquivalent(exp1, exp2, strategy: strategy);
|
| - }
|
| -
|
| - bool constantValueEquivalence(ConstantValue value1, ConstantValue value2,
|
| - {TestStrategy strategy}) {
|
| - strategy ??= defaultStrategy;
|
| - return areConstantValuesEquivalent(value1, value2, strategy: strategy);
|
| - }
|
| -}
|
|
|