diff --git a/working/0546-patterns/exhaustiveness_prototype/lib/equal.dart b/working/0546-patterns/exhaustiveness_prototype/lib/equal.dart index e9da1a4ac9..c85d5d5230 100644 --- a/working/0546-patterns/exhaustiveness_prototype/lib/equal.dart +++ b/working/0546-patterns/exhaustiveness_prototype/lib/equal.dart @@ -1,13 +1,16 @@ // 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) { - if (left == right) return true; +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; @@ -35,7 +38,7 @@ bool _equalUnions(UnionSpace left, UnionSpace right) { for (var leftArm in left.arms) { var found = false; for (var rightArm in right.arms) { - if (equal(leftArm, rightArm)) { + if (equal(leftArm, rightArm, 'recurse union')) { found = true; break; } @@ -58,7 +61,9 @@ bool _equalExtracts(ExtractSpace left, ExtractSpace right) { if (right.fields.length != fields.length) return false; for (var field in fields) { - if (!equal(left.fields[field]!, right.fields[field]!)) return false; + if (!equal(left.fields[field]!, right.fields[field]!, 'recurse extract')) { + return false; + } } return true; diff --git a/working/0546-patterns/exhaustiveness_prototype/lib/intersect.dart b/working/0546-patterns/exhaustiveness_prototype/lib/intersect.dart index a3c1448eae..2f18e04e53 100644 --- a/working/0546-patterns/exhaustiveness_prototype/lib/intersect.dart +++ b/working/0546-patterns/exhaustiveness_prototype/lib/intersect.dart @@ -1,15 +1,17 @@ // 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 'package:exhaustiveness_prototype/static_type.dart'; - +import 'profile.dart' as profile; import 'space.dart'; +import 'static_type.dart'; /// Calculates the intersection of [left] and [right]. /// /// This is used to tell if two field spaces on a pair of spaces being /// subtracted have no common values. Space intersect(Space left, Space right) { + profile.count('intersect'); + // The intersection with an empty space is always empty. if (left == Space.empty) return Space.empty; if (right == Space.empty) return Space.empty; diff --git a/working/0546-patterns/exhaustiveness_prototype/lib/profile.dart b/working/0546-patterns/exhaustiveness_prototype/lib/profile.dart new file mode 100644 index 0000000000..dbc9d4a215 --- /dev/null +++ b/working/0546-patterns/exhaustiveness_prototype/lib/profile.dart @@ -0,0 +1,47 @@ +// 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 'dart:math'; + +var enabled = false; + +final _counts = {}; + +void count(String name, [String? subname]) { + if (!enabled) return; + _counts.putIfAbsent(name, () => 0); + _counts[name] = _counts[name]! + 1; + + if (subname != null) { + count('$name/$subname'); + } +} + +void run(void Function() callback) { + reset(); + try { + callback(); + } finally { + log(); + reset(); + } +} + +void reset() { + _counts.clear(); +} + +void log() { + var names = _counts.keys.toList(); + names.sort(); + var nameLength = + names.fold(0, (length, name) => max(length, name.length)); + var countLength = _counts.values + .fold(0, (length, count) => max(length, count.toString().length)); + + for (var name in names) { + print('${name.padRight(nameLength)} = ' + '${_counts[name].toString().padLeft(countLength)}'); + } +} diff --git a/working/0546-patterns/exhaustiveness_prototype/lib/space.dart b/working/0546-patterns/exhaustiveness_prototype/lib/space.dart index 7739daef02..c9f6dc0694 100644 --- a/working/0546-patterns/exhaustiveness_prototype/lib/space.dart +++ b/working/0546-patterns/exhaustiveness_prototype/lib/space.dart @@ -28,7 +28,7 @@ abstract class Space { // implementation would likely define hash code too and then simply // create a hash set to merge duplicates in O(n) time. for (var existing in allArms) { - if (equal(existing, space)) return; + if (equal(existing, space, 'dedupe union')) return; } allArms.add(space); diff --git a/working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart b/working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart index 62a0d1ace0..788723cfb6 100644 --- a/working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart +++ b/working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart @@ -1,14 +1,17 @@ // 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 'package:exhaustiveness_prototype/intersect_empty.dart'; -import 'package:exhaustiveness_prototype/static_type.dart'; +import 'intersect_empty.dart'; +import 'profile.dart' as profile; +import 'static_type.dart'; import 'space.dart'; /// Returns a new [Space] that contains all of the values of [left] that are /// not also in [right]. Space subtract(Space left, Space right) { + profile.count('subtract'); + // Subtracting from empty is still empty. if (left == Space.empty) return Space.empty; @@ -96,7 +99,6 @@ List _subtractExtractAtType(StaticType type, ExtractSpace left, // Walk the fields and see which ones are modified by the right-hand fields. var fixed = {}; - var changedLeft = {}; var changedDifference = {}; for (var name in fieldNames) { var difference = subtract(leftFields[name]!, rightFields[name]!); @@ -108,18 +110,17 @@ List _subtractExtractAtType(StaticType type, ExtractSpace left, // If the resulting field matches everything, simply discard it since // it's equivalent to omitting the field. } else { - changedLeft[name] = leftFields[name]!; changedDifference[name] = difference; } } // If no fields are affected by the subtraction, just return a single arm // with all of the fields. - if (changedLeft.isEmpty) return [Space(type, fixed)]; + if (changedDifference.isEmpty) return [Space(type, fixed)]; // For each field whose `left - right` is different, include an arm that // includes that one difference. - var changedFields = changedLeft.keys.toList(); + var changedFields = changedDifference.keys.toList(); var spaces = []; for (var i = 0; i < changedFields.length; i++) { var fields = {...fixed}; @@ -129,7 +130,7 @@ List _subtractExtractAtType(StaticType type, ExtractSpace left, if (i == j) { fields[name] = changedDifference[name]!; } else { - fields[name] = changedLeft[name]!; + fields[name] = leftFields[name]!; } }