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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/serialization/equivalence.dart
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c91561b2a3d91ac6c67d3840152ae51f3b48ba2e
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -0,0 +1,701 @@
+// 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.
+
+/// Functions for asserting equivalence across serialization.
+
+library dart2js.serialization.equivalence;
+
+import '../common/resolution.dart';
+import '../constants/expressions.dart';
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import '../elements/visitor.dart';
+import '../universe/selector.dart';
+import '../universe/use.dart';
+
+/// Equality based equivalence function.
+bool equality(a, b) => a == b;
+
+/// Returns `true` if the elements in [a] and [b] are pair-wise equivalent
+/// according to [elementEquivalence].
+bool areListsEquivalent(
+ List a,
+ List b,
+ [bool elementEquivalence(a, b) = equality]) {
+
+ if (a.length != b.length) return false;
+ for (int i = 0; i < a.length && i < b.length; i++) {
+ if (!elementEquivalence(a[i], b[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Returns `true` if the elements in [a] and [b] are equivalent as sets using
+/// [elementEquivalence] to determine element equivalence.
+bool areSetsEquivalent(
+ Iterable set1,
+ Iterable set2,
+ [bool elementEquivalence(a, b) = equality]) {
+
+ Set remaining = set2.toSet();
+ for (var element1 in set1) {
+ bool found = false;
+ for (var element2 in set2) {
+ if (elementEquivalence(element1, element2)) {
+ found = true;
+ remaining.remove(element2);
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return remaining.isEmpty;
+}
+
+/// Returns `true` if elements [a] and [b] are equivalent.
+bool areElementsEquivalent(Element a, Element b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ return const ElementIdentityEquivalence().visit(a, b);
+}
+
+/// Returns `true` if types [a] and [b] are equivalent.
+bool areTypesEquivalent(DartType a, DartType b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ return const TypeEquivalence().visit(a, b);
+}
+
+/// Returns `true` if constants [a] and [b] are equivalent.
+bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) {
+ if (identical(exp1, exp2)) return true;
+ if (exp1 == null || exp2 == null) return false;
+ return const ConstantEquivalence().visit(exp1, exp2);
+}
+
+/// Returns `true` if the lists of elements, [a] and [b], are equivalent.
+bool areElementListsEquivalent(List<Element> a, List<Element> b) {
+ return areListsEquivalent(a, b, areElementsEquivalent);
+}
+
+/// Returns `true` if the lists of types, [a] and [b], are equivalent.
+bool areTypeListsEquivalent(List<DartType> a, List<DartType> b) {
+ return areListsEquivalent(a, b, areTypesEquivalent);
+}
+
+/// Returns `true` if the lists of constants, [a] and [b], are equivalent.
+bool areConstantListsEquivalent(List<ConstantExpression> a,
+ List<ConstantExpression> b) {
+ return areListsEquivalent(a, b, areConstantsEquivalent);
+}
+
+/// Returns `true` if the selectors [a] and [b] are equivalent.
+bool areSelectorsEquivalent(Selector a, Selector b) {
+ return a.kind == b.kind &&
+ a.callStructure == b.callStructure &&
+ areNamesEquivalent(a.memberName, b.memberName);
+}
+
+/// Returns `true` if the names [a] and [b] are equivalent.
+bool areNamesEquivalent(Name a, Name b) {
+ return a.text == b.text &&
+ a.isSetter == b.isSetter &&
+ areElementsEquivalent(a.library, b.library);
+}
+
+/// Returns `true` if the dynamic uses [a] and [b] are equivalent.
+bool areDynamicUsesEquivalent(DynamicUse a, DynamicUse b) {
+ return areSelectorsEquivalent(a.selector, b.selector);
+}
+
+/// Returns `true` if the static uses [a] and [b] are equivalent.
+bool areStaticUsesEquivalent(StaticUse a, StaticUse b) {
+ return a.kind == b.kind &&
+ areElementsEquivalent(a.element, b.element);
+}
+
+/// Returns `true` if the type uses [a] and [b] are equivalent.
+bool areTypeUsesEquivalent(TypeUse a, TypeUse b) {
+ return a.kind == b.kind &&
+ areTypesEquivalent(a.type, b.type);
+}
+
+/// Returns `true` if the list literal uses [a] and [b] are equivalent.
+bool areListLiteralUsesEquivalent(ListLiteralUse a, ListLiteralUse b) {
+ return areTypesEquivalent(a.type, b.type) &&
+ a.isConstant == b.isConstant &&
+ a.isEmpty == b.isEmpty;
+}
+
+/// Returns `true` if the map literal uses [a] and [b] are equivalent.
+bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b) {
+ return areTypesEquivalent(a.type, b.type) &&
+ a.isConstant == b.isConstant &&
+ a.isEmpty == b.isEmpty;
+}
+
+/// Strategy for testing equivalence.
+///
+/// Use this strategy to determine equivalence without failing on inequivalence.
+class TestStrategy {
+ const TestStrategy();
+
+ bool test(var object1, var object2, String property, var value1, var value2) {
+ return value1 == value2;
+ }
+
+ bool testLists(
+ Object object1, Object object2, String property,
+ List list1, List list2,
+ [bool elementEquivalence(a, b) = equality]) {
+ return areListsEquivalent(list1, list2, elementEquivalence);
+ }
+
+ bool testSets(
+ var object1, var object2, String property,
+ Iterable set1, Iterable set2,
+ [bool elementEquivalence(a, b) = equality]) {
+ return areSetsEquivalent(set1, set2, elementEquivalence);
+ }
+
+ bool testElements(
+ Object object1, Object object2, String property,
+ Element element1, Element element2) {
+ return areElementsEquivalent(element1, element2);
+ }
+
+ bool testTypes(
+ Object object1, Object object2, String property,
+ DartType type1, DartType type2) {
+ return areTypesEquivalent(type1, type2);
+ }
+
+ bool testConstants(
+ Object object1, Object object2, String property,
+ ConstantExpression exp1, ConstantExpression exp2) {
+ return areConstantsEquivalent(exp1, exp2);
+ }
+
+ bool testTypeLists(
+ Object object1, Object object2, String property,
+ List<DartType> list1, List<DartType> list2) {
+ return areTypeListsEquivalent(list1, list2);
+ }
+
+ bool testConstantLists(
+ Object object1, Object object2, String property,
+ List<ConstantExpression> list1,
+ List<ConstantExpression> list2) {
+ return areConstantListsEquivalent(list1, list2);
+ }
+
+}
+
+/// Visitor that checks for equivalence of [Element]s.
+class ElementIdentityEquivalence extends BaseElementVisitor<bool, Element> {
+ final TestStrategy strategy;
+
+ const ElementIdentityEquivalence([this.strategy = const TestStrategy()]);
+
+ bool visit(Element element1, Element element2) {
+ if (element1 == null && element2 == null) {
+ return true;
+ } else if (element1 == null || element2 == null) {
+ return false;
+ }
+ element1 = element1.declaration;
+ element2 = element2.declaration;
+ if (element1 == element2) {
+ return true;
+ }
+ return
+ strategy.test(
+ element1, element2, 'kind',
+ element1.kind, element2.kind) &&
+ element1.accept(this, element2);
+ }
+
+ @override
+ bool visitElement(Element e, Element arg) {
+ throw new UnsupportedError("Unsupported element $e");
+ }
+
+ @override
+ bool visitLibraryElement(LibraryElement element1, LibraryElement element2) {
+ return
+ strategy.test(element1, element2,
+ 'canonicalUri',
+ element1.canonicalUri, element2.canonicalUri);
+ }
+
+ @override
+ bool visitCompilationUnitElement(CompilationUnitElement element1,
+ CompilationUnitElement element2) {
+ return
+ strategy.test(element1, element2,
+ 'name',
+ element1.name, element2.name) &&
+ visit(element1.library, element2.library);
+ }
+
+ @override
+ bool visitClassElement(ClassElement element1, ClassElement element2) {
+ return
+ strategy.test(element1, element2,
+ 'name',
+ element1.name, element2.name) &&
+ visit(element1.library, element2.library);
+ }
+
+ bool checkMembers(Element element1, Element element2) {
+ if (!strategy.test(element1, element2, 'name',
+ element1.name, element2.name)) {
+ return false;
+ }
+ if (element1.enclosingClass != null || element2.enclosingClass != null) {
+ return visit(element1.enclosingClass, element2.enclosingClass);
+ } else {
+ return visit(element1.library, element2.library);
+ }
+ }
+
+ @override
+ bool visitFieldElement(FieldElement element1, FieldElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitConstructorElement(ConstructorElement element1,
+ ConstructorElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitMethodElement(MethodElement element1,
+ MethodElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitGetterElement(GetterElement element1,
+ GetterElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitSetterElement(SetterElement element1,
+ SetterElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitLocalFunctionElement(LocalFunctionElement element1,
+ LocalFunctionElement element2) {
+ // TODO(johnniwinther): Define an equivalence on locals.
+ return checkMembers(element1.memberContext, element2.memberContext);
+ }
+
+ bool visitAbstractFieldElement(AbstractFieldElement element1,
+ AbstractFieldElement element2) {
+ return checkMembers(element1, element2);
+ }
+
+ @override
+ bool visitTypeVariableElement(TypeVariableElement element1,
+ TypeVariableElement element2) {
+ return
+ strategy.test(
+ element1, element2, 'name',
+ element1.name, element2.name) &&
+ visit(element1.typeDeclaration, element2.typeDeclaration);
+ }
+
+ @override
+ bool visitTypedefElement(TypedefElement element1, TypedefElement element2) {
+ return
+ strategy.test(
+ element1, element2, 'name',
+ element1.name, element2.name) &&
+ visit(element1.library, element2.library);
+ }
+
+ @override
+ bool visitParameterElement(ParameterElement element1,
+ ParameterElement element2) {
+ return
+ strategy.test(
+ element1, element2, 'name',
+ element1.name, element2.name) &&
+ visit(element1.functionDeclaration, element2.functionDeclaration);
+ }
+
+ @override
+ bool visitImportElement(ImportElement element1, ImportElement element2) {
+ return
+ visit(element1.importedLibrary, element2.importedLibrary) &&
+ visit(element1.library, element2.library);
+ }
+
+ @override
+ bool visitExportElement(ExportElement element1, ExportElement element2) {
+ return
+ visit(element1.exportedLibrary, element2.exportedLibrary) &&
+ visit(element1.library, element2.library);
+ }
+
+ @override
+ bool visitPrefixElement(PrefixElement element1, PrefixElement element2) {
+ return
+ strategy.test(
+ element1, element2, 'name',
+ element1.name, element2.name) &&
+ visit(element1.library, element2.library);
+ }
+}
+
+
+/// Visitor that checks for equivalence of [DartType]s.
+class TypeEquivalence implements DartTypeVisitor<bool, DartType> {
+ final TestStrategy strategy;
+
+ const TypeEquivalence([this.strategy = const TestStrategy()]);
+
+ bool visit(DartType type1, DartType type2) {
+ return
+ strategy.test(type1, type2, 'kind', type1.kind, type2.kind) &&
+ type1.accept(this, type2);
+ }
+
+ @override
+ bool visitDynamicType(DynamicType type, DynamicType other) => true;
+
+ @override
+ bool visitFunctionType(FunctionType type, FunctionType other) {
+ return
+ strategy.testTypeLists(
+ type, other, 'parameterTypes',
+ type.parameterTypes, other.parameterTypes) &&
+ strategy.testTypeLists(
+ type, other, 'optionalParameterTypes',
+ type.optionalParameterTypes, other.optionalParameterTypes) &&
+ strategy.testTypeLists(
+ type, other, 'namedParameterTypes',
+ type.namedParameterTypes, other.namedParameterTypes) &&
+ strategy.testLists(
+ type, other, 'namedParameters',
+ type.namedParameters, other.namedParameters);
+ }
+
+ bool visitGenericType(GenericType type, GenericType other) {
+ return
+ strategy.testElements(
+ type, other, 'element',
+ type.element, other.element) &&
+ strategy.testTypeLists(
+ type, other, 'typeArguments',
+ type.typeArguments, other.typeArguments);
+ }
+
+ @override
+ bool visitMalformedType(MalformedType type, MalformedType other) => true;
+
+ @override
+ bool visitStatementType(StatementType type, StatementType other) {
+ throw new UnsupportedError("Unsupported type: $type");
+ }
+
+ @override
+ bool visitTypeVariableType(TypeVariableType type, TypeVariableType other) {
+ return
+ strategy.testElements(
+ type, other, 'element',
+ type.element, other.element);
+ }
+
+ @override
+ bool visitVoidType(VoidType type, VoidType argument) => true;
+
+ @override
+ bool visitInterfaceType(InterfaceType type, InterfaceType other) {
+ return visitGenericType(type, other);
+ }
+
+ @override
+ bool visitTypedefType(TypedefType type, TypedefType other) {
+ return visitGenericType(type, other);
+ }
+}
+
+/// Visitor that checks for structural equivalence of [ConstantExpression]s.
+class ConstantEquivalence
+ implements ConstantExpressionVisitor<bool, ConstantExpression> {
+ final TestStrategy strategy;
+
+ const ConstantEquivalence([this.strategy = const TestStrategy()]);
+
+ @override
+ bool visit(ConstantExpression exp1, ConstantExpression exp2) {
+ if (identical(exp1, exp2)) return true;
+ return
+ strategy.test(exp1, exp2, 'kind', exp1.kind, exp2.kind) &&
+ exp1.accept(this, exp2);
+ }
+
+ @override
+ bool visitBinary(BinaryConstantExpression exp1,
+ BinaryConstantExpression exp2) {
+ return
+ strategy.test(exp1, exp2, 'operator', exp1.operator, exp2.operator) &&
+ strategy.testConstants(exp1, exp2, 'left', exp1.left, exp2.left) &&
+ strategy.testConstants(exp1, exp2, 'right', exp1.right, exp2.right);
+ }
+
+ @override
+ bool visitConcatenate(ConcatenateConstantExpression exp1,
+ ConcatenateConstantExpression exp2) {
+ return
+ strategy.testConstantLists(
+ exp1, exp2, 'expressions',
+ exp1.expressions, exp2.expressions);
+ }
+
+ @override
+ bool visitConditional(ConditionalConstantExpression exp1,
+ ConditionalConstantExpression exp2) {
+ return
+ strategy.testConstants(
+ exp1, exp2, 'condition', exp1.condition, exp2.condition) &&
+ strategy.testConstants(
+ exp1, exp2, 'trueExp', exp1.trueExp, exp2.trueExp) &&
+ strategy.testConstants(
+ exp1, exp2, 'falseExp', exp1.falseExp, exp2.falseExp);
+ }
+
+ @override
+ bool visitConstructed(ConstructedConstantExpression exp1,
+ ConstructedConstantExpression exp2) {
+ return
+ strategy.testTypes(
+ exp1, exp2, 'type',
+ exp1.type, exp2.type) &&
+ strategy.testElements(
+ exp1, exp2, 'target',
+ exp1.target, exp2.target) &&
+ strategy.testConstantLists(
+ exp1, exp2, 'arguments',
+ exp1.arguments, exp2.arguments) &&
+ strategy.test(exp1, exp2, 'callStructure',
+ exp1.callStructure, exp2.callStructure);
+ }
+
+ @override
+ bool visitFunction(FunctionConstantExpression exp1,
+ FunctionConstantExpression exp2) {
+ return
+ strategy.testElements(
+ exp1, exp2, 'element',
+ exp1.element, exp2.element);
+ }
+
+ @override
+ bool visitIdentical(IdenticalConstantExpression exp1,
+ IdenticalConstantExpression exp2) {
+ return
+ strategy.testConstants(exp1, exp2, 'left', exp1.left, exp2.left) &&
+ strategy.testConstants(exp1, exp2, 'right', exp1.right, exp2.right);
+ }
+
+ @override
+ bool visitList(ListConstantExpression exp1, ListConstantExpression exp2) {
+ return
+ strategy.testTypes(
+ exp1, exp2, 'type',
+ exp1.type, exp2.type) &&
+ strategy.testConstantLists(
+ exp1, exp2, 'values',
+ exp1.values, exp2.values);
+ }
+
+ @override
+ bool visitMap(MapConstantExpression exp1, MapConstantExpression exp2) {
+ return
+ strategy.testTypes(
+ exp1, exp2, 'type',
+ exp1.type, exp2.type) &&
+ strategy.testConstantLists(
+ exp1, exp2, 'keys',
+ exp1.keys, exp2.keys) &&
+ strategy.testConstantLists(
+ exp1, exp2, 'values',
+ exp1.values, exp2.values);
+ }
+
+ @override
+ bool visitNamed(NamedArgumentReference exp1, NamedArgumentReference exp2) {
+ return strategy.test(exp1, exp2, 'name', exp1.name, exp2.name);
+ }
+
+ @override
+ bool visitPositional(PositionalArgumentReference exp1,
+ PositionalArgumentReference exp2) {
+ return strategy.test(exp1, exp2, 'index', exp1.index, exp2.index);
+ }
+
+ @override
+ bool visitSymbol(SymbolConstantExpression exp1,
+ SymbolConstantExpression exp2) {
+ // TODO: implement visitSymbol
+ return true;
+ }
+
+ @override
+ bool visitType(TypeConstantExpression exp1, TypeConstantExpression exp2) {
+ return strategy.testTypes(exp1, exp2, 'type', exp1.type, exp2.type);
+ }
+
+ @override
+ bool visitUnary(UnaryConstantExpression exp1, UnaryConstantExpression exp2) {
+ return
+ strategy.test(exp1, exp2, 'operator', exp1.operator, exp2.operator) &&
+ strategy.testConstants(
+ exp1, exp2, 'expression', exp1.expression, exp2.expression);
+ }
+
+ @override
+ bool visitVariable(VariableConstantExpression exp1,
+ VariableConstantExpression exp2) {
+ return
+ strategy.testElements(
+ exp1, exp2, 'element',
+ exp1.element, exp2.element);
+ }
+
+ @override
+ bool visitBool(BoolConstantExpression exp1, BoolConstantExpression exp2) {
+ return
+ strategy.test(
+ exp1, exp2, 'primitiveValue',
+ exp1.primitiveValue, exp2.primitiveValue);
+ }
+
+ @override
+ bool visitDouble(DoubleConstantExpression exp1,
+ DoubleConstantExpression exp2) {
+ return
+ strategy.test(
+ exp1, exp2, 'primitiveValue',
+ exp1.primitiveValue, exp2.primitiveValue);
+ }
+
+ @override
+ bool visitInt(IntConstantExpression exp1, IntConstantExpression exp2) {
+ return
+ strategy.test(
+ exp1, exp2, 'primitiveValue',
+ exp1.primitiveValue, exp2.primitiveValue);
+ }
+
+ @override
+ bool visitNull(NullConstantExpression exp1, NullConstantExpression exp2) {
+ return true;
+ }
+
+ @override
+ bool visitString(StringConstantExpression exp1,
+ StringConstantExpression exp2) {
+ return
+ strategy.test(
+ exp1, exp2, 'primitiveValue',
+ exp1.primitiveValue, exp2.primitiveValue);
+ }
+
+ @override
+ bool visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp1,
+ BoolFromEnvironmentConstantExpression exp2) {
+ return
+ strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
+ strategy.testConstants(
+ exp1, exp2, 'defaultValue',
+ exp1.defaultValue, exp2.defaultValue);
+ }
+
+ @override
+ bool visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp1,
+ IntFromEnvironmentConstantExpression exp2) {
+ return
+ strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
+ strategy.testConstants(
+ exp1, exp2, 'defaultValue',
+ exp1.defaultValue, exp2.defaultValue);
+ }
+
+ @override
+ bool visitStringFromEnvironment(
+ StringFromEnvironmentConstantExpression exp1,
+ StringFromEnvironmentConstantExpression exp2) {
+ return
+ strategy.testConstants(exp1, exp2, 'name', exp1.name, exp2.name) &&
+ strategy.testConstants(
+ exp1, exp2, 'defaultValue',
+ exp1.defaultValue, exp2.defaultValue);
+ }
+
+ @override
+ bool visitStringLength(StringLengthConstantExpression exp1,
+ StringLengthConstantExpression exp2) {
+ return
+ strategy.testConstants(
+ exp1, exp2, 'expression',
+ exp1.expression, exp2.expression);
+ }
+
+ @override
+ bool visitDeferred(DeferredConstantExpression exp1,
+ DeferredConstantExpression exp2) {
+ // TODO: implement visitDeferred
+ return true;
+ }
+}
+
+/// Tests the equivalence of [impact1] and [impact2] using [strategy].
+bool testResolutionImpactEquivalence(
+ ResolutionImpact impact1,
+ ResolutionImpact impact2,
+ [TestStrategy strategy = const TestStrategy()]) {
+ return
+ strategy.testSets(
+ impact1, impact2, 'constSymbolNames',
+ impact1.constSymbolNames, impact2.constSymbolNames) &&
+ strategy.testSets(
+ impact1, impact2, 'constantLiterals',
+ impact1.constantLiterals, impact2.constantLiterals,
+ areConstantsEquivalent) &&
+ strategy.testSets(
+ impact1, impact2, 'dynamicUses',
+ impact1.dynamicUses, impact2.dynamicUses,
+ areDynamicUsesEquivalent) &&
+ strategy.testSets(
+ impact1, impact2, 'features',
+ impact1.features, impact2.features) &&
+ strategy.testSets(
+ impact1, impact2, 'listLiterals',
+ impact1.listLiterals, impact2.listLiterals,
+ areListLiteralUsesEquivalent) &&
+ strategy.testSets(
+ impact1, impact2, 'mapLiterals',
+ impact1.mapLiterals, impact2.mapLiterals,
+ areMapLiteralUsesEquivalent) &&
+ strategy.testSets(
+ impact1, impact2, 'staticUses',
+ impact1.staticUses, impact2.staticUses,
+ areStaticUsesEquivalent) &&
+ strategy.testSets(
+ impact1, impact2, 'typeUses',
+ impact1.typeUses, impact2.typeUses,
+ areTypeUsesEquivalent);
+}
« 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