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;
}