Initial valid inference checks

Change-Id: I75c3f3a4072aeaa6f27d399196ba3c57e79fecbb
Reviewed-on: https://dart-review.googlesource.com/74017
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/tests/language_2/language_2.status b/tests/language_2/language_2.status
index 03666e2..50bc221 100644
--- a/tests/language_2/language_2.status
+++ b/tests/language_2/language_2.status
@@ -14,6 +14,7 @@
 
 [ $compiler == dart2analyzer ]
 double_literals/implicit_double_context_test: CompileTimeError # Needs triage, see Issue #34444
+mixin_declaration/mixin_declaration_inference_valid_classes_test: CompileTimeError # https://github.com/dart-lang/sdk/issues/34164
 
 [ $compiler != dart2analyzer ]
 switch_case_warn_test: Skip # Analyzer only, see language_analyzer2.status
@@ -51,6 +52,9 @@
 type_checks_in_factory_method_test: SkipByDesign # Requires checked mode.
 
 [ $fasta ]
+mixin_declaration/mixin_declaration_inference_invalid_05_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/34165
+mixin_declaration/mixin_declaration_inference_invalid_07_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/34165
+mixin_declaration/mixin_declaration_inference_invalid_10_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/34165
 partial_instantiation_static_bounds_check_test/01: MissingCompileTimeError # Issue 34327
 partial_instantiation_static_bounds_check_test/02: MissingCompileTimeError # Issue 34327
 partial_instantiation_static_bounds_check_test/03: MissingCompileTimeError # Issue 34327
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index 21a626b..29b9a9c 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -104,6 +104,15 @@
 issue32353_test: RuntimeError
 label_test: RuntimeError
 left_shift_test: RuntimeError # Ints and doubles are unified.
+mixin_declaration/mixin_declaration_inference_invalid_03_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_04_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_05_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_06_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_07_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_08_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_09_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_invalid_10_test: MissingCompileTimeError   # https://github.com/dart-lang/sdk/issues/34167
+mixin_declaration/mixin_declaration_inference_valid_classes_test: CompileTimeError   # https://github.com/dart-lang/sdk/issues/34164
 mixin_declaration/mixin_declaration_invalid_superinvocation_test/10: CompileTimeError    # Analyzer chooses wrong(?) super method.
 mixin_forwarding_constructor4_test/01: CompileTimeError # See issue 15101
 mixin_forwarding_constructor4_test/02: CompileTimeError # See issue 15101
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 2c1858f..a8212e0 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -271,6 +271,7 @@
 malbounded_type_test_test/00: MissingCompileTimeError # Issue 33308
 malbounded_type_test_test/01: MissingCompileTimeError # Issue 33308
 malbounded_type_test_test/02: MissingCompileTimeError # Issue 33308
