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 |
index be28121447478a00f77bd9d59506b7b5bb9cae63..d1356f73cee89c558c5cce0d06eb7f705195ef36 100644 |
--- a/pkg/compiler/lib/src/serialization/equivalence.dart |
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart |
@@ -11,6 +11,7 @@ import '../constants/expressions.dart'; |
import '../dart_types.dart'; |
import '../elements/elements.dart'; |
import '../elements/visitor.dart'; |
+import '../resolution/access_semantics.dart'; |
import '../resolution/send_structure.dart'; |
import '../resolution/tree_elements.dart'; |
import '../tokens/token.dart'; |
@@ -138,13 +139,114 @@ bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b) { |
a.isEmpty == b.isEmpty; |
} |
+/// Returns `true` if the access semantics [a] and [b] are equivalent. |
+bool areAccessSemanticsEquivalent(AccessSemantics a, AccessSemantics b) { |
+ if (a.kind != b.kind) return false; |
+ switch (a.kind) { |
+ case AccessKind.EXPRESSION: |
+ case AccessKind.THIS: |
+ // No additional properties. |
+ return true; |
+ case AccessKind.THIS_PROPERTY: |
+ case AccessKind.DYNAMIC_PROPERTY: |
+ case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY: |
+ return areNamesEquivalent(a.name, b.name); |
+ case AccessKind.CLASS_TYPE_LITERAL: |
+ case AccessKind.TYPEDEF_TYPE_LITERAL: |
+ case AccessKind.DYNAMIC_TYPE_LITERAL: |
+ return areConstantsEquivalent(a.constant, b.constant); |
+ case AccessKind.LOCAL_FUNCTION: |
+ case AccessKind.LOCAL_VARIABLE: |
+ case AccessKind.FINAL_LOCAL_VARIABLE: |
+ case AccessKind.PARAMETER: |
+ case AccessKind.FINAL_PARAMETER: |
+ case AccessKind.STATIC_FIELD: |
+ case AccessKind.FINAL_STATIC_FIELD: |
+ case AccessKind.STATIC_METHOD: |
+ case AccessKind.STATIC_GETTER: |
+ case AccessKind.STATIC_SETTER: |
+ case AccessKind.TOPLEVEL_FIELD: |
+ case AccessKind.FINAL_TOPLEVEL_FIELD: |
+ case AccessKind.TOPLEVEL_METHOD: |
+ case AccessKind.TOPLEVEL_GETTER: |
+ case AccessKind.TOPLEVEL_SETTER: |
+ case AccessKind.SUPER_FIELD: |
+ case AccessKind.SUPER_FINAL_FIELD: |
+ case AccessKind.SUPER_METHOD: |
+ case AccessKind.SUPER_GETTER: |
+ case AccessKind.SUPER_SETTER: |
+ case AccessKind.TYPE_PARAMETER_TYPE_LITERAL: |
+ case AccessKind.UNRESOLVED: |
+ case AccessKind.UNRESOLVED_SUPER: |
+ case AccessKind.INVALID: |
+ return areElementsEquivalent(a.element, b.element); |
+ case AccessKind.COMPOUND: |
+ CompoundAccessSemantics compoundAccess1 = a; |
+ CompoundAccessSemantics compoundAccess2 = b; |
+ return compoundAccess1.compoundAccessKind == |
+ compoundAccess2.compoundAccessKind && |
+ areElementsEquivalent( |
+ compoundAccess1.getter, compoundAccess2.getter) && |
+ areElementsEquivalent(compoundAccess1.setter, compoundAccess2.setter); |
+ case AccessKind.CONSTANT: |
+ throw new UnsupportedError('Unsupported access kind: ${a.kind}'); |
+ } |
+} |
+ |
/// Returns `true` if the send structures [a] and [b] are equivalent. |
bool areSendStructuresEquivalent(SendStructure a, SendStructure b) { |
if (identical(a, b)) return true; |
if (a == null || b == null) return false; |
if (a.kind != b.kind) return false; |
- // TODO(johnniwinther): Compute a deep equivalence. |
- return true; |
+ |
+ var ad = a; |
+ var bd = b; |
+ switch (a.kind) { |
+ case SendStructureKind.IF_NULL: |
+ case SendStructureKind.LOGICAL_AND: |
+ case SendStructureKind.LOGICAL_OR: |
+ case SendStructureKind.NOT: |
+ case SendStructureKind.INVALID_UNARY: |
+ case SendStructureKind.INVALID_BINARY: |
+ // No additional properties. |
+ return true; |
+ |
+ case SendStructureKind.IS: |
+ case SendStructureKind.IS_NOT: |
+ case SendStructureKind.AS: |
+ return areTypesEquivalent(ad.type, bd.type); |
+ |
+ case SendStructureKind.INVOKE: |
+ case SendStructureKind.INCOMPATIBLE_INVOKE: |
+ if (!areSelectorsEquivalent(ad.selector, bd.selector)) return false; |
+ continue semantics; |
+ |
+ case SendStructureKind.UNARY: |
+ case SendStructureKind.BINARY: |
+ case SendStructureKind.PREFIX: |
+ case SendStructureKind.POSTFIX: |
+ case SendStructureKind.INDEX_PREFIX: |
+ case SendStructureKind.INDEX_POSTFIX: |
+ case SendStructureKind.COMPOUND: |
+ case SendStructureKind.COMPOUND_INDEX_SET: |
+ if (ad.operator != bd.operator) return false; |
+ continue semantics; |
+ |
+ case SendStructureKind.DEFERRED_PREFIX: |
+ return areElementsEquivalent(ad.prefix, bd.prefix) && |
+ areSendStructuresEquivalent(ad.sendStructure, bd.sendStructure); |
+ |
+ semantics: case SendStructureKind.GET: |
+ case SendStructureKind.SET: |
+ case SendStructureKind.INDEX: |
+ case SendStructureKind.INDEX_SET: |
+ case SendStructureKind.EQUALS: |
+ case SendStructureKind.NOT_EQUALS: |
+ case SendStructureKind.SET_IF_NULL: |
+ case SendStructureKind.INDEX_SET_IF_NULL: |
+ return areAccessSemanticsEquivalent(ad.semantics, bd.semantics); |
+ } |
+ throw new UnsupportedError('Unexpected send structures $a vs $b'); |
} |
/// Returns `true` if the new structures [a] and [b] are equivalent. |
@@ -152,8 +254,21 @@ bool areNewStructuresEquivalent(NewStructure a, NewStructure b) { |
if (identical(a, b)) return true; |
if (a == null || b == null) return false; |
if (a.kind != b.kind) return false; |
- // TODO(johnniwinther): Compute a deep equivalence. |
- return true; |
+ |
+ var ad = a; |
+ var bd = b; |
+ switch (a.kind) { |
+ case NewStructureKind.NEW_INVOKE: |
+ return ad.semantics.kind == bd.semantics.kind && |
+ areElementsEquivalent(ad.semantics.element, bd.semantics.element) && |
+ areTypesEquivalent(ad.semantics.type, bd.semantics.type) && |
+ areSelectorsEquivalent(ad.selector, bd.selector); |
+ case NewStructureKind.CONST_INVOKE: |
+ return ad.constantInvokeKind == bd.constantInvokeKind && |
+ areConstantsEquivalent(ad.constant, bd.constant); |
+ case NewStructureKind.LATE_CONST: |
+ throw new UnsupportedError('Unsupported NewStructure kind ${a.kind}.'); |
+ } |
} |
/// Strategy for testing equivalence. |