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

Unified Diff: tests/compiler/dart2js/kernel/test_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 side-by-side diff with in-line comments
Download patch
Index: tests/compiler/dart2js/kernel/test_helpers.dart
diff --git a/tests/compiler/dart2js/kernel/test_helpers.dart b/tests/compiler/dart2js/kernel/test_helpers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..87994cb66d876eb987a04e34916783d3021f7f0b
--- /dev/null
+++ b/tests/compiler/dart2js/kernel/test_helpers.dart
@@ -0,0 +1,306 @@
+// Copyright (c) 2016, 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.kernel.equivalence;
+
+import 'package:compiler/src/common/backend_api.dart';
+import 'package:compiler/src/common/resolution.dart';
+import 'package:compiler/src/common/work.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/enqueue.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/ssa/kernel_impact.dart';
+import 'package:compiler/src/universe/world_impact.dart';
+import 'package:compiler/src/util/util.dart';
+
+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);
+ }
+}
+
+class KernelTestWorkItemBuilder implements WorkItemBuilder {
+ final Compiler _compiler;
+
+ KernelTestWorkItemBuilder(this._compiler);
+
+ @override
+ WorkItem createWorkItem(MemberEntity entity) {
+ return new KernelTestWorkItem(
+ _compiler, _compiler.backend.impactTransformer, entity);
+ }
+}
+
+class KernelTestWorkItem implements ResolutionWorkItem {
+ final Compiler _compiler;
+ final ImpactTransformer _impactTransformer;
+ final MemberElement element;
+
+ KernelTestWorkItem(this._compiler, this._impactTransformer, this.element);
+
+ @override
+ WorldImpact run() {
+ ResolutionImpact resolutionImpact = build(_compiler, element.resolvedAst);
+ return _impactTransformer.transformResolutionImpact(resolutionImpact);
+ }
+}
+
+/// Visitor the performers unaliasing of all typedefs nested within a
+/// [ResolutionDartType].
+class Unaliaser
+ extends BaseResolutionDartTypeVisitor<dynamic, ResolutionDartType> {
+ const Unaliaser();
+
+ @override
+ ResolutionDartType visit(ResolutionDartType type, [_]) =>
+ type.accept(this, null);
+
+ @override
+ ResolutionDartType visitType(ResolutionDartType type, _) => type;
+
+ List<ResolutionDartType> visitList(List<ResolutionDartType> types) =>
+ types.map(visit).toList();
+
+ @override
+ ResolutionDartType visitInterfaceType(ResolutionInterfaceType type, _) {
+ return type.createInstantiation(visitList(type.typeArguments));
+ }
+
+ @override
+ ResolutionDartType visitTypedefType(ResolutionTypedefType type, _) {
+ return visit(type.unaliased);
+ }
+
+ @override
+ ResolutionDartType visitFunctionType(ResolutionFunctionType type, _) {
+ return new ResolutionFunctionType.synthesized(
+ visit(type.returnType),
+ visitList(type.parameterTypes),
+ visitList(type.optionalParameterTypes),
+ type.namedParameters,
+ visitList(type.namedParameterTypes));
+ }
+}
+
+/// Perform unaliasing of all typedefs nested within a [ResolutionDartType].
+ResolutionDartType unalias(ResolutionDartType type) {
+ return const Unaliaser().visit(type);
+}
+
+bool elementFilter(Entity element) {
+ if (element is ConstructorElement && element.isRedirectingFactory) {
+ // Redirecting factory constructors are skipped in kernel.
+ return false;
+ }
+ if (element is ClassElement) {
+ for (ConstructorElement constructor in element.constructors) {
+ if (!constructor.isRedirectingFactory) {
+ return true;
+ }
+ }
+ // The class cannot itself be instantiated.
+ return false;
+ }
+ return true;
+}

Powered by Google App Engine
This is Rietveld 408576698