blob: 63f527d9a2d6c738ebdb201c29bca9279aab361d [file] [log] [blame]
// Copyright (c) 2022, 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.
import 'profile.dart' as profile;
import 'space.dart';
/// Returns `true` if [left] and [right] are equivalent spaces.
///
/// Equality is defined purely structurally/syntactically.
bool equal(Space left, Space right, String reason) {
profile.count('equal', reason);
if (identical(left, right)) return true;
// Empty is only equal to itself (and will get caught by the previous check).
if (left == Space.empty) return false;
if (right == Space.empty) return false;
if (left is UnionSpace && right is UnionSpace) {
return _equalUnions(left, right);
}
if (left is ExtractSpace && right is ExtractSpace) {
return _equalExtracts(left, right);
}
// If we get here, one is a union and one is an extract.
return false;
}
/// Returns `true` if [left] and [right] have the same type and the same fields
/// with equal subspaces.
bool _equalExtracts(ExtractSpace left, ExtractSpace right) {
// Must have the same type.
if (left.type != right.type) return false;
// And the same fields.
Set<String> fields = {...left.fields.keys, ...right.fields.keys};
if (left.fields.length != fields.length) return false;
if (right.fields.length != fields.length) return false;
for (String field in fields) {
if (!equal(left.fields[field]!, right.fields[field]!, 'recurse extract')) {
return false;
}
}
return true;
}
/// Returns `true` if [left] and [right] contain equal arms in any order.
///
/// Assumes that all duplicates have already been removed from each union.
bool _equalUnions(UnionSpace left, UnionSpace right) {
if (left.arms.length != right.arms.length) return false;
/// For each left arm, should find an equal right arm.
for (Space leftArm in left.arms) {
bool found = false;
for (Space rightArm in right.arms) {
if (equal(leftArm, rightArm, 'recurse union')) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}