Add Object.hash and Object.hashAll static helper methods.

Fixes #11617.

Bug: http://dartbug.com/11617
Change-Id: Id06fb5b3914bee24713427edbd3b9b7e86f86449
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/73360
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2021-06-25 11:40:35 +00:00 committed by commit-bot@chromium.org
parent 843bd00c71
commit 83376bf1ee
7 changed files with 1274 additions and 261 deletions

View file

@ -27,6 +27,10 @@
daylight saving changes that are not precisely one hour.
(No change on the Web which uses the JavaScript `Date` object.)
* Adds static methods `hash`, `hashAll` and `hashAllUnordered` to the
`Object` class. These can be used to combine the hash codes of
multiple objects in a consistent way.
#### `dart:ffi`
* Adds the `DynamicLibrary.providesSymbol` function to check whether a symbol

View file

@ -146,4 +146,418 @@ class Object {
/// A representation of the runtime type of the object.
external Type get runtimeType;
/// Creates a combined hash code for a number of objects.
///
/// The hash code is computed for all arguments that are actually
/// supplied, even if they are `null`, by numerically combining the
/// [Object.hashCode] of each argument.
///
/// Example:
/// ```dart
/// class SomeObject {
/// final Object a, b, c;
/// SomeObject(this.a, this.b, this.c);
/// bool operator=(Object other) =>
/// other is SomeObject && a == other.a && b == other.b && c == other.c;
/// int get hashCode => Object.hash(a, b, c);
/// }
/// ```
///
/// The computed value will be consistent when the function is called
/// with the same arguments multiple times
/// during the execution of a single program.
///
/// The hash value generated by this function is *not* guaranteed to be stable
/// over different runs of the same program,
/// or between code run in different isolates of the same program.
/// The exact algorithm used may differ between different platforms,
/// or between different versions of the platform libraries,
/// and it may depend on values that change on each program execution.
///
/// The [hashAll] function gives the same result as this function when
/// called with a collection containing the actual arguments
/// to this function in the same order.
@Since("2.14")
static int hash(Object? object1, Object? object2,
[Object? object3 = sentinelValue,
Object? object4 = sentinelValue,
Object? object5 = sentinelValue,
Object? object6 = sentinelValue,
Object? object7 = sentinelValue,
Object? object8 = sentinelValue,
Object? object9 = sentinelValue,
Object? object10 = sentinelValue,
Object? object11 = sentinelValue,
Object? object12 = sentinelValue,
Object? object13 = sentinelValue,
Object? object14 = sentinelValue,
Object? object15 = sentinelValue,
Object? object16 = sentinelValue,
Object? object17 = sentinelValue,
Object? object18 = sentinelValue,
Object? object19 = sentinelValue,
Object? object20 = sentinelValue]) {
if (sentinelValue == object3) {
return SystemHash.hash2(object1.hashCode, object2.hashCode, _hashSeed);
}
if (sentinelValue == object4) {
return SystemHash.hash3(
object1.hashCode, object2.hashCode, object3.hashCode, _hashSeed);
}
if (sentinelValue == object5) {
return SystemHash.hash4(object1.hashCode, object2.hashCode,
object3.hashCode, object4.hashCode, _hashSeed);
}
if (sentinelValue == object6) {
return SystemHash.hash5(object1.hashCode, object2.hashCode,
object3.hashCode, object4.hashCode, object5.hashCode, _hashSeed);
}
if (sentinelValue == object7) {
return SystemHash.hash6(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
_hashSeed);
}
if (sentinelValue == object8) {
return SystemHash.hash7(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
_hashSeed);
}
if (sentinelValue == object9) {
return SystemHash.hash8(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
_hashSeed);
}
if (sentinelValue == object10) {
return SystemHash.hash9(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
_hashSeed);
}
if (sentinelValue == object11) {
return SystemHash.hash10(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
_hashSeed);
}
if (sentinelValue == object12) {
return SystemHash.hash11(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
_hashSeed);
}
if (sentinelValue == object13) {
return SystemHash.hash12(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
_hashSeed);
}
if (sentinelValue == object14) {
return SystemHash.hash13(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
_hashSeed);
}
if (sentinelValue == object15) {
return SystemHash.hash14(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
_hashSeed);
}
if (sentinelValue == object16) {
return SystemHash.hash15(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
_hashSeed);
}
if (sentinelValue == object17) {
return SystemHash.hash16(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
object16.hashCode,
_hashSeed);
}
if (sentinelValue == object18) {
return SystemHash.hash17(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
object16.hashCode,
object17.hashCode,
_hashSeed);
}
if (sentinelValue == object19) {
return SystemHash.hash18(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
object16.hashCode,
object17.hashCode,
object18.hashCode,
_hashSeed);
}
if (sentinelValue == object20) {
return SystemHash.hash19(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
object16.hashCode,
object17.hashCode,
object18.hashCode,
object19.hashCode,
_hashSeed);
}
return SystemHash.hash20(
object1.hashCode,
object2.hashCode,
object3.hashCode,
object4.hashCode,
object5.hashCode,
object6.hashCode,
object7.hashCode,
object8.hashCode,
object9.hashCode,
object10.hashCode,
object11.hashCode,
object12.hashCode,
object13.hashCode,
object14.hashCode,
object15.hashCode,
object16.hashCode,
object17.hashCode,
object18.hashCode,
object19.hashCode,
object20.hashCode,
_hashSeed);
}
/// Creates a combined hash code for a sequence of objects.
///
/// The hash code is computed for elements in [objects],
/// even if they are `null`,
/// by numerically combining the [Object.hashCode] of each element
/// in iteration order.
///
/// The result of `hashAll([o])` is not `o.hashCode`.
///
/// Example:
/// ```dart
/// class SomeObject {
/// final List<String> path;
/// SomeObject(this.path);
/// bool operator=(Object other) {
/// if (other is SomeObject) {
/// if (path.length != other.path.length) return false;
/// for (int i = 0; i < path.length; i++) {
/// if (path[i] != other.path[i]) return false;
/// }
/// return true;
/// }
/// return false;
/// }
///
/// int get hashCode => Object.hashAll(path);
/// }
/// ```
///
/// The computed value will be be consistent when the function is called
/// again with objects that have the same hash codes in the same order
/// during an execution of a single program.
///
/// The hash value generated by this function is *not* guranteed to be stable
/// over different runs of the same program,
/// or between code run in different isolates of the same program.
/// The exact algorithm used may differ between different platforms,
/// or between different versions of the platform libraries,
/// and it may depend on values that change on each program execution.
@Since("2.14")
static int hashAll(Iterable<Object?> objects) {
int hash = _hashSeed;
for (var object in objects) {
hash = SystemHash.combine(hash, object.hashCode);
}
return SystemHash.finish(hash);
}
/// Creates a combined hash code for a collection of objects.
///
/// The hash code is computed for elements in [objects],
/// even if they are `null`,
/// by numerically combining the [Object.hashCode] of each element
/// in an order independent way.
///
/// The result of `unorderedHashAll({o})` is not `o.hashCode`.
///
/// Example:
/// ```dart
/// bool setEquals<T>(Set<T> set1, Set<T> set2) {
/// var hashCode1 = Object.unorderedHashAll(set1);
/// var hashCode2 = Object.unorderedHashAll(set2);
/// if (hashCode1 != hashCode2) return false;
/// // Compare elements ...
/// }
/// ```
///
/// The computed value will be be consistent when the function is called
/// again with objects that have the same hash codes
/// during an execution of a single program,
/// even if the objects are not necessarily in the same order,
///
/// The hash value generated by this function is *not* guranteed to be stable
/// over different runs of the same program.
/// The exact algorithm used may differ between different platforms,
/// or between different versions of the platform libraries,
/// and it may depend on values that change per program run
@Since("2.14")
static int hashAllUnordered(Iterable<Object?> objects) {
int sum = 0;
int count = 0;
const int mask = 0x3FFFFFFF;
for (var object in objects) {
int objectHash = SystemHash.smear(object.hashCode);
sum = (sum + objectHash) & mask;
count += 1;
}
return SystemHash.hash2(sum, count);
}
}
// A per-isolate seed for hash code computations.
final int _hashSeed = identityHashCode(Object);

