| Index: pkg/analyzer/lib/src/generated/element_resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
|
| index 9f0cda01242452fad472655826b09be07e19b09d..f3fb282e41d7d0cbaac736acd459af7a871001f5 100644
|
| --- a/pkg/analyzer/lib/src/generated/element_resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
|
| @@ -9,14 +9,12 @@ import 'dart:collection';
|
| import 'package:analyzer/dart/element/element.dart';
|
| import 'package:analyzer/dart/element/type.dart';
|
| import 'package:analyzer/src/dart/element/element.dart';
|
| -import 'package:analyzer/src/dart/element/member.dart';
|
| import 'package:analyzer/src/dart/element/type.dart';
|
| import 'package:analyzer/src/generated/ast.dart';
|
| import 'package:analyzer/src/generated/engine.dart';
|
| import 'package:analyzer/src/generated/error.dart';
|
| import 'package:analyzer/src/generated/resolver.dart';
|
| import 'package:analyzer/src/generated/scanner.dart' as sc;
|
| -import 'package:analyzer/src/generated/utilities_dart.dart';
|
|
|
| /**
|
| * An object used by instances of [ResolverVisitor] to resolve references within
|
| @@ -639,64 +637,41 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
| }
|
| }
|
| }
|
| - //
|
| - // Check for a generic method & apply type arguments if any were passed.
|
| - //
|
| - if (staticElement is MethodElement || staticElement is FunctionElement) {
|
| - FunctionType type = (staticElement as ExecutableElement).type;
|
| - List<TypeParameterElement> parameters = type.boundTypeParameters;
|
| -
|
| - NodeList<TypeName> arguments = node.typeArguments?.arguments;
|
| - if (arguments != null && arguments.length != parameters.length) {
|
| - // Wrong number of type arguments. Ignore them
|
| - arguments = null;
|
| - _resolver.reportErrorForNode(
|
| - StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
| - methodName,
|
| - [type, parameters.length, arguments.length]);
|
| - }
|
| - if (parameters.isNotEmpty) {
|
| - List<DartType> typeArgs;
|
| - if (arguments == null) {
|
| - typeArgs = new List<DartType>.filled(
|
| - parameters.length, DynamicTypeImpl.instance);
|
| - } else {
|
| - typeArgs = new List<DartType>.from(arguments.map((n) => n.type));
|
| - }
|
| - type = type.instantiate(typeArgs);
|
| -
|
| - if (staticElement is MethodMember) {
|
| - MethodMember member = staticElement;
|
| - staticElement =
|
| - new MethodMember(member.baseElement, member.definingType, type);
|
| - } else if (staticElement is MethodElement) {
|
| - ClassElement clazz = staticElement.enclosingElement;
|
| - staticElement = new MethodMember(staticElement, clazz.type, type);
|
| - } else {
|
| - staticElement =
|
| - new FunctionMember(staticElement as FunctionElement, type);
|
| - }
|
| - }
|
| - }
|
|
|
| staticElement = _convertSetterToGetter(staticElement);
|
| propagatedElement = _convertSetterToGetter(propagatedElement);
|
| +
|
| + DartType staticInvokeType = _computeMethodInvokeType(node, staticElement);
|
| + DartType propagatedInvokeType =
|
| + _computeMethodInvokeType(node, propagatedElement);
|
| +
|
| //
|
| // Record the results.
|
| //
|
| methodName.staticElement = staticElement;
|
| methodName.propagatedElement = propagatedElement;
|
| +
|
| + node.staticInvokeType = staticInvokeType;
|
| + if (propagatedInvokeType != null &&
|
| + propagatedInvokeType.isMoreSpecificThan(staticInvokeType)) {
|
| + // Don't store the propagated invoke type unless it's more specific than
|
| + // the static type. We still need to record the propagated parameter
|
| + // elements however, as that is used for the propagatedType downwards
|
| + // inference of lambda parameters.
|
| + node.propagatedInvokeType = propagatedInvokeType;
|
| + }
|
| +
|
| ArgumentList argumentList = node.argumentList;
|
| - if (staticElement != null) {
|
| + if (staticInvokeType != null) {
|
| List<ParameterElement> parameters =
|
| - _computeCorrespondingParameters(argumentList, staticElement);
|
| + _computeCorrespondingParameters(argumentList, staticInvokeType);
|
| if (parameters != null) {
|
| argumentList.correspondingStaticParameters = parameters;
|
| }
|
| }
|
| - if (propagatedElement != null) {
|
| + if (propagatedInvokeType != null) {
|
| List<ParameterElement> parameters =
|
| - _computeCorrespondingParameters(argumentList, propagatedElement);
|
| + _computeCorrespondingParameters(argumentList, propagatedInvokeType);
|
| if (parameters != null) {
|
| argumentList.correspondingPropagatedParameters = parameters;
|
| }
|
| @@ -1336,44 +1311,16 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
| * arguments, or `null` if no correspondence could be computed.
|
| */
|
| List<ParameterElement> _computeCorrespondingParameters(
|
| - ArgumentList argumentList, Element element) {
|
| - if (element is PropertyAccessorElement) {
|
| - //
|
| - // This is an invocation of the call method defined on the value returned
|
| - // by the getter.
|
| - //
|
| - FunctionType getterType = element.type;
|
| - if (getterType != null) {
|
| - DartType getterReturnType = getterType.returnType;
|
| - if (getterReturnType is InterfaceType) {
|
| - MethodElement callMethod = getterReturnType.lookUpMethod(
|
| - FunctionElement.CALL_METHOD_NAME, _definingLibrary);
|
| - if (callMethod != null) {
|
| - return _resolveArgumentsToFunction(false, argumentList, callMethod);
|
| - }
|
| - } else if (getterReturnType is FunctionType) {
|
| - List<ParameterElement> parameters = getterReturnType.parameters;
|
| - return _resolveArgumentsToParameters(false, argumentList, parameters);
|
| - }
|
| - }
|
| - } else if (element is ExecutableElement) {
|
| - return _resolveArgumentsToFunction(false, argumentList, element);
|
| - } else if (element is VariableElement) {
|
| - VariableElement variable = element;
|
| - DartType type = _promoteManager.getStaticType(variable);
|
| - if (type is FunctionType) {
|
| - FunctionType functionType = type;
|
| - List<ParameterElement> parameters = functionType.parameters;
|
| - return _resolveArgumentsToParameters(false, argumentList, parameters);
|
| - } else if (type is InterfaceType) {
|
| - // "call" invocation
|
| - MethodElement callMethod = type.lookUpMethod(
|
| - FunctionElement.CALL_METHOD_NAME, _definingLibrary);
|
| - if (callMethod != null) {
|
| - List<ParameterElement> parameters = callMethod.parameters;
|
| - return _resolveArgumentsToParameters(false, argumentList, parameters);
|
| - }
|
| + ArgumentList argumentList, DartType type) {
|
| + if (type is InterfaceType) {
|
| + MethodElement callMethod =
|
| + type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
|
| + if (callMethod != null) {
|
| + return _resolveArgumentsToFunction(false, argumentList, callMethod);
|
| }
|
| + } else if (type is FunctionType) {
|
| + return _resolveArgumentsToParameters(
|
| + false, argumentList, type.parameters);
|
| }
|
| return null;
|
| }
|
| @@ -1514,6 +1461,49 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
| return staticType;
|
| }
|
|
|
| + DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
|
| + if (element == null) {
|
| + return null;
|
| + }
|
| +
|
| + DartType invokeType;
|
| + if (element is PropertyAccessorElement) {
|
| + invokeType = element.returnType;
|
| + } else if (element is ExecutableElement) {
|
| + invokeType = element.type;
|
| + } else if (element is VariableElement) {
|
| + invokeType = _promoteManager.getStaticType(element);
|
| + }
|
| +
|
| + //
|
| + // Check for a generic method & apply type arguments if any were passed.
|
| + //
|
| + // TODO(jmesserly): support generic "call" methods on InterfaceType.
|
| + if (invokeType is FunctionType) {
|
| + FunctionType type = invokeType;
|
| + List<TypeParameterElement> parameters = type.typeFormals;
|
| +
|
| + NodeList<TypeName> arguments = node.typeArguments?.arguments;
|
| + if (arguments != null && arguments.length != parameters.length) {
|
| + // Wrong number of type arguments. Ignore them
|
| + arguments = null;
|
| + _resolver.reportErrorForNode(
|
| + StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
| + node.methodName,
|
| + [type, parameters.length, arguments?.length ?? 0]);
|
| + }
|
| + if (parameters.isNotEmpty) {
|
| + if (arguments == null) {
|
| + invokeType = _resolver.typeSystem.instantiateToBounds(type);
|
| + } else {
|
| + invokeType = type.instantiate(arguments.map((n) => n.type).toList());
|
| + }
|
| + }
|
| + }
|
| +
|
| + return invokeType;
|
| + }
|
| +
|
| /**
|
| * Return `true` if the given [expression] is a prefix for a deferred import.
|
| */
|
| @@ -1948,102 +1938,35 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
| * Given an [argumentList] and the [executableElement] that will be invoked
|
| * using those argument, compute the list of parameters that correspond to the
|
| * list of arguments. An error will be reported if any of the arguments cannot
|
| - * be matched to a parameter. The flag [reportError] should be `true` if a
|
| + * be matched to a parameter. The flag [reportAsError] should be `true` if a
|
| * compile-time error should be reported; or `false` if a compile-time warning
|
| * should be reported. Return the parameters that correspond to the arguments,
|
| * or `null` if no correspondence could be computed.
|
| */
|
| - List<ParameterElement> _resolveArgumentsToFunction(bool reportError,
|
| + List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
|
| ArgumentList argumentList, ExecutableElement executableElement) {
|
| if (executableElement == null) {
|
| return null;
|
| }
|
| List<ParameterElement> parameters = executableElement.parameters;
|
| - return _resolveArgumentsToParameters(reportError, argumentList, parameters);
|
| + return _resolveArgumentsToParameters(
|
| + reportAsError, argumentList, parameters);
|
| }
|
|
|
| /**
|
| * Given an [argumentList] and the [parameters] related to the element that
|
| * will be invoked using those arguments, compute the list of parameters that
|
| * correspond to the list of arguments. An error will be reported if any of
|
| - * the arguments cannot be matched to a parameter. The flag [reportError]
|
| + * the arguments cannot be matched to a parameter. The flag [reportAsError]
|
| * should be `true` if a compile-time error should be reported; or `false` if
|
| * a compile-time warning should be reported. Return the parameters that
|
| * correspond to the arguments.
|
| */
|
| - List<ParameterElement> _resolveArgumentsToParameters(bool reportError,
|
| + List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
|
| ArgumentList argumentList, List<ParameterElement> parameters) {
|
| - List<ParameterElement> requiredParameters = new List<ParameterElement>();
|
| - List<ParameterElement> positionalParameters = new List<ParameterElement>();
|
| - HashMap<String, ParameterElement> namedParameters =
|
| - new HashMap<String, ParameterElement>();
|
| - for (ParameterElement parameter in parameters) {
|
| - ParameterKind kind = parameter.parameterKind;
|
| - if (kind == ParameterKind.REQUIRED) {
|
| - requiredParameters.add(parameter);
|
| - } else if (kind == ParameterKind.POSITIONAL) {
|
| - positionalParameters.add(parameter);
|
| - } else {
|
| - namedParameters[parameter.name] = parameter;
|
| - }
|
| - }
|
| - List<ParameterElement> unnamedParameters =
|
| - new List<ParameterElement>.from(requiredParameters);
|
| - unnamedParameters.addAll(positionalParameters);
|
| - int unnamedParameterCount = unnamedParameters.length;
|
| - int unnamedIndex = 0;
|
| - NodeList<Expression> arguments = argumentList.arguments;
|
| - int argumentCount = arguments.length;
|
| - List<ParameterElement> resolvedParameters =
|
| - new List<ParameterElement>(argumentCount);
|
| - int positionalArgumentCount = 0;
|
| - HashSet<String> usedNames = new HashSet<String>();
|
| - bool noBlankArguments = true;
|
| - for (int i = 0; i < argumentCount; i++) {
|
| - Expression argument = arguments[i];
|
| - if (argument is NamedExpression) {
|
| - SimpleIdentifier nameNode = argument.name.label;
|
| - String name = nameNode.name;
|
| - ParameterElement element = namedParameters[name];
|
| - if (element == null) {
|
| - ErrorCode errorCode = (reportError
|
| - ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
|
| - : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
|
| - _resolver.reportErrorForNode(errorCode, nameNode, [name]);
|
| - } else {
|
| - resolvedParameters[i] = element;
|
| - nameNode.staticElement = element;
|
| - }
|
| - if (!usedNames.add(name)) {
|
| - _resolver.reportErrorForNode(
|
| - CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
|
| - }
|
| - } else {
|
| - if (argument is SimpleIdentifier && argument.name.isEmpty) {
|
| - noBlankArguments = false;
|
| - }
|
| - positionalArgumentCount++;
|
| - if (unnamedIndex < unnamedParameterCount) {
|
| - resolvedParameters[i] = unnamedParameters[unnamedIndex++];
|
| - }
|
| - }
|
| - }
|
| - if (positionalArgumentCount < requiredParameters.length &&
|
| - noBlankArguments) {
|
| - ErrorCode errorCode = (reportError
|
| - ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
|
| - : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
|
| - _resolver.reportErrorForNode(errorCode, argumentList,
|
| - [requiredParameters.length, positionalArgumentCount]);
|
| - } else if (positionalArgumentCount > unnamedParameterCount &&
|
| - noBlankArguments) {
|
| - ErrorCode errorCode = (reportError
|
| - ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
|
| - : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
|
| - _resolver.reportErrorForNode(errorCode, argumentList,
|
| - [unnamedParameterCount, positionalArgumentCount]);
|
| - }
|
| - return resolvedParameters;
|
| + return ResolverVisitor.resolveArgumentsToParameters(
|
| + argumentList, parameters, _resolver.reportErrorForNode,
|
| + reportAsError: reportAsError);
|
| }
|
|
|
| void _resolveBinaryExpression(BinaryExpression node, String methodName) {
|
|
|