Generate more mixin errors.

R=brianwilkerson@google.com

Change-Id: Ia858efb270caa5664728395d47b4e31e34a0ed91
Reviewed-on: https://dart-review.googlesource.com/74667
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index d0000d9..e403d5b 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -216,6 +216,7 @@
   CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
   CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT,
   CompileTimeErrorCode.OBJECT_CANNOT_EXTEND_ANOTHER_CLASS,
+  CompileTimeErrorCode.ON_REPEATED,
   CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_OPERATOR,
   CompileTimeErrorCode.PART_OF_NON_PART,
   CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 8f136c6..0a15bc0 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -408,6 +408,17 @@
           correction: "Try converting the getter to a method, or "
               "renaming the field to a name that doesn't conflit.");
 
+  /**
+   * 10.10 Superinterfaces: It is a compile-time error if a class `C` has two
+   * superinterfaces that are different instantiations of the same generic
+   * class. For example, a class may not have both `List<int>` and `List<num>`
+   * as superinterfaces.
+   *
+   * Parameters:
+   * 0: the name of the class implementing the conflicting interface
+   * 1: the first conflicting type
+   * 1: the second conflicting type
+   */
   static const CompileTimeErrorCode CONFLICTING_GENERIC_INTERFACES =
       const CompileTimeErrorCode(
           'CONFLICTING_GENERIC_INTERFACES',
@@ -1174,11 +1185,12 @@
               "Try specifying a class, or remove the name from the list.");
 
   /**
-   * 7.10 Superinterfaces: It is a compile-time error if a type <i>T</i> appears
-   * more than once in the implements clause of a class.
+   * 10.10 Superinterfaces: It is a compile-time error if two elements in the
+   * type list of the implements clause of a class `C` specifies the same
+   * type `T`.
    *
    * Parameters:
-   * 0: the name of the class that is implemented more than once
+   * 0: the name of the interface that is implemented more than once
    */
   static const CompileTimeErrorCode IMPLEMENTS_REPEATED =
       const CompileTimeErrorCode(
@@ -2105,6 +2117,19 @@
           "The class 'Object' can't extend any other class.");
 
   /**
+   * 10.10 Superinterfaces: It is a compile-time error if two elements in the
+   * type list of the implements clause of a class `C` specifies the same
+   * type `T`.
+   *
+   * Parameters:
+   * 0: the name of the interface that is implemented more than once
+   */
+  static const CompileTimeErrorCode ON_REPEATED = const CompileTimeErrorCode(
+      'ON_REPEATED',
+      "'{0}' can only be used in super-class constraints only once.",
+      correction: "Try removing all but one occurance of the class name.");
+
+  /**
    * 7.1.1 Operators: It is a compile-time error to declare an optional
    * parameter in an operator.
    */
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 8d11163..2bfb759 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1047,8 +1047,6 @@
 
       _initializeInitialFieldElementsMap(_enclosingClass.fields);
       _checkForFinalNotInitializedInClass(members);
-//      _checkForDuplicateDefinitionInheritance();
-//      _checkForConflictingInstanceMethodSetter(node);
 //      _checkForBadFunctionUse(node);
       return super.visitMixinDeclaration(node);
     } finally {
@@ -1353,6 +1351,8 @@
       _checkForInconsistentMethodInheritance();
       _checkForRecursiveInterfaceInheritance(_enclosingClass);
       _checkForConflictingClassMembers();
+      _checkForRepeatedType(implementsClause?.interfaces,
+          CompileTimeErrorCode.IMPLEMENTS_REPEATED);
       _checkImplementsSuperClass(implementsClause);
       _checkForMixinHasNoConstructors(node);
       _checkMixinInference(node, withClause);
@@ -2553,6 +2553,7 @@
       }
       visit(type.superclass);
       type.mixins.forEach(visit);
+      type.superclassConstraints.forEach(visit);
       type.interfaces.forEach(visit);
       visitedClasses.removeLast();
     }
@@ -5098,6 +5099,31 @@
     }
   }
 
