Skip to content

Commit

Permalink
Add deep equivalence test for Send/NewStructures.
Browse files Browse the repository at this point in the history
R=sigmund@google.com

Review URL: https://codereview.chromium.org/1881743004 .
  • Loading branch information
johnniwinther committed Apr 13, 2016
1 parent 68a9225 commit 058441e
Showing 1 changed file with 119 additions and 4 deletions.
123 changes: 119 additions & 4 deletions pkg/compiler/lib/src/serialization/equivalence.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -139,22 +140,136 @@ 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.
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.
Expand Down

0 comments on commit 058441e

Please sign in to comment.