Elements. Use combineSignatureTypes() for inheritance inference.

When we use it, we already have a method declared, it is just that
its types are not specified. OTOH, combineSignatures() creates
a new sythetic fragment / element.

Change-Id: I5f735c1c09ade12c12294c3a6fd6894ba706eac0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/431980
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 797bab0..723ba2f 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -107,21 +107,10 @@
     var targetLibrary = targetClass.library;
     var typeSystem = targetLibrary.typeSystem;
 
-    var validOverrides = <ExecutableElementOrMember>[];
-    for (var i = 0; i < candidates.length; i++) {
-      ExecutableElementOrMember? validOverride = candidates[i];
-      var validOverrideType = validOverride.type;
-      for (var j = 0; j < candidates.length; j++) {
-        var candidate = candidates[j];
-        if (!typeSystem.isSubtypeOf(validOverrideType, candidate.type)) {
-          validOverride = null;
-          break;
-        }
-      }
-      if (validOverride != null) {
-        validOverrides.add(validOverride);
-      }
-    }
+    var validOverrides = _getValidOverrides(
+      candidates: candidates,
+      typeSystem: typeSystem,
+    );
 
     if (validOverrides.isEmpty) {
       conflicts?.add(CandidatesConflict(name: name, candidates: candidates));
@@ -134,6 +123,47 @@
     return _topMerge(typeSystem, targetClass, validOverrides);
   }
 
+  /// Combine types of [candidates] into a single most specific type.
+  ///
+  /// If such signature does not exist, return `null`, and if [conflicts] is
+  /// not `null`, add a new [Conflict] to it.
+  FunctionTypeImpl? combineSignatureTypes({
+    required TypeSystemImpl typeSystem,
+    required List<ExecutableElementOrMember> candidates,
+    required Name name,
+    List<Conflict>? conflicts,
+  }) {
+    if (candidates.length == 1) {
+      return candidates[0].type;
+    }
+
+    var validOverrides = _getValidOverrides(
+      typeSystem: typeSystem,
+      candidates: candidates,
+    );
+
+    if (validOverrides.isEmpty) {
+      conflicts?.add(CandidatesConflict(name: name, candidates: candidates));
+      return null;
+    }
+
+    // Often there is one most specific signature.
+    var firstType = validOverrides[0].type;
+    if (validOverrides.length == 1) {
+      return firstType;
+    }
+
+    // Maybe more than valid, but the same type.
+    if (validOverrides.every((e) => e.type == firstType)) {
+      return firstType;
+    }
+
+    return _topMergeSignatureTypes(
+      typeSystem: typeSystem,
+      validOverrides: validOverrides,
+    );
+  }
+
   /// Return the result of [getInherited2] with [type] substitution.
   ExecutableElementOrMember? getInherited(InterfaceType type, Name name) {
     type as InterfaceTypeImpl;
@@ -1170,25 +1200,14 @@
     }
 
     var firstType = first.type;
