Version 2.14.0-248.0.dev
Merge commit '83376bf1ee81607a182f8558b242f1c9f4883246' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5119c30..f32243e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/sdk/lib/core/object.dart b/sdk/lib/core/object.dart
index 32b52bf..8d02d06 100644
--- a/sdk/lib/core/object.dart
+++ b/sdk/lib/core/object.dart
@@ -146,4 +146,418 @@
/// 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);
diff --git a/sdk/lib/internal/internal.dart b/sdk/lib/internal/internal.dart
index 858f1f5..0e4c898 100644
--- a/sdk/lib/internal/internal.dart
+++ b/sdk/lib/internal/internal.dart
@@ -148,7 +148,7 @@
///
/// [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 @@
/// }
/// 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
}
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 @@
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 @@
}
}
+/// 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
diff --git a/tests/corelib/object_hash_test.dart b/tests/corelib/object_hash_test.dart
new file mode 100644
index 0000000..3e9e5d8
--- /dev/null
+++ b/tests/corelib/object_hash_test.dart
@@ -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;
+}
diff --git a/tests/corelib_2/object_hash_test.dart b/tests/corelib_2/object_hash_test.dart
new file mode 100644
index 0000000..3e9e5d8
--- /dev/null
+++ b/tests/corelib_2/object_hash_test.dart
@@ -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;
+}
diff --git a/tests/lib/mirrors/class_declarations_test.dart b/tests/lib/mirrors/class_declarations_test.dart
index 83f8964..2cbf8de 100644
--- a/tests/lib/mirrors/class_declarations_test.dart
+++ b/tests/lib/mirrors/class_declarations_test.dart
@@ -10,11 +10,18 @@
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 @@
'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 @@
'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 @@
'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 @@
' 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 @@
'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');
}
diff --git a/tests/lib_2/mirrors/class_declarations_test.dart b/tests/lib_2/mirrors/class_declarations_test.dart
index fc43a76..29c1595 100644
--- a/tests/lib_2/mirrors/class_declarations_test.dart
+++ b/tests/lib_2/mirrors/class_declarations_test.dart
@@ -12,9 +12,16 @@
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 @@
'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 @@
'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 @@
'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 @@
' 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 @@
'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');
}
diff --git a/tools/VERSION b/tools/VERSION
index eeda70a..2264ce2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 247
+PRERELEASE 248
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index e9520a3..b2b13ea 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -1266,7 +1266,7 @@
"vm-precomp-ffi-qemu-linux-release-arm"
],
"meta": {
- "description": "This configuration is used for running FFI tests on qemu and FFI unit tests."
+ "description": "This configuration is used for running vm unit tests and FFI tests on qemu and FFI unit tests."
},
"steps": [
{
@@ -1303,6 +1303,13 @@
]
},
{
+ "name": "vm unit tests",
+ "arguments": [
+ "-ndartk-linux-${mode}-arm-qemu",
+ "vm/cc"
+ ]
+ },
+ {
"name": "ffi tests",
"arguments": [
"-ndartkp-linux-${mode}-arm-qemu",