Index: tests/compiler/dart2js/serialization_test.dart |
diff --git a/tests/compiler/dart2js/serialization_test.dart b/tests/compiler/dart2js/serialization_test.dart |
index 0f965a3205e88c9041f46bf1d76a0db3643854e1..26740bc477e906fd2a9eadbb55354887cb4c139b 100644 |
--- a/tests/compiler/dart2js/serialization_test.dart |
+++ b/tests/compiler/dart2js/serialization_test.dart |
@@ -17,6 +17,7 @@ import 'package:compiler/src/elements/elements.dart'; |
import 'package:compiler/src/elements/visitor.dart'; |
import 'package:compiler/src/ordered_typeset.dart'; |
import 'package:compiler/src/serialization/element_serialization.dart'; |
+import 'package:compiler/src/serialization/equivalence.dart'; |
import 'package:compiler/src/serialization/json_serializer.dart'; |
import 'package:compiler/src/serialization/serialization.dart'; |
@@ -144,7 +145,7 @@ checkElementLists(Object object1, Object object2, String property, |
/// [checkEquivalence] to check the pair-wise equivalence. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkListEquivalence( |
+bool checkListEquivalence( |
Object object1, Object object2, String property, |
Iterable list1, Iterable list2, |
void checkEquivalence(o1, o2, property, a, b)) { |
@@ -167,30 +168,73 @@ void checkListEquivalence( |
'`${property}` on $object1:\n ${list1.join('\n ')}\n' |
'`${property}` on $object2:\n ${list2.join('\n ')}'; |
} |
+ return true; |
+} |
+ |
+/// Check equivalence of the two iterables, [set1] and [set1], as sets using |
+/// [elementEquivalence] to compute the pair-wise equivalence. |
+/// |
+/// Uses [object1], [object2] and [property] to provide context for failures. |
+bool checkSetEquivalence( |
+ var object1, |
+ var object2, |
+ String property, |
+ Iterable set1, |
+ Iterable set2, |
+ bool sameElement(a, b)) { |
+ List common = []; |
+ List unfound = []; |
+ Set remaining = set2.toSet(); |
+ for (var element1 in set1) { |
+ bool found = false; |
+ for (var element2 in remaining) { |
+ if (sameElement(element1, element2)) { |
+ found = true; |
+ remaining.remove(element2); |
+ break; |
+ } |
+ } |
+ if (found) { |
+ common.add(element1); |
+ } else { |
+ unfound.add(element1); |
+ } |
+ } |
+ if (unfound.isNotEmpty || remaining.isNotEmpty) { |
+ String message = |
+ "Set mismatch for `$property` on $object1 vs $object2: \n" |
+ "Common:\n ${common.join('\n ')}\n" |
+ "Unfound:\n ${unfound.join('\n ')}\n" |
+ "Extra: \n ${remaining.join('\n ')}"; |
+ throw message; |
+ } |
+ return true; |
} |
/// Checks the equivalence of the identity (but not properties) of [element1] |
/// and [element2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkElementIdentities( |
+bool checkElementIdentities( |
Object object1, Object object2, String property, |
Element element1, Element element2) { |
- if (identical(element1, element2)) return; |
+ if (identical(element1, element2)) return true; |
if (element1 == null || element2 == null) { |
- check(object1, object2, property, element1, element2); |
+ return check(object1, object2, property, element1, element2); |
+ } else { |
+ return const ElementIdentityEquivalence(const CheckStrategy()) |
+ .visit(element1, element2); |
} |
- const ElementIdentityEquivalence().visit(element1, element2); |
} |
/// Checks the pair-wise equivalence of the identity (but not properties) of the |
/// elements in [list] and [list2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkElementListIdentities( |
+bool checkElementListIdentities( |
Object object1, Object object2, String property, |
Iterable<Element> list1, Iterable<Element> list2) { |
- checkListEquivalence( |
+ return checkListEquivalence( |
object1, object2, property, |
list1, list2, checkElementIdentities); |
} |
@@ -198,50 +242,129 @@ void checkElementListIdentities( |
/// Checks the equivalence of [type1] and [type2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkTypes( |
+bool checkTypes( |
Object object1, Object object2, String property, |
DartType type1, DartType type2) { |
- if (identical(type1, type2)) return; |
+ if (identical(type1, type2)) return true; |
if (type1 == null || type2 == null) { |
- check(object1, object2, property, type1, type2); |
+ return check(object1, object2, property, type1, type2); |
+ } else { |
+ return const TypeEquivalence(const CheckStrategy()).visit(type1, type2); |
} |
- const TypeEquivalence().visit(type1, type2); |
} |
/// Checks the pair-wise equivalence of the types in [list1] and [list2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkTypeLists( |
+bool checkTypeLists( |
Object object1, Object object2, String property, |
List<DartType> list1, List<DartType> list2) { |
- checkListEquivalence(object1, object2, property, list1, list2, checkTypes); |
+ return checkListEquivalence( |
+ object1, object2, property, list1, list2, checkTypes); |
} |
/// Checks the equivalence of [exp1] and [exp2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkConstants( |
+bool checkConstants( |
Object object1, Object object2, String property, |
ConstantExpression exp1, ConstantExpression exp2) { |
- if (identical(exp1, exp2)) return; |
+ if (identical(exp1, exp2)) return true; |
if (exp1 == null || exp2 == null) { |
- check(object1, object2, property, exp1, exp2); |
+ return check(object1, object2, property, exp1, exp2); |
+ } else { |
+ return const ConstantEquivalence(const CheckStrategy()).visit(exp1, exp2); |
} |
- const ConstantEquivalence().visit(exp1, exp2); |
} |
/// Checks the pair-wise equivalence of the contants in [list1] and [list2]. |
/// |
/// Uses [object1], [object2] and [property] to provide context for failures. |
-void checkConstantLists( |
+bool checkConstantLists( |
Object object1, Object object2, String property, |
List<ConstantExpression> list1, |
List<ConstantExpression> list2) { |
- checkListEquivalence( |
+ return checkListEquivalence( |
object1, object2, property, |
list1, list2, checkConstants); |
} |
+ |
+/// Strategy for checking equivalence. |
+/// |
+/// Use this strategy to fail early with contextual information in the event of |
+/// inequivalence. |
+class CheckStrategy implements TestStrategy { |
+ const CheckStrategy(); |
+ |
+ @override |
+ bool test(var object1, var object2, String property, var value1, var value2) { |
+ return check(object1, object2, property, value1, value2); |
+ } |
+ |
+ @override |
+ bool testLists( |
+ Object object1, Object object2, String property, |
+ List list1, List list2, |
+ [bool elementEquivalence(a, b) = equality]) { |
+ return checkListEquivalence( |
+ object1, object2, property, list1, list2, |
+ (o1, o2, p, v1, v2) { |
+ if (!elementEquivalence(v1, v2)) { |
+ throw "$o1.$p = '${v1}' <> " |
+ "$o2.$p = '${v2}'"; |
+ } |
+ return true; |
+ }); |
+ } |
+ |
+ @override |
+ bool testSets( |
+ var object1, var object2, String property, |
+ Iterable set1, Iterable set2, |
+ [bool elementEquivalence(a, b) = equality]) { |
+ return checkSetEquivalence( |
+ object1, object2,property, set1, set2, elementEquivalence); |
+ } |
+ |
+ @override |
+ bool testElements( |
+ Object object1, Object object2, String property, |
+ Element element1, Element element2) { |
+ return checkElementIdentities( |
+ object1, object2, property, element1, element2); |
+ } |
+ |
+ @override |
+ bool testTypes( |
+ Object object1, Object object2, String property, |
+ DartType type1, DartType type2) { |
+ return checkTypes(object1, object2, property, type1, type2); |
+ } |
+ |
+ @override |
+ bool testConstants( |
+ Object object1, Object object2, String property, |
+ ConstantExpression exp1, ConstantExpression exp2) { |
+ return checkConstants(object1, object2, property, exp1, exp2); |
+ } |
+ |
+ @override |
+ bool testTypeLists( |
+ Object object1, Object object2, String property, |
+ List<DartType> list1, List<DartType> list2) { |
+ return checkTypeLists(object1, object2, property, list1, list2); |
+ } |
+ |
+ @override |
+ bool testConstantLists( |
+ Object object1, Object object2, String property, |
+ List<ConstantExpression> list1, |
+ List<ConstantExpression> list2) { |
+ return checkConstantLists(object1, object2, property, list1, list2); |
+ } |
+} |
+ |
/// Checks the equivalence of [constructor1] and [constructor2]. |
void constantConstructorEquivalence(ConstantConstructor constructor1, |
ConstantConstructor constructor2) { |
@@ -333,127 +456,12 @@ class ConstantConstructorEquivalence |
/// Check that the values [property] of [object1] and [object2], [value1] and |
/// [value2] respectively, are equal and throw otherwise. |
-void check(var object1, var object2, String property, var value1, value2) { |
+bool check(var object1, var object2, String property, var value1, value2) { |
if (value1 != value2) { |
throw "$object1.$property = '${value1}' <> " |
"$object2.$property = '${value2}'"; |
} |
-} |
- |
-/// Visitor that checks for equivalence of [Element] identities. |
-class ElementIdentityEquivalence extends BaseElementVisitor<dynamic, Element> { |
- const ElementIdentityEquivalence(); |
- |
- void visit(Element element1, Element element2) { |
- if (element1 == null && element2 == null) return; |
- element1 = element1.declaration; |
- element2 = element2.declaration; |
- if (element1 == element2) return; |
- check(element1, element2, 'kind', element1.kind, element2.kind); |
- element1.accept(this, element2); |
- } |
- |
- @override |
- void visitElement(Element e, Element arg) { |
- throw new UnsupportedError("Unsupported element $e"); |
- } |
- |
- @override |
- void visitLibraryElement(LibraryElement element1, LibraryElement element2) { |
- check(element1, element2, |
- 'canonicalUri', |
- element1.canonicalUri, element2.canonicalUri); |
- } |
- |
- @override |
- void visitCompilationUnitElement(CompilationUnitElement element1, |
- CompilationUnitElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.library, element2.library); |
- } |
- |
- @override |
- void visitClassElement(ClassElement element1, ClassElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.library, element2.library); |
- } |
- |
- void checkMembers(Element element1, Element element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- if (element1.enclosingClass != null || element2.enclosingClass != null) { |
- visit(element1.enclosingClass, element2.enclosingClass); |
- } else { |
- visit(element1.library, element2.library); |
- } |
- } |
- |
- @override |
- void visitFieldElement(FieldElement element1, FieldElement element2) { |
- checkMembers(element1, element2); |
- } |
- |
- @override |
- void visitFunctionElement(FunctionElement element1, |
- FunctionElement element2) { |
- checkMembers(element1, element2); |
- } |
- |
- void visitAbstractFieldElement(AbstractFieldElement element1, |
- AbstractFieldElement element2) { |
- checkMembers(element1, element2); |
- } |
- |
- @override |
- void visitTypeVariableElement(TypeVariableElement element1, |
- TypeVariableElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.typeDeclaration, element2.typeDeclaration); |
- } |
- |
- @override |
- void visitTypedefElement(TypedefElement element1, TypedefElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.library, element2.library); |
- } |
- |
- @override |
- void visitParameterElement(ParameterElement element1, |
- ParameterElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.functionDeclaration, element2.functionDeclaration); |
- } |
- |
- @override |
- void visitImportElement(ImportElement element1, ImportElement element2) { |
- visit(element1.importedLibrary, element2.importedLibrary); |
- visit(element1.library, element2.library); |
- } |
- |
- @override |
- void visitExportElement(ExportElement element1, ExportElement element2) { |
- visit(element1.exportedLibrary, element2.exportedLibrary); |
- visit(element1.library, element2.library); |
- } |
- |
- @override |
- void visitPrefixElement(PrefixElement element1, PrefixElement element2) { |
- check(element1, element2, |
- 'name', |
- element1.name, element2.name); |
- visit(element1.library, element2.library); |
- } |
+ return true; |
} |
/// Visitor that checks for equivalence of [Element] properties. |
@@ -555,7 +563,7 @@ class ElementPropertyEquivalence extends BaseElementVisitor<dynamic, Element> { |
'Missing member for $member2 in\n ${members1.join('\n ')}'; |
if (member2.isAbstractField) { |
// TODO(johnniwinther): Ensure abstract fields are handled correctly. |
- print(message); |
+ //print(message); |
continue; |
} else { |
throw message; |
@@ -566,7 +574,7 @@ class ElementPropertyEquivalence extends BaseElementVisitor<dynamic, Element> { |
'Missing member for $member1 in\n ${members2.join('\n ')}'; |
if (member1.isAbstractField) { |
// TODO(johnniwinther): Ensure abstract fields are handled correctly. |
- print(message); |
+ //print(message); |
continue; |
} else { |
throw message; |
@@ -864,273 +872,3 @@ class ElementPropertyEquivalence extends BaseElementVisitor<dynamic, Element> { |
// TODO(johnniwinther): Check members. |
} |
} |
- |
-/// Visitor that checks for equivalence of [DartType]s. |
-class TypeEquivalence implements DartTypeVisitor<dynamic, DartType> { |
- const TypeEquivalence(); |
- |
- void visit(DartType type1, DartType type2) { |
- check(type1, type2, 'kind', type1.kind, type2.kind); |
- type1.accept(this, type2); |
- } |
- |
- @override |
- void visitDynamicType(DynamicType type, DynamicType other) { |
- } |
- |
- @override |
- void visitFunctionType(FunctionType type, FunctionType other) { |
- checkTypeLists( |
- type, other, 'parameterTypes', |
- type.parameterTypes, other.parameterTypes); |
- checkTypeLists( |
- type, other, 'optionalParameterTypes', |
- type.optionalParameterTypes, other.optionalParameterTypes); |
- checkTypeLists( |
- type, other, 'namedParameterTypes', |
- type.namedParameterTypes, other.namedParameterTypes); |
- for (int i = 0; i < type.namedParameters.length; i++) { |
- if (type.namedParameters[i] != other.namedParameters[i]) { |
- throw "Named parameter '$type.namedParameters[i]' <> " |
- "'${other.namedParameters[i]}'"; |
- } |
- } |
- } |
- |
- void visitGenericType(GenericType type, GenericType other) { |
- checkElementIdentities( |
- type, other, 'element', |
- type.element, other.element); |
- checkTypeLists( |
- type, other, 'typeArguments', |
- type.typeArguments, other.typeArguments); |
- } |
- |
- @override |
- void visitMalformedType(MalformedType type, MalformedType other) { |
- } |
- |
- @override |
- void visitStatementType(StatementType type, StatementType other) { |
- throw new UnsupportedError("Unsupported type: $type"); |
- } |
- |
- @override |
- void visitTypeVariableType(TypeVariableType type, TypeVariableType other) { |
- checkElementIdentities( |
- type, other, 'element', |
- type.element, other.element); |
- } |
- |
- @override |
- void visitVoidType(VoidType type, VoidType argument) { |
- } |
- |
- @override |
- void visitInterfaceType(InterfaceType type, InterfaceType other) { |
- visitGenericType(type, other); |
- } |
- |
- @override |
- void visitTypedefType(TypedefType type, TypedefType other) { |
- visitGenericType(type, other); |
- } |
-} |
- |
-/// Visitor that checks for structural equivalence of [ConstantExpression]s. |
-class ConstantEquivalence |
- implements ConstantExpressionVisitor<dynamic, ConstantExpression> { |
- const ConstantEquivalence(); |
- |
- @override |
- visit(ConstantExpression exp1, ConstantExpression exp2) { |
- if (identical(exp1, exp2)) return; |
- check(exp1, exp2, 'kind', exp1.kind, exp2.kind); |
- exp1.accept(this, exp2); |
- } |
- |
- @override |
- visitBinary(BinaryConstantExpression exp1, BinaryConstantExpression exp2) { |
- check(exp1, exp2, 'operator', exp1.operator, exp2.operator); |
- checkConstants(exp1, exp2, 'left', exp1.left, exp2.left); |
- checkConstants(exp1, exp2, 'right', exp1.right, exp2.right); |
- } |
- |
- @override |
- visitConcatenate(ConcatenateConstantExpression exp1, |
- ConcatenateConstantExpression exp2) { |
- checkConstantLists( |
- exp1, exp2, 'expressions', |
- exp1.expressions, exp2.expressions); |
- } |
- |
- @override |
- visitConditional(ConditionalConstantExpression exp1, |
- ConditionalConstantExpression exp2) { |
- checkConstants( |
- exp1, exp2, 'condition', exp1.condition, exp2.condition); |
- checkConstants(exp1, exp2, 'trueExp', exp1.trueExp, exp2.trueExp); |
- checkConstants(exp1, exp2, 'falseExp', exp1.falseExp, exp2.falseExp); |
- } |
- |
- @override |
- visitConstructed(ConstructedConstantExpression exp1, |
- ConstructedConstantExpression exp2) { |
- checkTypes( |
- exp1, exp2, 'type', |
- exp1.type, exp2.type); |
- checkElementIdentities( |
- exp1, exp2, 'target', |
- exp1.target, exp2.target); |
- checkConstantLists( |
- exp1, exp2, 'arguments', |
- exp1.arguments, exp2.arguments); |
- check(exp1, exp2, 'callStructure', exp1.callStructure, exp2.callStructure); |
- } |
- |
- @override |
- visitFunction(FunctionConstantExpression exp1, |
- FunctionConstantExpression exp2) { |
- checkElementIdentities( |
- exp1, exp2, 'element', |
- exp1.element, exp2.element); |
- } |
- |
- @override |
- visitIdentical(IdenticalConstantExpression exp1, |
- IdenticalConstantExpression exp2) { |
- checkConstants(exp1, exp2, 'left', exp1.left, exp2.left); |
- checkConstants(exp1, exp2, 'right', exp1.right, exp2.right); |
- } |
- |
- @override |
- visitList(ListConstantExpression exp1, ListConstantExpression exp2) { |
- checkTypes( |
- exp1, exp2, 'type', |
- exp1.type, exp2.type); |
- checkConstantLists( |
- exp1, exp2, 'values', |
- exp1.values, exp2.values); |
- } |
- |
- @override |
- visitMap(MapConstantExpression exp1, MapConstantExpression exp2) { |
- checkTypes( |
- exp1, exp2, 'type', |
- exp1.type, exp2.type); |
- checkConstantLists( |
- exp1, exp2, 'keys', |
- exp1.keys, exp2.keys); |
- checkConstantLists( |
- exp1, exp2, 'values', |
- exp1.values, exp2.values); |
- } |
- |
- @override |
- visitNamed(NamedArgumentReference exp1, NamedArgumentReference exp2) { |
- check(exp1, exp2, 'name', exp1.name, exp2.name); |
- } |
- |
- @override |
- visitPositional(PositionalArgumentReference exp1, |
- PositionalArgumentReference exp2) { |
- check(exp1, exp2, 'index', exp1.index, exp2.index); |
- } |
- |
- @override |
- visitSymbol(SymbolConstantExpression exp1, SymbolConstantExpression exp2) { |
- // TODO: implement visitSymbol |
- } |
- |
- @override |
- visitType(TypeConstantExpression exp1, TypeConstantExpression exp2) { |
- checkTypes( |
- exp1, exp2, 'type', |
- exp1.type, exp2.type); |
- } |
- |
- @override |
- visitUnary(UnaryConstantExpression exp1, UnaryConstantExpression exp2) { |
- check(exp1, exp2, 'operator', exp1.operator, exp2.operator); |
- checkConstants( |
- exp1, exp2, 'expression', exp1.expression, exp2.expression); |
- } |
- |
- @override |
- visitVariable(VariableConstantExpression exp1, |
- VariableConstantExpression exp2) { |
- checkElementIdentities( |
- exp1, exp2, 'element', |
- exp1.element, exp2.element); |
- } |
- |
- @override |
- visitBool(BoolConstantExpression exp1, BoolConstantExpression exp2) { |
- check(exp1, exp2, 'primitiveValue', |
- exp1.primitiveValue, exp2.primitiveValue); |
- } |
- |
- @override |
- visitDouble(DoubleConstantExpression exp1, DoubleConstantExpression exp2) { |
- check(exp1, exp2, 'primitiveValue', |
- exp1.primitiveValue, exp2.primitiveValue); |
- } |
- |
- @override |
- visitInt(IntConstantExpression exp1, IntConstantExpression exp2) { |
- check(exp1, exp2, 'primitiveValue', |
- exp1.primitiveValue, exp2.primitiveValue); |
- } |
- |
- @override |
- visitNull(NullConstantExpression exp1, NullConstantExpression exp2) { |
- // Do nothing. |
- } |
- |
- @override |
- visitString(StringConstantExpression exp1, StringConstantExpression exp2) { |
- check(exp1, exp2, 'primitiveValue', |
- exp1.primitiveValue, exp2.primitiveValue); |
- } |
- |
- @override |
- visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp1, |
- BoolFromEnvironmentConstantExpression exp2) { |
- checkConstants(exp1, exp2, 'name', exp1.name, exp2.name); |
- checkConstants( |
- exp1, exp2, 'defaultValue', |
- exp1.defaultValue, exp2.defaultValue); |
- } |
- |
- @override |
- visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp1, |
- IntFromEnvironmentConstantExpression exp2) { |
- checkConstants(exp1, exp2, 'name', exp1.name, exp2.name); |
- checkConstants( |
- exp1, exp2, 'defaultValue', |
- exp1.defaultValue, exp2.defaultValue); |
- } |
- |
- @override |
- visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp1, |
- StringFromEnvironmentConstantExpression exp2) { |
- checkConstants(exp1, exp2, 'name', exp1.name, exp2.name); |
- checkConstants( |
- exp1, exp2, 'defaultValue', |
- exp1.defaultValue, exp2.defaultValue); |
- } |
- |
- @override |
- visitStringLength(StringLengthConstantExpression exp1, |
- StringLengthConstantExpression exp2) { |
- checkConstants( |
- exp1, exp2, 'expression', |
- exp1.expression, exp2.expression); |
- } |
- |
- @override |
- visitDeferred(DeferredConstantExpression exp1, |
- DeferredConstantExpression exp2) { |
- // TODO: implement visitDeferred |
- } |
-} |