-    var allTypesEqual = true;
-    for (var executable in validOverrides) {
-      if (executable.type != firstType) {
-        allTypesEqual = false;
-        break;
-      }
-    }
-
-    if (allTypesEqual) {
+    if (validOverrides.every((e) => e.type == firstType)) {
       return first;
     }
 
-    var resultType = validOverrides
-        .map((e) {
-          return typeSystem.normalizeFunctionType(e.type);
-        })
-        .reduce((previous, next) {
-          return typeSystem.topMerge(previous, next) as FunctionTypeImpl;
-        });
+    var resultType = _topMergeSignatureTypes(
+      typeSystem: typeSystem,
+      validOverrides: validOverrides,
+    );
 
     for (var executable in validOverrides) {
       if (executable.type == resultType) {
@@ -1267,10 +1286,42 @@
     return declared;
   }
 
+  /// Returns executables that are valid overrides of [candidates].
+  static List<ExecutableElementOrMember> _getValidOverrides({
+    required TypeSystemImpl typeSystem,
+    required List<ExecutableElementOrMember> candidates,
+  }) {
+    var validOverrides = <ExecutableElementOrMember>[];
+    outer:
+    for (var i = 0; i < candidates.length; i++) {
+      var validOverride = candidates[i];
+      var validOverrideType = validOverride.type;
+      for (var j = 0; j < candidates.length; j++) {
+        var candidate = candidates[j];
+        if (!typeSystem.isSubtypeOf(validOverrideType, candidate.type)) {
+          continue outer;
+        }
+      }
+      validOverrides.add(validOverride);
+    }
+    return validOverrides;
+  }
+
   static bool _isDeclaredInObject(ExecutableElementOrMember element) {
     var enclosing = element.asElement2.enclosingElement;
     return enclosing is ClassElement && enclosing.isDartCoreObject;
   }
+
+  static FunctionTypeImpl _topMergeSignatureTypes({
+    required TypeSystemImpl typeSystem,
+    required List<ExecutableElementOrMember> validOverrides,
+  }) {
+    return validOverrides
+        .map((e) => typeSystem.normalizeFunctionType(e.type))
+        .reduce((previous, next) {
+          return typeSystem.topMerge(previous, next) as FunctionTypeImpl;
+        });
+  }
 }
 
 /// The instance interface of an [InterfaceType].
diff --git a/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart b/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
index 0a93961..3543dce 100644
--- a/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
+++ b/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
@@ -2,12 +2,12 @@
 // 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:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/error/inference_error.dart';
 import 'package:analyzer/src/util/collection.dart';
 import 'package:analyzer/src/utilities/extensions/element.dart';
@@ -24,6 +24,10 @@
   /// Initialize a newly create inferrer.
   InstanceMemberInferrer(this.inheritance);
 
+  TypeSystemImpl get typeSystem {
+    return currentInterfaceElement.library.typeSystem;
+  }
+
   /// Infer type information for all of the instance members in the given
   /// compilation [unit].
   void inferCompilationUnit(LibraryFragmentImpl unit) {
@@ -132,25 +136,25 @@
     overriddenSetters ??= const [];
 
     TypeImpl combinedGetterType() {
-      var combinedGetter = inheritance.combineSignatures(
-        targetClass: currentInterfaceElement,
+      var combinedGetterType = inheritance.combineSignatureTypes(
+        typeSystem: typeSystem,
         candidates: overriddenGetters!,
         name: getterName,
       );
-      if (combinedGetter != null) {
-        return combinedGetter.returnType;
+      if (combinedGetterType != null) {
+        return combinedGetterType.returnType;
       }
       return DynamicTypeImpl.instance;
     }
 
     TypeImpl combinedSetterType() {
-      var combinedSetter = inheritance.combineSignatures(
-        targetClass: currentInterfaceElement,
+      var combinedSetterType = inheritance.combineSignatureTypes(
+        typeSystem: typeSystem,
         candidates: overriddenSetters!,
         name: setterName,
       );
-      if (combinedSetter != null) {
-        var parameters = combinedSetter.parameters;
+      if (combinedSetterType != null) {
+        var parameters = combinedSetterType.parameters;
         if (parameters.isNotEmpty) {
           return parameters[0].type;
         }
@@ -416,18 +420,17 @@
         element.parameters.any((e) => e.hasImplicitType);
     if (hasImplicitType) {
       var conflicts = <Conflict>[];
-      var combinedSignature = inheritance.combineSignatures(
-        targetClass: currentInterfaceElement,
+      combinedSignatureType = inheritance.combineSignatureTypes(
+        typeSystem: typeSystem,
         candidates: overriddenElements,
         name: name,
         conflicts: conflicts,
       );
-      if (combinedSignature != null) {
+      if (combinedSignatureType != null) {
         combinedSignatureType = _toOverriddenFunctionType(
           element,
-          combinedSignature,
+          combinedSignatureType,
         );
-        if (combinedSignatureType != null) {}
       } else {
         var conflictExplanation = '<unknown>';
         if (conflicts.length == 1) {
@@ -714,8 +717,8 @@
     }
   }
 
-  /// Return the [FunctionType] of the [overriddenElement] that [element]
-  /// overrides. Return `null`, in case of type parameters inconsistency.
+  /// Return [overriddenType] with type parameters substituted to [element].
+  /// Return `null`, in case of type parameters inconsistency.
   ///
   /// The overridden element must have the same number of generic type
   /// parameters as the target element, or none.
@@ -726,16 +729,15 @@
   /// should infer this as `m<T>(T t)`.
   FunctionTypeImpl? _toOverriddenFunctionType(
     ExecutableElementOrMember element,
-    ExecutableElementOrMember overriddenElement,
+    FunctionTypeImpl overriddenType,
   ) {
     var elementTypeParameters = element.asElement2.typeParameters2;
-    var overriddenTypeParameters = overriddenElement.typeParameters;
+    var overriddenTypeParameters = overriddenType.typeParameters;
 
     if (elementTypeParameters.length != overriddenTypeParameters.length) {
       return null;
     }
 
-    var overriddenType = overriddenElement.type;
     if (elementTypeParameters.isEmpty) {
       return overriddenType;
     }