+  void _checkForRepeatedType(List<TypeName> typeNames, ErrorCode errorCode) {
+    if (typeNames == null) {
+      return;
+    }
+
+    int count = typeNames.length;
+    List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false);
+    for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
+      detectedRepeatOnIndex[i] = false;
+    }
+    for (int i = 0; i < count; i++) {
+      if (!detectedRepeatOnIndex[i]) {
+        Element element = typeNames[i].name.staticElement;
+        for (int j = i + 1; j < count; j++) {
+          TypeName typeName = typeNames[j];
+          if (typeName.name.staticElement == element) {
+            detectedRepeatOnIndex[j] = true;
+            _errorReporter
+                .reportErrorForNode(errorCode, typeName, [typeName.name.name]);
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Check that the given rethrow [expression] is inside of a catch clause.
    *
@@ -5821,23 +5847,25 @@
    */
   void _checkMixinInheritance(MixinDeclaration node, OnClause onClause,
       ImplementsClause implementsClause) {
-    // TODO(scheglov) Verify for all mixin errors.
     // Only check for all of the inheritance logic around clauses if there
     // isn't an error code such as "Cannot implement double" already.
     if (!_checkForOnClauseErrorCodes(onClause) &&
         !_checkForImplementsClauseErrorCodes(implementsClause)) {
 //      _checkForImplicitDynamicType(superclass);
-//      _checkForNonAbstractClassInheritsAbstractMember(node.name);
       _checkForInconsistentMethodInheritance();
       _checkForRecursiveInterfaceInheritance(_enclosingClass);
       _checkForConflictingClassMembers();
-//      _checkImplementsSuperClass(implementsClause);
-//      _checkForMixinHasNoConstructors(node);
-//      _checkMixinInference(node, onClause);
-//      _checkForMixinWithConflictingPrivateMember(onClause, superclass);
-//      if (!disableConflictingGenericsCheck) {
-//        _checkForConflictingGenerics(node);
-//      }
+      _checkForRepeatedType(
+        onClause?.superclassConstraints,
+        CompileTimeErrorCode.ON_REPEATED,
+      );
+      _checkForRepeatedType(
+        implementsClause?.interfaces,
+        CompileTimeErrorCode.IMPLEMENTS_REPEATED,
+      );
+      if (!disableConflictingGenericsCheck) {
+        _checkForConflictingGenerics(node);
+      }
     }
   }
 
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a082af4..7d74d96 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -10287,29 +10287,6 @@
       if (classElement != null) {
         classElement.interfaces = interfaceTypes;
       }
-      // TODO(brianwilkerson) Move the following checks to ErrorVerifier.
-      int count = interfaces.length;
-      List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false);
-      for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
-        detectedRepeatOnIndex[i] = false;
-      }
-      for (int i = 0; i < count; i++) {
-        TypeName typeName = interfaces[i];
-        if (!detectedRepeatOnIndex[i]) {
-          Element element = typeName.name.staticElement;
-          for (int j = i + 1; j < count; j++) {
-            TypeName typeName2 = interfaces[j];
-            Identifier identifier2 = typeName2.name;
-            String name2 = identifier2.name;
-            Element element2 = identifier2.staticElement;
-            if (element != null && element == element2) {
-              detectedRepeatOnIndex[j] = true;
-              errorReporter.reportErrorForNode(
-                  CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
-            }
-          }
-        }
-      }
     }
   }
 
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
index fdda0cd..4e73768 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
@@ -18,31 +18,6 @@
   bool get enableNewAnalysisDriver => true;
 
   @override // Passes with driver
-  test_conflictingGenericInterfaces_simple() =>
-      super.test_conflictingGenericInterfaces_simple();
-
-  @override // Passes with driver
-  test_conflictingGenericInterfaces_viaMixin() =>
-      super.test_conflictingGenericInterfaces_viaMixin();
-
-  @override // Passes with driver
-  test_mixinInference_conflictingSubstitution() =>
-      super.test_mixinInference_conflictingSubstitution();
-
-  @override // Passes with driver
-  test_mixinInference_doNotIgnorePreviousExplicitMixins() =>
-      super.test_mixinInference_doNotIgnorePreviousExplicitMixins();
-
-  @override // Passes with driver
-  test_mixinInference_impossibleSubstitution() =>
-      super.test_mixinInference_impossibleSubstitution();
-
-  @override // Passes with driver
-  test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() =>
-      super
-          .test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause();
-
-  @override // Passes with driver
   test_mixinInference_recursiveSubtypeCheck() =>
       super.test_mixinInference_recursiveSubtypeCheck();
 }
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 3ac833f..1955f4a 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -730,30 +730,6 @@
     assertNoErrors(source);
   }
 