View file

@ -148,7 +148,7 @@ final Future<Null> nullFuture = Zone.root.run(() => Future<Null>.value(null));
///
/// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
///
/// Usage:
/// Use:
/// Hash each value with the hash of the previous value, then get the final
/// hash by calling finish.
/// ```
@ -158,8 +158,9 @@ final Future<Null> nullFuture = Zone.root.run(() => Future<Null>.value(null));
/// }
/// hash = SystemHash.finish(hash);
/// ```
// TODO(lrn): Consider specializing this code per platform,
// so the VM can use its 64-bit integers directly.
///
/// TODO(lrn): Consider specializing this code per platform,
/// so the VM can use its 64-bit integers directly.
@Since("2.11")
class SystemHash {
static int combine(int hash, int value) {
@ -174,23 +175,24 @@ class SystemHash {
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
static int hash2(int v1, int v2) {
int hash = 0;
static int hash2(int v1, int v2, [@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
return finish(hash);
}
static int hash3(int v1, int v2, int v3) {
int hash = 0;
static int hash3(int v1, int v2, int v3, [@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
return finish(hash);
}
static int hash4(int v1, int v2, int v3, int v4) {
int hash = 0;
static int hash4(int v1, int v2, int v3, int v4,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -198,8 +200,9 @@ class SystemHash {
return finish(hash);
}
static int hash5(int v1, int v2, int v3, int v4, int v5) {
int hash = 0;
static int hash5(int v1, int v2, int v3, int v4, int v5,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -208,8 +211,9 @@ class SystemHash {
return finish(hash);
}
static int hash6(int v1, int v2, int v3, int v4, int v5, int v6) {
int hash = 0;
static int hash6(int v1, int v2, int v3, int v4, int v5, int v6,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -219,8 +223,9 @@ class SystemHash {
return finish(hash);
}
static int hash7(int v1, int v2, int v3, int v4, int v5, int v6, int v7) {
int hash = 0;
static int hash7(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -232,8 +237,9 @@ class SystemHash {
}
static int hash8(
int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8) {
int hash = 0;
int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -246,8 +252,9 @@ class SystemHash {
}
static int hash9(
int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9) {
int hash = 0;
int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -261,8 +268,9 @@ class SystemHash {
}
static int hash10(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10) {
int hash = 0;
int v8, int v9, int v10,
[@Since("2.14") int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
@ -276,14 +284,334 @@ class SystemHash {
return finish(hash);
}
@Since("2.14")
static int hash11(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10, int v11,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
return finish(hash);
}
@Since("2.14")
static int hash12(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10, int v11, int v12,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
return finish(hash);
}
@Since("2.14")
static int hash13(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10, int v11, int v12, int v13,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
return finish(hash);
}
@Since("2.14")
static int hash14(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10, int v11, int v12, int v13, int v14,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
return finish(hash);
}
@Since("2.14")
static int hash15(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
int v8, int v9, int v10, int v11, int v12, int v13, int v14, int v15,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
return finish(hash);
}
@Since("2.14")
static int hash16(
int v1,
int v2,
int v3,
int v4,
int v5,
int v6,
int v7,
int v8,
int v9,
int v10,
int v11,
int v12,
int v13,
int v14,
int v15,
int v16,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
hash = combine(hash, v16);
return finish(hash);
}
@Since("2.14")
static int hash17(
int v1,
int v2,
int v3,
int v4,
int v5,
int v6,
int v7,
int v8,
int v9,
int v10,
int v11,
int v12,
int v13,
int v14,
int v15,
int v16,
int v17,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
hash = combine(hash, v16);
hash = combine(hash, v17);
return finish(hash);
}
@Since("2.14")
static int hash18(
int v1,
int v2,
int v3,
int v4,
int v5,
int v6,
int v7,
int v8,
int v9,
int v10,
int v11,
int v12,
int v13,
int v14,
int v15,
int v16,
int v17,
int v18,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
hash = combine(hash, v16);
hash = combine(hash, v17);
hash = combine(hash, v18);
return finish(hash);
}
@Since("2.14")
static int hash19(
int v1,
int v2,
int v3,
int v4,
int v5,
int v6,
int v7,
int v8,
int v9,
int v10,
int v11,
int v12,
int v13,
int v14,
int v15,
int v16,
int v17,
int v18,
int v19,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
hash = combine(hash, v16);
hash = combine(hash, v17);
hash = combine(hash, v18);
hash = combine(hash, v19);
return finish(hash);
}
@Since("2.14")
static int hash20(
int v1,
int v2,
int v3,
int v4,
int v5,
int v6,
int v7,
int v8,
int v9,
int v10,
int v11,
int v12,
int v13,
int v14,
int v15,
int v16,
int v17,
int v18,
int v19,
int v20,
[int seed = 0]) {
int hash = seed;
hash = combine(hash, v1);
hash = combine(hash, v2);
hash = combine(hash, v3);
hash = combine(hash, v4);
hash = combine(hash, v5);
hash = combine(hash, v6);
hash = combine(hash, v7);
hash = combine(hash, v8);
hash = combine(hash, v9);
hash = combine(hash, v10);
hash = combine(hash, v11);
hash = combine(hash, v12);
hash = combine(hash, v13);
hash = combine(hash, v14);
hash = combine(hash, v15);
hash = combine(hash, v16);
hash = combine(hash, v17);
hash = combine(hash, v18);
hash = combine(hash, v19);
hash = combine(hash, v20);
return finish(hash);
}
/// Bit shuffling operation to improve hash codes.
///
/// Dart integers have very simple hash codes (their value),
/// which is acceptable for the hash above because it smears the bits
/// as part of the combination.
/// However, for the unordered hash based on xor, we need to improve
/// the hash code of, e.g., integers, so a set containing the integers
/// from zero to 2^n won't always have a zero hashcode.
/// However, for the unordered hash, we need to improve
/// the hash code of, e.g., integers, to avoid collections of small integers
/// too easily having colliding hash results.
///
/// Assumes the input hash code is an unsigned 32-bit integer.
/// Found by Christopher Wellons [https://github.com/skeeto/hash-prospector].
@ -298,6 +626,17 @@ class SystemHash {
}
}
/// Sentinel values that should never be exposed outside of platform libraries.
@Since("2.14")
class SentinelValue {
final int id;
const SentinelValue(this.id);
}
/// A default value to use when only one sentinel is needed.
@Since("2.14")
const Object sentinelValue = const SentinelValue(0);
/// Given an [instance] of some generic type [T], and [extract], a first-class
/// generic function that takes the same number of type parameters as [T],
/// invokes the function with the same type arguments that were passed to T

View file

@ -0,0 +1,134 @@
// Copyright (c) 2018, 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";
import "dart:typed_data";
import "package:expect/expect.dart";
main() {
const nan = double.nan;
const inf = double.infinity;
int hash1234 = Object.hash(1, 2, 3, 4);
Expect.type<int>(hash1234);
Expect.equals(hash1234, Object.hash(1, 2, 3, 4)); // Consistent.
Expect.equals(hash1234, Object.hashAll([1, 2, 3, 4]));
Expect.equals(hash1234, Object.hashAll(Uint8List.fromList([1, 2, 3, 4])));
Expect.notEquals(hash1234, Object.hash(1, 2, 3, 4, null));
Expect.equals(Object.hash(1, 2, 3, 4, 5, 6, 7, 8, 9),
Object.hashAll([1, 2, 3, 4, 5, 6, 7, 8, 9]));
// Check that we can call `hash` with 2-20 arguments,
// and they all agree with `hashAll`.
var random = Random();
for (var i = 2; i <= 20; i++) {
var arguments = [for (var j = 0; j < i; j++) random.nextInt(256)];
var hashAll = Object.hashAll(arguments);
var hash = Function.apply(Object.hash, arguments);
Expect.equals(
hashAll,
hash,
"hashAll and hash disagrees for $i values:\n"
"$arguments");
}
// Works for all kinds of objects;
int varHash = Object.hash(
"string", 3, nan, true, null, Type, #Symbol, const Object(), function);
Expect.equals(
varHash,
Object.hashAll([
"string",
3,
nan,
true,
null,
Type,
#Symbol,
const Object(),
function
]));
// Object doesn't matter, just its hash code.
Expect.equals(hash1234,
Object.hash(Hashable(1), Hashable(2), Hashable(3), Hashable(4)));
// It's potentially possible to get a conflict, but it doesn't happen here.
Expect.notEquals("str".hashCode, Object.hashAll(["str"]));
var hash12345 = Object.hashAllUnordered([1, 2, 3, 4, 5]);
for (var p in permutations([1, 2, 3, 4, 5])) {
Expect.equals(hash12345, Object.hashAllUnordered(p));
}
Expect.notEquals(
Object.hashAllUnordered(["a", "a"]), Object.hashAllUnordered(["a"]));
Expect.notEquals(Object.hashAllUnordered(["a", "a"]),
Object.hashAllUnordered(["a", "a", "a", "a"]));
Expect.notEquals(Object.hashAllUnordered(["a", "b"]),
Object.hashAllUnordered(["a", "a", "a", "b"]));
/// Unordered hashing works for all kinds of objects.
var unorderHash = Object.hashAllUnordered([
"string",
3,
nan,
true,
null,
Type,
#Symbol,
const Object(),
function,
]);
var unorderHash2 = Object.hashAllUnordered([
true,
const Object(),
3,
function,
Type,
"string",
null,
nan,
#Symbol,
]);
Expect.equals(unorderHash, unorderHash2);
}
/// Lazily emits all permutations of [values].
///
/// Modifes [values] rather than create a new list.
/// The [values] list is guaranteed to end up in its original state
/// after all permutations have been read.
Iterable<List<T>> permutations<T>(List<T> values) {
Iterable<List<T>> recPermute(int end) sync* {
if (end == 1) {
yield values;
return;
}
for (var i = 0; i < end; i++) {
yield* recPermute(end - 1);
// Rotate values[i:].
var tmp = values.first;
for (var k = 1; k < end; k++) values[k - 1] = values[k];
values[end - 1] = tmp;
}
}
return recPermute(values.length);
}
// static function, used as constant value.
void function() {}
class Hashable {
final Object o;
Hashable(this.o);
bool operator ==(Object other) => other is Hashable && o == other.o;
int get hashCode => o.hashCode;
}

View file

@ -0,0 +1,134 @@
// Copyright (c) 2018, 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";
import "dart:typed_data";
import "package:expect/expect.dart";
main() {
const nan = double.nan;
const inf = double.infinity;
int hash1234 = Object.hash(1, 2, 3, 4);
Expect.type<int>(hash1234);
Expect.equals(hash1234, Object.hash(1, 2, 3, 4)); // Consistent.
Expect.equals(hash1234, Object.hashAll([1, 2, 3, 4]));
Expect.equals(hash1234, Object.hashAll(Uint8List.fromList([1, 2, 3, 4])));
Expect.notEquals(hash1234, Object.hash(1, 2, 3, 4, null));
Expect.equals(Object.hash(1, 2, 3, 4, 5, 6, 7, 8, 9),
Object.hashAll([1, 2, 3, 4, 5, 6, 7, 8, 9]));
// Check that we can call `hash` with 2-20 arguments,
// and they all agree with `hashAll`.
var random = Random();
for (var i = 2; i <= 20; i++) {
var arguments = [for (var j = 0; j < i; j++) random.nextInt(256)];
var hashAll = Object.hashAll(arguments);
var hash = Function.apply(Object.hash, arguments);
Expect.equals(
hashAll,
hash,
"hashAll and hash disagrees for $i values:\n"
"$arguments");
}
// Works for all kinds of objects;
int varHash = Object.hash(
"string", 3, nan, true, null, Type, #Symbol, const Object(), function);
Expect.equals(
varHash,
Object.hashAll([
"string",
3,
nan,
true,
null,
Type,
#Symbol,
const Object(),
function
]));
// Object doesn't matter, just its hash code.
Expect.equals(hash1234,
Object.hash(Hashable(1), Hashable(2), Hashable(3), Hashable(4)));
// It's potentially possible to get a conflict, but it doesn't happen here.
Expect.notEquals("str".hashCode, Object.hashAll(["str"]));
var hash12345 = Object.hashAllUnordered([1, 2, 3, 4, 5]);
for (var p in permutations([1, 2, 3, 4, 5])) {
Expect.equals(hash12345, Object.hashAllUnordered(p));
}
Expect.notEquals(
Object.hashAllUnordered(["a", "a"]), Object.hashAllUnordered(["a"]));
Expect.notEquals(Object.hashAllUnordered(["a", "a"]),
Object.hashAllUnordered(["a", "a", "a", "a"]));
Expect.notEquals(Object.hashAllUnordered(["a", "b"]),
Object.hashAllUnordered(["a", "a", "a", "b"]));
/// Unordered hashing works for all kinds of objects.
var unorderHash = Object.hashAllUnordered([
"string",
3,
nan,
true,
null,
Type,
#Symbol,
const Object(),
function,
]);
var unorderHash2 = Object.hashAllUnordered([
true,
const Object(),
3,
function,
Type,
"string",
null,
nan,
#Symbol,
]);
Expect.equals(unorderHash, unorderHash2);
}
/// Lazily emits all permutations of [values].
///
/// Modifes [values] rather than create a new list.
/// The [values] list is guaranteed to end up in its original state
/// after all permutations have been read.
Iterable<List<T>> permutations<T>(List<T> values) {
Iterable<List<T>> recPermute(int end) sync* {
if (end == 1) {
yield values;
return;
}
for (var i = 0; i < end; i++) {
yield* recPermute(end - 1);
// Rotate values[i:].
var tmp = values.first;
for (var k = 1; k < end; k++) values[k - 1] = values[k];
values[end - 1] = tmp;
}
}
return recPermute(values.length);
}
// static function, used as constant value.
void function() {}
class Hashable {
final Object o;
Hashable(this.o);
bool operator ==(Object other) => other is Hashable && o == other.o;
int get hashCode => o.hashCode;
}

View file

@ -10,11 +10,18 @@ import 'package:expect/expect.dart';
import 'stringify.dart';
import 'declarations_model.dart' as declarations_model;
Set<DeclarationMirror> inheritedDeclarations(ClassMirror? cm) {
/// Collects all declarations of [cm] and its super-classes except `Object`.
///
/// Includes static declarations of super-classes.
///
/// The `Object` class is omitted because this test should be stable against
/// changes to the platform libraries, as long as the declaration model code
/// doesn't change.
Set<DeclarationMirror> transitiveDeclarations(ClassMirror cm) {
var decls = new Set<DeclarationMirror>();
while (cm != null) {
while (cm != reflectClass(Object)) {
decls.addAll(cm.declarations.values);
cm = cm.superclass;
cm = cm.superclass!;
}
return decls;
}
@ -163,14 +170,12 @@ main() {
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'Method(s(==) in s(Object))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'Method(s(Object) in s(Object), constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass.inheritedGenerativeConstructor)'
@ -182,7 +187,6 @@ main() {
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(hashCode) in s(Object), getter)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
@ -199,8 +203,6 @@ main() {
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(noSuchMethod) in s(Object))',
'Method(s(runtimeType) in s(Object), getter)',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
@ -213,12 +215,11 @@ main() {
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(toString) in s(Object))',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)'
], inheritedDeclarations(cm).where((dm) => !dm.isPrivate).map(stringify),
], transitiveDeclarations(cm).where((dm) => !dm.isPrivate).map(stringify),
'transitive public');
// The public members of Object should be the same in all implementations, so
// we don't exclude Object here.
@ -256,113 +257,106 @@ main() {
'Variable(s(staticVariable) in s(Class), static)'
], cm.declarations.values.map(stringify), 'declarations');
Expect.setEquals(
[
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class._generativeConstructor) in s(Class), private, constructor)',
'Method(s(Class._normalFactory) in s(Class), private, static, constructor)',
'Method(s(Class._redirectingConstructor)'
' in s(Class), private, constructor)',
'Method(s(Class._redirectingFactory)'
' in s(Class), private, static, constructor)',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass._inheritedGenerativeConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedNormalFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass._inheritedRedirectingConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedRedirectingFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass.inheritedGenerativeConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedNormalFactory)'
' in s(Superclass), static, constructor)',
'Method(s(Superclass.inheritedRedirectingConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(_inheritedInstanceGetter) in s(Superclass), private, getter)',
'Method(s(_inheritedInstanceMethod) in s(Superclass), private)',
'Method(s(_inheritedInstanceSetter=) in s(Superclass), private, setter)',
'Variable(s(_inheritedInstanceVariable) in s(Superclass), private)',
'Method(s(_inheritedStaticGetter)'
' in s(Superclass), private, static, getter)',
'Method(s(_inheritedStaticMethod) in s(Superclass), private, static)',
'Method(s(_inheritedStaticSetter=)'
' in s(Superclass), private, static, setter)',
'Variable(s(_inheritedStaticVariable) in s(Superclass), private, static)',
'Method(s(_instanceGetter) in s(Class), private, getter)',
'Method(s(_instanceMethod) in s(Class), private)',
'Method(s(_instanceSetter=) in s(Class), private, setter)',
'Variable(s(_instanceVariable) in s(Class), private)',
'Method(s(_mixinInstanceGetter) in s(Mixin), private, getter)',
'Method(s(_mixinInstanceMethod) in s(Mixin), private)',
'Method(s(_mixinInstanceSetter=) in s(Mixin), private, setter)',
'Variable(s(_mixinInstanceVariable) in s(Mixin), private)',
'Method(s(_staticGetter) in s(Class), private, static, getter)',
'Method(s(_staticMethod) in s(Class), private, static)',
'Method(s(_staticSetter=) in s(Class), private, static, setter)',
'Variable(s(_staticVariable) in s(Class), private, static)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
'Variable(s(inheritedInstanceVariable) in s(Superclass))',
'Method(s(inheritedStaticGetter) in s(Superclass), static, getter)',
'Method(s(inheritedStaticMethod) in s(Superclass), static)',
'Method(s(inheritedStaticSetter=) in s(Superclass), static, setter)',
'Variable(s(inheritedStaticVariable) in s(Superclass), static)',
'Method(s(instanceGetter) in s(Class), getter)',
'Method(s(instanceMethod) in s(Class))',
'Method(s(instanceSetter=) in s(Class), setter)',
'Variable(s(instanceVariable) in s(Class))',
'Method(s(mixinInstanceGetter) in s(Mixin), getter)',
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
'Variable(s(staticVariable) in s(Class), static)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Variable(s(_mixinStaticVariable) in s(Mixin), private, static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)',
'Method(s(_mixinStaticGetter) in s(Mixin), private, static, getter)',
'Method(s(_mixinStaticSetter=) in s(Mixin), private, static, setter)',
'Method(s(_mixinStaticMethod) in s(Mixin), private, static)'
],
inheritedDeclarations(cm)
.difference(reflectClass(Object).declarations.values.toSet())
.map(stringify),
'transitive less Object');
// The private members of Object may vary across implementations, so we
// exclude the declarations of Object in this test case.
Expect.setEquals([
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class._generativeConstructor) in s(Class), private, constructor)',
'Method(s(Class._normalFactory) in s(Class), private, static, constructor)',
'Method(s(Class._redirectingConstructor)'
' in s(Class), private, constructor)',
'Method(s(Class._redirectingFactory)'
' in s(Class), private, static, constructor)',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass._inheritedGenerativeConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedNormalFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass._inheritedRedirectingConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedRedirectingFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass.inheritedGenerativeConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedNormalFactory)'
' in s(Superclass), static, constructor)',
'Method(s(Superclass.inheritedRedirectingConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(_inheritedInstanceGetter) in s(Superclass), private, getter)',
'Method(s(_inheritedInstanceMethod) in s(Superclass), private)',
'Method(s(_inheritedInstanceSetter=) in s(Superclass), private, setter)',
'Variable(s(_inheritedInstanceVariable) in s(Superclass), private)',
'Method(s(_inheritedStaticGetter)'
' in s(Superclass), private, static, getter)',
'Method(s(_inheritedStaticMethod) in s(Superclass), private, static)',
'Method(s(_inheritedStaticSetter=)'
' in s(Superclass), private, static, setter)',
'Variable(s(_inheritedStaticVariable) in s(Superclass), private, static)',
'Method(s(_instanceGetter) in s(Class), private, getter)',
'Method(s(_instanceMethod) in s(Class), private)',
'Method(s(_instanceSetter=) in s(Class), private, setter)',
'Variable(s(_instanceVariable) in s(Class), private)',
'Method(s(_mixinInstanceGetter) in s(Mixin), private, getter)',
'Method(s(_mixinInstanceMethod) in s(Mixin), private)',
'Method(s(_mixinInstanceSetter=) in s(Mixin), private, setter)',
'Variable(s(_mixinInstanceVariable) in s(Mixin), private)',
'Method(s(_staticGetter) in s(Class), private, static, getter)',
'Method(s(_staticMethod) in s(Class), private, static)',
'Method(s(_staticSetter=) in s(Class), private, static, setter)',
'Variable(s(_staticVariable) in s(Class), private, static)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
'Variable(s(inheritedInstanceVariable) in s(Superclass))',
'Method(s(inheritedStaticGetter) in s(Superclass), static, getter)',
'Method(s(inheritedStaticMethod) in s(Superclass), static)',
'Method(s(inheritedStaticSetter=) in s(Superclass), static, setter)',
'Variable(s(inheritedStaticVariable) in s(Superclass), static)',
'Method(s(instanceGetter) in s(Class), getter)',
'Method(s(instanceMethod) in s(Class))',
'Method(s(instanceSetter=) in s(Class), setter)',
'Variable(s(instanceVariable) in s(Class))',
'Method(s(mixinInstanceGetter) in s(Mixin), getter)',
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
'Variable(s(staticVariable) in s(Class), static)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Variable(s(_mixinStaticVariable) in s(Mixin), private, static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)',
'Method(s(_mixinStaticGetter) in s(Mixin), private, static, getter)',
'Method(s(_mixinStaticSetter=) in s(Mixin), private, static, setter)',
'Method(s(_mixinStaticMethod) in s(Mixin), private, static)'
], transitiveDeclarations(cm).map(stringify), 'transitive all');
}

View file

@ -12,9 +12,16 @@ import 'package:expect/expect.dart';
import 'stringify.dart';
import 'declarations_model.dart' as declarations_model;
Set<DeclarationMirror> inheritedDeclarations(ClassMirror cm) {
/// Collects all declarations of [cm] and its super-classes except `Object`.
///
/// Includes static declarations of super-classes.
///
/// The `Object` class is omitted because this test should be stable against
/// changes to the platform libraries, as long as the declaration model code
/// doesn't change.
Set<DeclarationMirror> transitiveDeclarations(ClassMirror cm) {
var decls = new Set<DeclarationMirror>();
while (cm != null) {
while (cm != reflectClass(Object)) {
decls.addAll(cm.declarations.values);
cm = cm.superclass;
}
@ -165,14 +172,12 @@ main() {
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'Method(s(==) in s(Object))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'Method(s(Object) in s(Object), constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass.inheritedGenerativeConstructor)'
@ -184,7 +189,6 @@ main() {
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(hashCode) in s(Object), getter)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
@ -201,8 +205,6 @@ main() {
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(noSuchMethod) in s(Object))',
'Method(s(runtimeType) in s(Object), getter)',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
@ -215,12 +217,11 @@ main() {
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(toString) in s(Object))',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)'
], inheritedDeclarations(cm).where((dm) => !dm.isPrivate).map(stringify),
], transitiveDeclarations(cm).where((dm) => !dm.isPrivate).map(stringify),
'transitive public');
// The public members of Object should be the same in all implementations, so
// we don't exclude Object here.
@ -258,113 +259,106 @@ main() {
'Variable(s(staticVariable) in s(Class), static)'
], cm.declarations.values.map(stringify), 'declarations');
Expect.setEquals(
[
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class._generativeConstructor) in s(Class), private, constructor)',
'Method(s(Class._normalFactory) in s(Class), private, static, constructor)',
'Method(s(Class._redirectingConstructor)'
' in s(Class), private, constructor)',
'Method(s(Class._redirectingFactory)'
' in s(Class), private, static, constructor)',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass._inheritedGenerativeConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedNormalFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass._inheritedRedirectingConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedRedirectingFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass.inheritedGenerativeConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedNormalFactory)'
' in s(Superclass), static, constructor)',
'Method(s(Superclass.inheritedRedirectingConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(_inheritedInstanceGetter) in s(Superclass), private, getter)',
'Method(s(_inheritedInstanceMethod) in s(Superclass), private)',
'Method(s(_inheritedInstanceSetter=) in s(Superclass), private, setter)',
'Variable(s(_inheritedInstanceVariable) in s(Superclass), private)',
'Method(s(_inheritedStaticGetter)'
' in s(Superclass), private, static, getter)',
'Method(s(_inheritedStaticMethod) in s(Superclass), private, static)',
'Method(s(_inheritedStaticSetter=)'
' in s(Superclass), private, static, setter)',
'Variable(s(_inheritedStaticVariable) in s(Superclass), private, static)',
'Method(s(_instanceGetter) in s(Class), private, getter)',
'Method(s(_instanceMethod) in s(Class), private)',
'Method(s(_instanceSetter=) in s(Class), private, setter)',
'Variable(s(_instanceVariable) in s(Class), private)',
'Method(s(_mixinInstanceGetter) in s(Mixin), private, getter)',
'Method(s(_mixinInstanceMethod) in s(Mixin), private)',
'Method(s(_mixinInstanceSetter=) in s(Mixin), private, setter)',
'Variable(s(_mixinInstanceVariable) in s(Mixin), private)',
'Method(s(_staticGetter) in s(Class), private, static, getter)',
'Method(s(_staticMethod) in s(Class), private, static)',
'Method(s(_staticSetter=) in s(Class), private, static, setter)',
'Variable(s(_staticVariable) in s(Class), private, static)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
'Variable(s(inheritedInstanceVariable) in s(Superclass))',
'Method(s(inheritedStaticGetter) in s(Superclass), static, getter)',
'Method(s(inheritedStaticMethod) in s(Superclass), static)',
'Method(s(inheritedStaticSetter=) in s(Superclass), static, setter)',
'Variable(s(inheritedStaticVariable) in s(Superclass), static)',
'Method(s(instanceGetter) in s(Class), getter)',
'Method(s(instanceMethod) in s(Class))',
'Method(s(instanceSetter=) in s(Class), setter)',
'Variable(s(instanceVariable) in s(Class))',
'Method(s(mixinInstanceGetter) in s(Mixin), getter)',
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
'Variable(s(staticVariable) in s(Class), static)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Variable(s(_mixinStaticVariable) in s(Mixin), private, static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)',
'Method(s(_mixinStaticGetter) in s(Mixin), private, static, getter)',
'Method(s(_mixinStaticSetter=) in s(Mixin), private, static, setter)',
'Method(s(_mixinStaticMethod) in s(Mixin), private, static)'
],
inheritedDeclarations(cm)
.difference(reflectClass(Object).declarations.values.toSet())
.map(stringify),
'transitive less Object');
// The private members of Object may vary across implementations, so we
// exclude the declarations of Object in this test case.
Expect.setEquals([
'Method(s(*) in s(Mixin))',
'Method(s(+) in s(Class))',
'Method(s(-) in s(Superclass))',
'TypeVariable(s(C) in s(Class),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Class._generativeConstructor) in s(Class), private, constructor)',
'Method(s(Class._normalFactory) in s(Class), private, static, constructor)',
'Method(s(Class._redirectingConstructor)'
' in s(Class), private, constructor)',
'Method(s(Class._redirectingFactory)'
' in s(Class), private, static, constructor)',
'Method(s(Class.generativeConstructor) in s(Class), constructor)',
'Method(s(Class.normalFactory) in s(Class), static, constructor)',
'Method(s(Class.redirectingConstructor) in s(Class), constructor)',
'Method(s(Class.redirectingFactory) in s(Class), static, constructor)',
'TypeVariable(s(S) in s(Superclass),'
' upperBound = Class(s(Object) in s(dart.core), top-level))',
'Method(s(Superclass._inheritedGenerativeConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedNormalFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass._inheritedRedirectingConstructor)'
' in s(Superclass), private, constructor)',
'Method(s(Superclass._inheritedRedirectingFactory)'
' in s(Superclass), private, static, constructor)',
'Method(s(Superclass.inheritedGenerativeConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedNormalFactory)'
' in s(Superclass), static, constructor)',
'Method(s(Superclass.inheritedRedirectingConstructor)'
' in s(Superclass), constructor)',
'Method(s(Superclass.inheritedRedirectingFactory)'
' in s(Superclass), static, constructor)',
'Method(s(_inheritedInstanceGetter) in s(Superclass), private, getter)',
'Method(s(_inheritedInstanceMethod) in s(Superclass), private)',
'Method(s(_inheritedInstanceSetter=) in s(Superclass), private, setter)',
'Variable(s(_inheritedInstanceVariable) in s(Superclass), private)',
'Method(s(_inheritedStaticGetter)'
' in s(Superclass), private, static, getter)',
'Method(s(_inheritedStaticMethod) in s(Superclass), private, static)',
'Method(s(_inheritedStaticSetter=)'
' in s(Superclass), private, static, setter)',
'Variable(s(_inheritedStaticVariable) in s(Superclass), private, static)',
'Method(s(_instanceGetter) in s(Class), private, getter)',
'Method(s(_instanceMethod) in s(Class), private)',
'Method(s(_instanceSetter=) in s(Class), private, setter)',
'Variable(s(_instanceVariable) in s(Class), private)',
'Method(s(_mixinInstanceGetter) in s(Mixin), private, getter)',
'Method(s(_mixinInstanceMethod) in s(Mixin), private)',
'Method(s(_mixinInstanceSetter=) in s(Mixin), private, setter)',
'Variable(s(_mixinInstanceVariable) in s(Mixin), private)',
'Method(s(_staticGetter) in s(Class), private, static, getter)',
'Method(s(_staticMethod) in s(Class), private, static)',
'Method(s(_staticSetter=) in s(Class), private, static, setter)',
'Variable(s(_staticVariable) in s(Class), private, static)',
'Method(s(abstractMethod) in s(Class), abstract)',
'Method(s(inheritedInstanceGetter) in s(Superclass), getter)',
'Method(s(inheritedInstanceMethod) in s(Superclass))',
'Method(s(inheritedInstanceSetter=) in s(Superclass), setter)',
'Variable(s(inheritedInstanceVariable) in s(Superclass))',
'Method(s(inheritedStaticGetter) in s(Superclass), static, getter)',
'Method(s(inheritedStaticMethod) in s(Superclass), static)',
'Method(s(inheritedStaticSetter=) in s(Superclass), static, setter)',
'Variable(s(inheritedStaticVariable) in s(Superclass), static)',
'Method(s(instanceGetter) in s(Class), getter)',
'Method(s(instanceMethod) in s(Class))',
'Method(s(instanceSetter=) in s(Class), setter)',
'Variable(s(instanceVariable) in s(Class))',
'Method(s(mixinInstanceGetter) in s(Mixin), getter)',
'Method(s(mixinInstanceMethod) in s(Mixin))',
'Method(s(mixinInstanceSetter=) in s(Mixin), setter)',
'Variable(s(mixinInstanceVariable) in s(Mixin))',
'Method(s(staticGetter) in s(Class), static, getter)',
'Method(s(staticMethod) in s(Class), static)',
'Method(s(staticSetter=) in s(Class), static, setter)',
'Variable(s(staticVariable) in s(Class), static)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin._inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), private, constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedGenerativeConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Method(s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin.inheritedRedirectingConstructor)'
' in s(test.declarations_model.Superclass'
' with test.declarations_model.Mixin), constructor)',
'Variable(s(mixinStaticVariable) in s(Mixin), static)',
'Variable(s(_mixinStaticVariable) in s(Mixin), private, static)',
'Method(s(mixinStaticGetter) in s(Mixin), static, getter)',
'Method(s(mixinStaticSetter=) in s(Mixin), static, setter)',
'Method(s(mixinStaticMethod) in s(Mixin), static)',
'Method(s(_mixinStaticGetter) in s(Mixin), private, static, getter)',
'Method(s(_mixinStaticSetter=) in s(Mixin), private, static, setter)',
'Method(s(_mixinStaticMethod) in s(Mixin), private, static)'
], transitiveDeclarations(cm).map(stringify), 'transitive all');
}