Index: tests/language/least_upper_bound_expansive_test.dart |
diff --git a/tests/language/least_upper_bound_expansive_test.dart b/tests/language/least_upper_bound_expansive_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..704b2a384faefb22cc9a892a87481f363ac20185 |
--- /dev/null |
+++ b/tests/language/least_upper_bound_expansive_test.dart |
@@ -0,0 +1,101 @@ |
+// Copyright (c) 2013, 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. |
+ |
+// Test least upper bound through type checking of conditionals. |
+ |
+class N<T> { |
+ T get n => null; |
+} |
+ |
+class C1<T> extends N<N<C1<T>>> { |
+ T get c1 => null; |
+} |
+ |
+class C2<T> extends N<N<C2<N<C2<T>>>>> { |
+ T get c2 => null; |
+} |
+ |
+/** |
+ * Test that we don't try to find the least upper bound by applying the |
+ * algorithm for finding the most specific common declaration recursively on |
+ * type arguments. |
+ * |
+ * For C1<int> and N<C1<String>> this would result in this infinite chain of |
+ * computations: |
+ * |
+ * lub(C1<int>, N<C1<String>>) = lub(N<N<C1<int>>>, N<C1<String>>) |
+ * => |
+ * lub(N<C1<int>>, C1<String>) = lub(N<C1<int>>, N<N<C1<String>>>) |
+ * => |
+ * lub(C1<int>, N<C1<String>>) = lub(N<N<C1<int>>>, N<C1<String>>>) |
+ * => ... |
+ */ |
+void testC1(bool z, C1<int> a, N<C1<String>> b) { |
+ if (z) { |
+ // The least upper bound of C1<int> and N<C1<String>> is Object since the |
+ // supertypes are |
+ // {C1<int>, N<N<C1<int>>>, Object} for C1<int> and |
+ // {N<C1<String>>, Object} for N<C1<String>> and |
+ // Object is the most specific type in the intersection of the supertypes. |
+ |
+ // Is least upper bound dynamic? |
+ (z ? a : b).z; /// 01: static type warning |
+ // Is least upper bound N<...> ? |
+ (z ? a : b).n; /// 02: static type warning |
+ // Is least upper bound C1<...> ? |
+ (z ? a : b).c1; /// 03: static type warning |
+ // Is least upper bound N<dynamic> ? |
+ (z ? a : b).n.z; /// 04: static type warning |
+ // Is least upper bound N<N<...>> ? |
+ (z ? a : b).n.n; /// 05: static type warning |
+ // Is least upper bound N<C1<...>> ? |
+ (z ? a : b).n.c1; /// 06: static type warning |
+ } |
+} |
+ |
+/** |
+ * Test that we don't try to find the least upper bound by applying the |
+ * algorithm for finding the most specific common declaration recursively on |
+ * type arguments. |
+ * |
+ * For C1<int> and N<C1<String>> this would result in this infinite and |
+ * expanding chain of computations: |
+ * |
+ * lub(C2<int>, N<C2<String>>) = lub(N<N<C2<N<C2<int>>>>>, N<C2<String>>) |
+ * => |
+ * lub(N<C2<N<C2<int>>>>, C2<String>) = |
+ * lub(N<C2<N<C2<int>>>>, N<N<C2<N<C2<String>>>>>) |
+ * => |
+ * lub(C2<N<C2<int>>>, N<C2<N<C2<String>>>>) = |
+ * lub(N<N<C2<N<C2<int>>>>>, N<C2<N<C2<String>>>>>) |
+ * => ... |
+ */ |
+ |
+void testC2(bool z, C2<int> a, N<C2<String>> b) { |
+ if (z) { |
+ // The least upper bound of C2<int> and N<C2<String>> is Object since the |
+ // supertypes are |
+ // {C2<int>, N<N<C2<N<C2<int>>>>>, Object} for C1<int> and |
+ // {N<C2<String>>, Object} for N<C1<String>> and |
+ // Object is the most specific type in the intersection of the supertypes. |
+ |
+ // Is least upper bound dynamic? |
+ (z ? a : b).z; /// 07: static type warning |
+ // Is least upper bound N<...> ? |
+ (z ? a : b).n; /// 08: static type warning |
+ // Is least upper bound C2<...> ? |
+ (z ? a : b).c2; /// 09: static type warning |
+ // Is least upper bound N<dynamic> ? |
+ (z ? a : b).n.z; /// 10: static type warning |
+ // Is least upper bound N<N<...>> ? |
+ (z ? a : b).n.n; /// 11: static type warning |
+ // Is least upper bound N<C2<...>> ? |
+ (z ? a : b).n.c2; /// 12: static type warning |
+ } |
+} |
+ |
+void main() { |
+ testC1(false, null, null); |
+ testC2(false, null, null); |
+} |