+mixin_declaration/mixin_declaration_inference_valid_classes_test: DartkCrash, Crash # https://github.com/dart-lang/sdk/issues/34165
 mixin_invalid_bound2_test/02: MissingCompileTimeError # Issue 33308
 mixin_invalid_bound2_test/03: MissingCompileTimeError # Issue 33308
 mixin_invalid_bound2_test/04: MissingCompileTimeError # Issue 33308
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_00_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_00_test.dart
new file mode 100644
index 0000000..5d99d2f
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_00_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> on I<T> {}
+
+///////////////////////////////////////////////////////
+// Inference happens from superclasses to subclasses
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 extends I with M0<int> {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_01_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_01_test.dart
new file mode 100644
index 0000000..749d813
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_01_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> on I<T> {}
+
+mixin M1<T> on I<T> {}
+
+///////////////////////////////////////////////////////
+// Inference happens from superclasses to subclasses
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 extends I with M0, M1<int> {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_02_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_02_test.dart
new file mode 100644
index 0000000..01ae1ae
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_02_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> implements I<T> {}
+
+mixin M1<T> on I<T> {}
+
+///////////////////////////////////////////////////////
+// Inference happens from superclasses to subclasses
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 with M0, M1<int> {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_03_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_03_test.dart
new file mode 100644
index 0000000..5741700
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_03_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> implements I<T> {}
+
+//////////////////////////////////////////////////////
+// Inference happens from superclasses to subclasses
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 extends Object with M0 implements I<int> {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_04_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_04_test.dart
new file mode 100644
index 0000000..50d017b
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_04_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> implements I<T> {}
+
+//////////////////////////////////////////////////////
+// Inference does not use implements constraints on mixin
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 with M0 implements I<int> {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_05_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_05_test.dart
new file mode 100644
index 0000000..38e681e
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_05_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<T> implements I<T> {}
+
+mixin M1<T> implements I<T> {}
+
+//////////////////////////////////////////////////////
+// Inference does not use implements constraints on mixin
+///////////////////////////////////////////////////////
+
+// Error since class hierarchy is inconsistent
+class A00 extends I<int> with M0<int>, M1 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_06_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_06_test.dart
new file mode 100644
index 0000000..14c2416
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_06_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+class I<X> {}
+class J<X> {}
+
+mixin M0<S, T> implements I<S>, J<T> {}
+
+mixin M1<S, T> implements I<S>, J<T> {}
+
+//////////////////////////////////////////////////////
+// Inference does not use implements constraints on mixin
+///////////////////////////////////////////////////////
+
+class A00 extends I<int> with M0 {}
+
+class A01 extends J<int> with M1 {}
+
+// Error since class hierarchy is inconsistent
+class A02 extends A00 implements A01 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_07_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_07_test.dart
new file mode 100644
index 0000000..9b16c66
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_07_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+class I<X> {}
+
+mixin M0<X, Y extends Comparable<Y>> on I<X> {}
+
+class M1 implements I<int> {}
+
+//////////////////////////////////////////////////////
+// Inference does not produce super-bounded types
+///////////////////////////////////////////////////////
+
+// M0 is inferred as M0<int, Comparable<dynamic>>
+// Error since super-bounded type not allowed
+class A extends M1 with M0 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_08_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_08_test.dart
new file mode 100644
index 0000000..23da50d3
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_08_test.dart
@@ -0,0 +1,21 @@
+// 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.
+
+class I<X, Y> {}
+
+mixin M0<T> implements I<T, int> {}
+
+mixin M1<T> implements I<String, T> {}
+
+//////////////////////////////////////////////////////
+// Inference is not bi-directional
+///////////////////////////////////////////////////////
+
+
+// M0<String>, M1<int> is a solution, but we shouldn't find it
+// M0 inferred as M0<dynamic>
+// M1 inferred as M1<dynamic>
+class A with M0, M1 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_09_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_09_test.dart
new file mode 100644
index 0000000..0ebdf97
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_09_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+class I<X, Y> {}
+
+mixin M0<T> implements I<T, List<T>> {}
+
+mixin M1<T> implements I<List<T>, T> {}
+
+//////////////////////////////////////////////////////
+// Inference does not produce infinite types
+///////////////////////////////////////////////////////
+
+// No solution, even with unification, since solution
+// requires that I<List<U0>, U0> == I<U1, List<U1>>
+// for some U0, U1, and hence that:
+// U0 = List<U1>
+// U1 = List<U0>
+// which has no finite solution
+class A with M0, M1 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_10_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_10_test.dart
new file mode 100644
index 0000000..00563ef
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_invalid_10_test.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class I<T> {}
+class J<T> {}
+mixin M0<T> implements I<T>, J<T> {}
+
+//////////////////////////////////////////////////////
+// Over-constrained results are caught
+///////////////////////////////////////////////////////
+
+class A with I<int>, J<double>, M0 {} /*@compile-error=unspecified*/
+
+void main() {}
\ No newline at end of file
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_inference_valid_classes_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_inference_valid_classes_test.dart
new file mode 100644
index 0000000..e7eeb50
--- /dev/null
+++ b/tests/language_2/mixin_declaration/mixin_declaration_inference_valid_classes_test.dart
@@ -0,0 +1,396 @@
+// 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 "package:expect/expect.dart";
+
+class I<X> {}
+
+class C0<T> extends I<T> {}
+class C1<T> implements I<T> {}
+
+mixin M0<T> on I<T> {
+}
+
+mixin M1<T> on I<T> {
+  T Function(T) get value => null;
+}
+
+mixin M2<T> implements I<T> {}
+
+mixin M3<T> on I<T> {}
+
+class J<X> {}
+class C2 extends C1<int> implements J<double> {}
+class C3 extends J<double> {}
+
+mixin M4<S, T> on I<S>, J<T> {
+  S Function(S) get value0 => null;
+  T Function(T) get value1 => null;
+}
+
+///////////////////////////////////////////////////////
+// Inference of a single mixin from a super class works
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class A00 extends I<int> with M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class A01 extends C0<int> with M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class A02 extends C1<int> with M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Inference of a single mixin from another mixin works
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class B00 extends Object with I<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B01 extends Object with C1<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B02 extends I<int> with M0<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B03 extends Object with M2<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Inference of a single mixin from another mixin works
+// with the shorthand syntax
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class C00 with I<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C01 with C1<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C02 with I<int>, M0<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C03 with M2<int>, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Inference of two mixins from a super class works
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class A10 extends I<int> with M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class A11 extends C0<int> with M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class A12 extends C1<int> with M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Inference of two mixins from another mixin works
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class B10 extends Object with I<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B11 extends Object with C1<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B12 extends I<int> with M0<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class B13 extends Object with M2<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Inference of a single mixin from another mixin works
+// with the shorthand syntax
+///////////////////////////////////////////////////////
+
+// M1 is inferred as M1<int>
+class C10 with I<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C11 with C1<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C12 with I<int>, M0<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+// M1 is inferred as M1<int>
+class C13 with M2<int>, M3, M1 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+  }
+}
+
+
+///////////////////////////////////////////////////////
+// Inference from multiple constraints works
+///////////////////////////////////////////////////////
+
+
+// M4 is inferred as M4<int, double>
+class A20 extends C2 with M4 {
+  void check() {
+    // Verify that M4.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M4.T is exactly double
+    double Function(double) f1 = this.value1;
+  }
+}
+
+// M4 is inferred as M4<int, double>
+class A21 extends C3 with M2<int>, M4 {
+  void check() {
+    // Verify that M4.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M4.T is exactly double
+    double Function(double) f1 = this.value0;
+  }
+}
+
+// M4 is inferred as M4<int, double>
+class A22 extends C2 with M1, M4 {
+  void check() {
+    // Verify that M1.T is exactly int
+    int Function(int) f = this.value;
+    // Verify that M4.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M4.T is exactly double
+    double Function(double) f1 = this.value1;
+  }
+}
+
+mixin _M5<T> on I<T> implements J<T> {}
+
+// Inference here puts J<int> in the superclass hierarchy
+class _A23 extends C0<int> with _M5 {}
+
+// Inference here should get J<int> for M4.T
+// if inference for _M5 is done first (correctly)
+// and otherwise J<dynamic>
+class A23 extends _A23 with M4 {
+  void check() {
+    // Verify that M4.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M4.T is exactly int
+    int Function(int) f1 = this.value1;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Unconstrained parameters go to bounds
+///////////////////////////////////////////////////////
+
+mixin M5<S, T extends String> on I<S> {
+  S Function(S) get value0 => null;
+  T Function(T) get value1 => null;
+}
+
+mixin M6<S, T extends S> on I<S> {
+  S Function(S) get value0 => null;
+  T Function(T) get value1 => null;
+}
+
+// M5 is inferred as M5<int, String>
+class A30 extends C0<int> with M5 {
+  void check() {
+    // Verify that M5.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M5.T is exactly String
+    String Function(String) f1 = this.value1;
+  }
+}
+
+// M6 is inferred as M6<int, int>
+class A31 extends C0<int> with M6 {
+  void check() {
+    // Verify that M6.S is exactly int
+    int Function(int) f0 = this.value0;
+    // Verify that M6.T is exactly int
+    int Function(int) f1 = this.value1;
+  }
+}
+
+///////////////////////////////////////////////////////
+// Non-trivial constraints should work
+///////////////////////////////////////////////////////
+
+mixin M7<T> on I<List<T>> {
+  T Function(T) get value0 => null;
+}
+
+mixin M8<T> on I<Iterable<T>> {
+  T Function(T) get value0 => null;
+}
+
+class A40<T> extends I<List<T>> {}
+
+class A41<T> extends A40<Map<T, T>> {}
+
+// M7 is inferred as M7<Map<int, int>>
+class A42 extends A41<int> with M7 {
+  void check() {
+    // Verify that M7.T is exactly Map<int, int>
+    Map<int, int> Function(Map<int, int>) f1 = this.value0;
+  }
+}
+
+// M8 is inferred as M8<Map<int, int>>
+class A43 extends A41<int> with M8 {
+  void check() {
+    // Verify that M8.T is exactly Map<int, int>
+    Map<int, int> Function(Map<int, int>) f1 = this.value0;
+  }
+}
+
+
+void main() {
+  Expect.type<M1<int>>(new A00()..check());
+  Expect.type<M1<int>>(new A01()..check());
+  Expect.type<M1<int>>(new A02()..check());
+
+  Expect.type<M1<int>>(new B00()..check());
+  Expect.type<M1<int>>(new B01()..check());
+  Expect.type<M1<int>>(new B02()..check());
+  Expect.type<M1<int>>(new B03()..check());
+
+  Expect.type<M1<int>>(new C00()..check());
+  Expect.type<M1<int>>(new C01()..check());
+  Expect.type<M1<int>>(new C02()..check());
+  Expect.type<M1<int>>(new C03()..check());
+
+  Expect.type<M1<int>>(new A10()..check());
+  Expect.type<M1<int>>(new A11()..check());
+  Expect.type<M1<int>>(new A12()..check());
+
+  Expect.type<M1<int>>(new B10()..check());
+  Expect.type<M1<int>>(new B11()..check());
+  Expect.type<M1<int>>(new B12()..check());
+  Expect.type<M1<int>>(new B13()..check());
+
+  Expect.type<M1<int>>(new C10()..check());
+  Expect.type<M1<int>>(new C11()..check());
+  Expect.type<M1<int>>(new C12()..check());
+  Expect.type<M1<int>>(new C13()..check());
+
+  Expect.type<M4<int, double>>(new A20()..check());
+  Expect.type<M4<int, double>>(new A21()..check());
+  Expect.type<M4<int, double>>(new A22()..check());
+  Expect.type<M1<int>>(new A22()..check());
+  Expect.type<M4<int, int>>(new A23()..check());
+
+  Expect.type<M5<int, String>>(new A30()..check());
+  Expect.type<M6<int, int>>(new A31()..check());
+
+  Expect.type<M7<Map<int, int>>>(new A42()..check());
+  Expect.type<M8<Map<int, int>>>(new A43()..check());
+}
\ No newline at end of file