Optimize structural equality checks on inline record types.
This dramatically improves performance on code that makes heavy use of "typedef protos".
@@ -346,17 +346,25 @@ final class EqualityChecker {
}
/**
- * Check for equality on anonymous object types (e.g. `{a: 3}`).
+ * Check for equality on inline record types (e.g. `{a: number}`).
*
- * <p>Only anonymous types can be compared for equality based on structure.
- *
- * <p>The concept of "structural equality" on nominal types is incompatible with the meaning of
- * "equals" in Java. That kind of relationship is correctly expressed as both types being mutual
- * subtypes.
+ * <p>Only inline record types can be compared for equality based on structure. All other
+ * structural types, such as @records and object-literal types, have some concept of uniquenes.
+ * Such structural relationships are correctly expressed in terms of subtyping.
*/
private boolean areRecordEqual(RecordType left, RecordType right) {
- Set<String> leftKeys = left.getPropertyNames();
- Set<String> rightKeys = right.getPropertyNames();
+ /**
+ * Don't check inherited properties; checking them is both incorrect and slow.
+ *
+ * <p>The full definition of a record type is contained in its "own" properties (i.e. `{a:
+ * boolean, toString: function(...)}` and `{a: boolean}` are not interchangable). This is in
+ * part because all inline record types share the same inheritance.
+ *
+ * <p>Additionally, code that makes heavy use of inline record types compiles very slowly if the
+ * set of inherited properties is recomputed during every equality check.
+ */
+ Set<String> leftKeys = left.getOwnPropertyNames();
+ Set<String> rightKeys = right.getOwnPropertyNames();
if (!rightKeys.equals(leftKeys)) {
return false;
}
@@ -366,6 +374,7 @@ final class EqualityChecker {
return false;
}
}
+
return true;
}