-  @failingTest // Does not work with old task model
-  test_conflictingGenericInterfaces_simple() async {
-    Source source = addSource('''
-class I<T> {}
-class A implements I<int> {}
-class B implements I<String> {}
-class C extends A implements B {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
-  }
-
-  @failingTest // Does not work with old task model
-  test_conflictingGenericInterfaces_viaMixin() async {
-    Source source = addSource('''
-class I<T> {}
-class A implements I<int> {}
-class B implements I<String> {}
-class C extends A with B {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
-  }
-
   test_conflictingTypeVariableAndClass() async {
     Source source = addSource(r'''
 class T<T> {
@@ -2769,28 +2745,6 @@
     verify([source]);
   }
 
-  test_implementsRepeated() async {
-    Source source = addSource(r'''
-class A {}
-class B implements A, A {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [CompileTimeErrorCode.IMPLEMENTS_REPEATED]);
-    verify([source]);
-  }
-
-  test_implementsRepeated_3times() async {
-    Source source = addSource(r'''
-class A {} class C{}
-class B implements A, A, A, A {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.IMPLEMENTS_REPEATED,
-      CompileTimeErrorCode.IMPLEMENTS_REPEATED,
-      CompileTimeErrorCode.IMPLEMENTS_REPEATED
-    ]);
-    verify([source]);
-  }
-
   test_implementsSuperClass() async {
     Source source = addSource(r'''
 class A {}
@@ -3949,56 +3903,6 @@
     verify([source]);
   }
 
-  @failingTest // Does not work with old task model
-  test_mixinInference_conflictingSubstitution() async {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.enableSuperMixins = true;
-    resetWith(options: options);
-    Source source = addSource('''
-abstract class A<T> {}
-class M<T> extends A<Map<T, T>> {}
-class C extends A<Map<int, String>> with M {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
-      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
-    ]);
-  }
-
-  @failingTest // Does not work with old task model
-  test_mixinInference_doNotIgnorePreviousExplicitMixins() async {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.enableSuperMixins = true;
-    resetWith(options: options);
-    Source source = addSource('''
-class A extends Object with B<String>, C {}
-class B<T> {}
-class C<T> extends B<T> {}
-''');
-    var analysisResult = await computeAnalysisResult(source);
-    assertNoErrors(source);
-    var mixins = analysisResult.unit.declaredElement.getType('A').mixins;
-    expect(mixins[1].toString(), 'C<String>');
-  }
-
-  @failingTest // Does not work with old task model
-  test_mixinInference_impossibleSubstitution() async {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.enableSuperMixins = true;
-    resetWith(options: options);
-    Source source = addSource('''
-abstract class A<T> {}
-class M<T> extends A<Map<T, T>> {}
-class C extends A<List<int>> with M {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
-      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
-    ]);
-  }
-
   test_mixinInference_matchingClass() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
@@ -4043,24 +3947,6 @@
         source, [CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS]);
   }
 
-  @failingTest // Does not work with old task model
-  test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() async {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.enableSuperMixins = true;
-    resetWith(options: options);
-    Source source = addSource('''
-abstract class A<T> {}
-class B {}
-class M<T> extends A<T> {}
-class C extends Object with M implements A<B> {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS,
-      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
-    ]);
-  }
-
   test_mixinInference_noMatchingClass_namedMixinApplication() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
diff --git a/pkg/analyzer/test/src/dart/resolution/class_test.dart b/pkg/analyzer/test/src/dart/resolution/class_test.dart
index f3496cc..533ae56 100644
--- a/pkg/analyzer/test/src/dart/resolution/class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/class_test.dart
@@ -251,6 +251,28 @@
     assertElement(findNode.simple('foo = 0;'), findElement.setter('foo'));
   }
 
+  test_conflictingGenericInterfaces_simple() async {
+    addTestFile('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+class C extends A implements B {}
+''');
+    await resolveTestFile();
+    assertTestErrors([CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
+  }
+
+  test_conflictingGenericInterfaces_viaMixin() async {
+    addTestFile('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+class C extends A with B {}
+''');
+    await resolveTestFile();
+    assertTestErrors([CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
+  }
+
   test_error_conflictingConstructorAndStaticField_field() async {
     addTestFile(r'''
 class C {
@@ -1081,6 +1103,31 @@
     assertElementType(a.supertype, objectType);
   }
 
+  test_error_implementsRepeated() async {
+    addTestFile(r'''
+class A {}
+class B implements A, A {} // ref
+''');
+    await resolveTestFile();
+    assertTestErrors([CompileTimeErrorCode.IMPLEMENTS_REPEATED]);
+
+    var a = findElement.class_('A');
+    assertTypeName(findNode.typeName('A, A {} // ref'), a, 'A');
+    assertTypeName(findNode.typeName('A {} // ref'), a, 'A');
+  }
+
+  test_error_implementsRepeated_3times() async {
+    addTestFile(r'''
+class A {} class C{}
+class B implements A, A, A, A {}''');
+    await resolveTestFile();
+    assertTestErrors([
+      CompileTimeErrorCode.IMPLEMENTS_REPEATED,
+      CompileTimeErrorCode.IMPLEMENTS_REPEATED,
+      CompileTimeErrorCode.IMPLEMENTS_REPEATED
+    ]);
+  }
+
   test_error_memberWithClassName_getter() async {
     addTestFile(r'''
 class C {
@@ -1210,6 +1257,62 @@
     ]);
   }
 
+  test_mixinInference_conflictingSubstitution() async {
+    setAnalysisOptions(enableSuperMixins: true);
+    addTestFile('''
+abstract class A<T> {}
+class M<T> extends A<Map<T, T>> {}
+class C extends A<Map<int, String>> with M {}
+''');
+    await resolveTestFile();
+    assertTestErrors([
+      CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
+      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
+    ]);
+  }
+
+  test_mixinInference_doNotIgnorePreviousExplicitMixins() async {
+    setAnalysisOptions(enableSuperMixins: true);
+    addTestFile('''
+class A extends Object with B<String>, C {}
+class B<T> {}
+class C<T> extends B<T> {}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+    var mixins = result.unit.declaredElement.getType('A').mixins;
+    expect(mixins[1].toString(), 'C<String>');
+  }
+
+  test_mixinInference_impossibleSubstitution() async {
+    setAnalysisOptions(enableSuperMixins: true);
+    addTestFile('''
+abstract class A<T> {}
+class M<T> extends A<Map<T, T>> {}
+class C extends A<List<int>> with M {}
+''');
+    await resolveTestFile();
+    assertTestErrors([
+      CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
+      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
+    ]);
+  }
+
+  test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() async {
+    setAnalysisOptions(enableSuperMixins: true);
+    addTestFile('''
+abstract class A<T> {}
+class B {}
+class M<T> extends A<T> {}
+class C extends Object with M implements A<B> {}
+''');
+    await resolveTestFile();
+    assertTestErrors([
+      CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS,
+      CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
+    ]);
+  }
+
   test_recursiveInterfaceInheritance_extends() async {
     addTestFile(r'''
 class A extends B {}
@@ -1438,4 +1541,35 @@
 
 @reflectiveTest
 class ClassTaskResolutionTest extends TaskResolutionTest
-    with ClassResolutionMixin {}
+    with ClassResolutionMixin {
+  @failingTest
+  test_conflictingGenericInterfaces_simple() {
+    return super.test_conflictingGenericInterfaces_simple();
+  }
+
+  @failingTest
+  test_conflictingGenericInterfaces_viaMixin() {
+    return super.test_conflictingGenericInterfaces_viaMixin();
+  }
+
+  @failingTest
+  test_mixinInference_conflictingSubstitution() {
+    return super.test_mixinInference_conflictingSubstitution();
+  }
+
+  @failingTest
+  test_mixinInference_doNotIgnorePreviousExplicitMixins() {
+    return super.test_mixinInference_doNotIgnorePreviousExplicitMixins();
+  }
+
+  @failingTest
+  test_mixinInference_impossibleSubstitution() {
+    return super.test_mixinInference_impossibleSubstitution();
+  }
+
+  @failingTest
+  test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() {
+    return super
+        .test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause();
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 180ea83..92750a6 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -139,6 +139,17 @@
     assertTypeNull(aRef);
   }
 
+  test_conflictingGenericInterfaces() async {
+    addTestFile('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+mixin M on A implements B {}
+''');
+    await resolveTestFile();
+    assertTestErrors([CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
+  }
+
   test_element() async {
     addTestFile(r'''
 mixin M {}
@@ -743,6 +754,16 @@
     assertTypeName(typeRef, null, 'void');
   }
 
+  test_error_implementsRepeated() async {
+    addTestFile(r'''
+class A {}
+mixin M implements A, A {}
+''');
+    await resolveTestFile();
+    CompileTimeErrorCode.IMPLEMENTS_REPEATED;
+    assertTestErrors([CompileTimeErrorCode.IMPLEMENTS_REPEATED]);
+  }
+
   test_error_memberWithClassName_getter() async {
     addTestFile(r'''
 mixin M {
@@ -1108,6 +1129,16 @@
     assertElementTypes(b.superclassConstraints, [a.type]);
   }
 
+  test_error_onRepeated() async {
+    addTestFile(r'''
+class A {}
+mixin M on A, A {}
+''');
+    await resolveTestFile();
+    CompileTimeErrorCode.IMPLEMENTS_REPEATED;
+    assertTestErrors([CompileTimeErrorCode.ON_REPEATED]);
+  }
+
   test_error_undefinedSuperMethod() async {
     addTestFile(r'''
 class A {}
@@ -1497,4 +1528,9 @@
 
 @reflectiveTest
 class MixinTaskResolutionTest extends TaskResolutionTest
-    with MixinResolutionMixin {}
+    with MixinResolutionMixin {
+  @failingTest
+  test_conflictingGenericInterfaces() {
+    return super.test_conflictingGenericInterfaces();
+  }
+}