Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: pkg/analyzer/lib/src/generated/element_resolver.dart

Issue 1568643002: clean up generic methods in resolution (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.element_resolver; 5 library analyzer.src.generated.element_resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/element/element.dart'; 9 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/type.dart'; 10 import 'package:analyzer/dart/element/type.dart';
11 import 'package:analyzer/src/dart/element/element.dart'; 11 import 'package:analyzer/src/dart/element/element.dart';
12 import 'package:analyzer/src/dart/element/member.dart';
13 import 'package:analyzer/src/dart/element/type.dart'; 12 import 'package:analyzer/src/dart/element/type.dart';
14 import 'package:analyzer/src/generated/ast.dart'; 13 import 'package:analyzer/src/generated/ast.dart';
15 import 'package:analyzer/src/generated/engine.dart'; 14 import 'package:analyzer/src/generated/engine.dart';
16 import 'package:analyzer/src/generated/error.dart'; 15 import 'package:analyzer/src/generated/error.dart';
17 import 'package:analyzer/src/generated/resolver.dart'; 16 import 'package:analyzer/src/generated/resolver.dart';
18 import 'package:analyzer/src/generated/scanner.dart' as sc; 17 import 'package:analyzer/src/generated/scanner.dart' as sc;
19 import 'package:analyzer/src/generated/utilities_dart.dart';
20 18
21 /** 19 /**
22 * An object used by instances of [ResolverVisitor] to resolve references within 20 * An object used by instances of [ResolverVisitor] to resolve references within
23 * the AST structure to the elements being referenced. The requirements for the 21 * the AST structure to the elements being referenced. The requirements for the
24 * element resolver are: 22 * element resolver are:
25 * 23 *
26 * 1. Every [SimpleIdentifier] should be resolved to the element to which it 24 * 1. Every [SimpleIdentifier] should be resolved to the element to which it
27 * refers. Specifically: 25 * refers. Specifically:
28 * * An identifier within the declaration of that name should resolve to the 26 * * An identifier within the declaration of that name should resolve to the
29 * element being declared. 27 * element being declared.
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 target, staticType, methodName, isConditional); 630 target, staticType, methodName, isConditional);
633 // If we have propagated type information use it (since it should 631 // If we have propagated type information use it (since it should
634 // not be redundant with the staticType). Otherwise, don't produce 632 // not be redundant with the staticType). Otherwise, don't produce
635 // a propagatedElement which duplicates the staticElement. 633 // a propagatedElement which duplicates the staticElement.
636 if (propagatedType is InterfaceType) { 634 if (propagatedType is InterfaceType) {
637 propagatedElement = _resolveInvokedElementWithTarget( 635 propagatedElement = _resolveInvokedElementWithTarget(
638 target, propagatedType, methodName, isConditional); 636 target, propagatedType, methodName, isConditional);
639 } 637 }
640 } 638 }
641 } 639 }
642 //
643 // Check for a generic method & apply type arguments if any were passed.
644 //
645 if (staticElement is MethodElement || staticElement is FunctionElement) {
646 FunctionType type = (staticElement as ExecutableElement).type;
647 List<TypeParameterElement> parameters = type.boundTypeParameters;
648
649 NodeList<TypeName> arguments = node.typeArguments?.arguments;
650 if (arguments != null && arguments.length != parameters.length) {
651 // Wrong number of type arguments. Ignore them
652 arguments = null;
653 _resolver.reportErrorForNode(
654 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
655 methodName,
656 [type, parameters.length, arguments.length]);
657 }
658 if (parameters.isNotEmpty) {
659 List<DartType> typeArgs;
660 if (arguments == null) {
661 typeArgs = new List<DartType>.filled(
662 parameters.length, DynamicTypeImpl.instance);
663 } else {
664 typeArgs = new List<DartType>.from(arguments.map((n) => n.type));
665 }
666 type = type.instantiate(typeArgs);
667
668 if (staticElement is MethodMember) {
669 MethodMember member = staticElement;
670 staticElement =
671 new MethodMember(member.baseElement, member.definingType, type);
672 } else if (staticElement is MethodElement) {
673 ClassElement clazz = staticElement.enclosingElement;
674 staticElement = new MethodMember(staticElement, clazz.type, type);
675 } else {
676 staticElement =
677 new FunctionMember(staticElement as FunctionElement, type);
678 }
679 }
680 }
681 640
682 staticElement = _convertSetterToGetter(staticElement); 641 staticElement = _convertSetterToGetter(staticElement);
683 propagatedElement = _convertSetterToGetter(propagatedElement); 642 propagatedElement = _convertSetterToGetter(propagatedElement);
643
644 DartType staticInvokeType = _computeMethodInvokeType(node, staticElement);
645 DartType propagatedInvokeType =
646 _computeMethodInvokeType(node, propagatedElement);
647
684 // 648 //
685 // Record the results. 649 // Record the results.
686 // 650 //
687 methodName.staticElement = staticElement; 651 methodName.staticElement = staticElement;
688 methodName.propagatedElement = propagatedElement; 652 methodName.propagatedElement = propagatedElement;
653
654 node.staticInvokeType = staticInvokeType;
655 if (propagatedInvokeType != null &&
656 propagatedInvokeType.isMoreSpecificThan(staticInvokeType)) {
657 // Don't store the propagated invoke type unless it's more specific than
658 // the static type. We still need to record the propagated parameter
659 // elements however, as that is used for the propagatedType downwards
660 // inference of lambda parameters.
661 node.propagatedInvokeType = propagatedInvokeType;
662 }
663
689 ArgumentList argumentList = node.argumentList; 664 ArgumentList argumentList = node.argumentList;
690 if (staticElement != null) { 665 if (staticInvokeType != null) {
691 List<ParameterElement> parameters = 666 List<ParameterElement> parameters =
692 _computeCorrespondingParameters(argumentList, staticElement); 667 _computeCorrespondingParameters(argumentList, staticInvokeType);
693 if (parameters != null) { 668 if (parameters != null) {
694 argumentList.correspondingStaticParameters = parameters; 669 argumentList.correspondingStaticParameters = parameters;
695 } 670 }
696 } 671 }
697 if (propagatedElement != null) { 672 if (propagatedInvokeType != null) {
698 List<ParameterElement> parameters = 673 List<ParameterElement> parameters =
699 _computeCorrespondingParameters(argumentList, propagatedElement); 674 _computeCorrespondingParameters(argumentList, propagatedInvokeType);
700 if (parameters != null) { 675 if (parameters != null) {
701 argumentList.correspondingPropagatedParameters = parameters; 676 argumentList.correspondingPropagatedParameters = parameters;
702 } 677 }
703 } 678 }
704 // 679 //
705 // Then check for error conditions. 680 // Then check for error conditions.
706 // 681 //
707 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); 682 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement);
708 bool generatedWithTypePropagation = false; 683 bool generatedWithTypePropagation = false;
709 if (_enableHints && errorCode == null && staticElement == null) { 684 if (_enableHints && errorCode == null && staticElement == null) {
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
1329 return false; 1304 return false;
1330 } 1305 }
1331 1306
1332 /** 1307 /**
1333 * Given an [argumentList] and the executable [element] that will be invoked 1308 * Given an [argumentList] and the executable [element] that will be invoked
1334 * using those arguments, compute the list of parameters that correspond to 1309 * using those arguments, compute the list of parameters that correspond to
1335 * the list of arguments. Return the parameters that correspond to the 1310 * the list of arguments. Return the parameters that correspond to the
1336 * arguments, or `null` if no correspondence could be computed. 1311 * arguments, or `null` if no correspondence could be computed.
1337 */ 1312 */
1338 List<ParameterElement> _computeCorrespondingParameters( 1313 List<ParameterElement> _computeCorrespondingParameters(
1339 ArgumentList argumentList, Element element) { 1314 ArgumentList argumentList, DartType type) {
1340 if (element is PropertyAccessorElement) { 1315 if (type is InterfaceType) {
1341 // 1316 MethodElement callMethod =
1342 // This is an invocation of the call method defined on the value returned 1317 type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1343 // by the getter. 1318 if (callMethod != null) {
1344 // 1319 return _resolveArgumentsToFunction(false, argumentList, callMethod);
1345 FunctionType getterType = element.type;
1346 if (getterType != null) {
1347 DartType getterReturnType = getterType.returnType;
1348 if (getterReturnType is InterfaceType) {
1349 MethodElement callMethod = getterReturnType.lookUpMethod(
1350 FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1351 if (callMethod != null) {
1352 return _resolveArgumentsToFunction(false, argumentList, callMethod);
1353 }
1354 } else if (getterReturnType is FunctionType) {
1355 List<ParameterElement> parameters = getterReturnType.parameters;
1356 return _resolveArgumentsToParameters(false, argumentList, parameters);
1357 }
1358 } 1320 }
1359 } else if (element is ExecutableElement) { 1321 } else if (type is FunctionType) {
1360 return _resolveArgumentsToFunction(false, argumentList, element); 1322 return _resolveArgumentsToParameters(
1361 } else if (element is VariableElement) { 1323 false, argumentList, type.parameters);
1362 VariableElement variable = element;
1363 DartType type = _promoteManager.getStaticType(variable);
1364 if (type is FunctionType) {
1365 FunctionType functionType = type;
1366 List<ParameterElement> parameters = functionType.parameters;
1367 return _resolveArgumentsToParameters(false, argumentList, parameters);
1368 } else if (type is InterfaceType) {
1369 // "call" invocation
1370 MethodElement callMethod = type.lookUpMethod(
1371 FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1372 if (callMethod != null) {
1373 List<ParameterElement> parameters = callMethod.parameters;
1374 return _resolveArgumentsToParameters(false, argumentList, parameters);
1375 }
1376 }
1377 } 1324 }
1378 return null; 1325 return null;
1379 } 1326 }
1380 1327
1381 /** 1328 /**
1382 * If the given [element] is a setter, return the getter associated with it. 1329 * If the given [element] is a setter, return the getter associated with it.
1383 * Otherwise, return the element unchanged. 1330 * Otherwise, return the element unchanged.
1384 */ 1331 */
1385 Element _convertSetterToGetter(Element element) { 1332 Element _convertSetterToGetter(Element element) {
1386 // TODO(brianwilkerson) Determine whether and why the element could ever be 1333 // TODO(brianwilkerson) Determine whether and why the element could ever be
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 if (staticType is FunctionType) { 1454 if (staticType is FunctionType) {
1508 // 1455 //
1509 // All function types are subtypes of 'Function', which is itself a 1456 // All function types are subtypes of 'Function', which is itself a
1510 // subclass of 'Object'. 1457 // subclass of 'Object'.
1511 // 1458 //
1512 staticType = _resolver.typeProvider.functionType; 1459 staticType = _resolver.typeProvider.functionType;
1513 } 1460 }
1514 return staticType; 1461 return staticType;
1515 } 1462 }
1516 1463
1464 DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
1465 if (element == null) {
1466 return null;
1467 }
1468
1469 DartType invokeType;
1470 if (element is PropertyAccessorElement) {
1471 invokeType = element.returnType;
1472 } else if (element is ExecutableElement) {
1473 invokeType = element.type;
1474 } else if (element is VariableElement) {
1475 invokeType = _promoteManager.getStaticType(element);
1476 }
1477
1478 //
1479 // Check for a generic method & apply type arguments if any were passed.
1480 //
1481 // TODO(jmesserly): support generic "call" methods on InterfaceType.
1482 if (invokeType is FunctionType) {
1483 FunctionType type = invokeType;
1484 List<TypeParameterElement> parameters = type.typeFormals;
1485
1486 NodeList<TypeName> arguments = node.typeArguments?.arguments;
1487 if (arguments != null && arguments.length != parameters.length) {
1488 // Wrong number of type arguments. Ignore them
1489 arguments = null;
1490 _resolver.reportErrorForNode(
1491 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
1492 node.methodName,
1493 [type, parameters.length, arguments?.length ?? 0]);
1494 }
1495 if (parameters.isNotEmpty) {
1496 if (arguments == null) {
1497 invokeType = _resolver.typeSystem.instantiateToBounds(type);
1498 } else {
1499 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
1500 }
1501 }
1502 }
1503
1504 return invokeType;
1505 }
1506
1517 /** 1507 /**
1518 * Return `true` if the given [expression] is a prefix for a deferred import. 1508 * Return `true` if the given [expression] is a prefix for a deferred import.
1519 */ 1509 */
1520 bool _isDeferredPrefix(Expression expression) { 1510 bool _isDeferredPrefix(Expression expression) {
1521 if (expression is! SimpleIdentifier) { 1511 if (expression is! SimpleIdentifier) {
1522 return false; 1512 return false;
1523 } 1513 }
1524 Element element = (expression as SimpleIdentifier).staticElement; 1514 Element element = (expression as SimpleIdentifier).staticElement;
1525 if (element is! PrefixElement) { 1515 if (element is! PrefixElement) {
1526 return false; 1516 return false;
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after
1941 [annotation.name]); 1931 [annotation.name]);
1942 } 1932 }
1943 // OK 1933 // OK
1944 return; 1934 return;
1945 } 1935 }
1946 1936
1947 /** 1937 /**
1948 * Given an [argumentList] and the [executableElement] that will be invoked 1938 * Given an [argumentList] and the [executableElement] that will be invoked
1949 * using those argument, compute the list of parameters that correspond to the 1939 * using those argument, compute the list of parameters that correspond to the
1950 * list of arguments. An error will be reported if any of the arguments cannot 1940 * list of arguments. An error will be reported if any of the arguments cannot
1951 * be matched to a parameter. The flag [reportError] should be `true` if a 1941 * be matched to a parameter. The flag [reportAsError] should be `true` if a
1952 * compile-time error should be reported; or `false` if a compile-time warning 1942 * compile-time error should be reported; or `false` if a compile-time warning
1953 * should be reported. Return the parameters that correspond to the arguments, 1943 * should be reported. Return the parameters that correspond to the arguments,
1954 * or `null` if no correspondence could be computed. 1944 * or `null` if no correspondence could be computed.
1955 */ 1945 */
1956 List<ParameterElement> _resolveArgumentsToFunction(bool reportError, 1946 List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
1957 ArgumentList argumentList, ExecutableElement executableElement) { 1947 ArgumentList argumentList, ExecutableElement executableElement) {
1958 if (executableElement == null) { 1948 if (executableElement == null) {
1959 return null; 1949 return null;
1960 } 1950 }
1961 List<ParameterElement> parameters = executableElement.parameters; 1951 List<ParameterElement> parameters = executableElement.parameters;
1962 return _resolveArgumentsToParameters(reportError, argumentList, parameters); 1952 return _resolveArgumentsToParameters(
1953 reportAsError, argumentList, parameters);
1963 } 1954 }
1964 1955
1965 /** 1956 /**
1966 * Given an [argumentList] and the [parameters] related to the element that 1957 * Given an [argumentList] and the [parameters] related to the element that
1967 * will be invoked using those arguments, compute the list of parameters that 1958 * will be invoked using those arguments, compute the list of parameters that
1968 * correspond to the list of arguments. An error will be reported if any of 1959 * correspond to the list of arguments. An error will be reported if any of
1969 * the arguments cannot be matched to a parameter. The flag [reportError] 1960 * the arguments cannot be matched to a parameter. The flag [reportAsError]
1970 * should be `true` if a compile-time error should be reported; or `false` if 1961 * should be `true` if a compile-time error should be reported; or `false` if
1971 * a compile-time warning should be reported. Return the parameters that 1962 * a compile-time warning should be reported. Return the parameters that
1972 * correspond to the arguments. 1963 * correspond to the arguments.
1973 */ 1964 */
1974 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, 1965 List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
1975 ArgumentList argumentList, List<ParameterElement> parameters) { 1966 ArgumentList argumentList, List<ParameterElement> parameters) {
1976 List<ParameterElement> requiredParameters = new List<ParameterElement>(); 1967 return ResolverVisitor.resolveArgumentsToParameters(
1977 List<ParameterElement> positionalParameters = new List<ParameterElement>(); 1968 argumentList, parameters, _resolver.reportErrorForNode,
1978 HashMap<String, ParameterElement> namedParameters = 1969 reportAsError: reportAsError);
1979 new HashMap<String, ParameterElement>();
1980 for (ParameterElement parameter in parameters) {
1981 ParameterKind kind = parameter.parameterKind;
1982 if (kind == ParameterKind.REQUIRED) {
1983 requiredParameters.add(parameter);
1984 } else if (kind == ParameterKind.POSITIONAL) {
1985 positionalParameters.add(parameter);
1986 } else {
1987 namedParameters[parameter.name] = parameter;
1988 }
1989 }
1990 List<ParameterElement> unnamedParameters =
1991 new List<ParameterElement>.from(requiredParameters);
1992 unnamedParameters.addAll(positionalParameters);
1993 int unnamedParameterCount = unnamedParameters.length;
1994 int unnamedIndex = 0;
1995 NodeList<Expression> arguments = argumentList.arguments;
1996 int argumentCount = arguments.length;
1997 List<ParameterElement> resolvedParameters =
1998 new List<ParameterElement>(argumentCount);
1999 int positionalArgumentCount = 0;
2000 HashSet<String> usedNames = new HashSet<String>();
2001 bool noBlankArguments = true;
2002 for (int i = 0; i < argumentCount; i++) {
2003 Expression argument = arguments[i];
2004 if (argument is NamedExpression) {
2005 SimpleIdentifier nameNode = argument.name.label;
2006 String name = nameNode.name;
2007 ParameterElement element = namedParameters[name];
2008 if (element == null) {
2009 ErrorCode errorCode = (reportError
2010 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
2011 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
2012 _resolver.reportErrorForNode(errorCode, nameNode, [name]);
2013 } else {
2014 resolvedParameters[i] = element;
2015 nameNode.staticElement = element;
2016 }
2017 if (!usedNames.add(name)) {
2018 _resolver.reportErrorForNode(
2019 CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
2020 }
2021 } else {
2022 if (argument is SimpleIdentifier && argument.name.isEmpty) {
2023 noBlankArguments = false;
2024 }
2025 positionalArgumentCount++;
2026 if (unnamedIndex < unnamedParameterCount) {
2027 resolvedParameters[i] = unnamedParameters[unnamedIndex++];
2028 }
2029 }
2030 }
2031 if (positionalArgumentCount < requiredParameters.length &&
2032 noBlankArguments) {
2033 ErrorCode errorCode = (reportError
2034 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
2035 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
2036 _resolver.reportErrorForNode(errorCode, argumentList,
2037 [requiredParameters.length, positionalArgumentCount]);
2038 } else if (positionalArgumentCount > unnamedParameterCount &&
2039 noBlankArguments) {
2040 ErrorCode errorCode = (reportError
2041 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
2042 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
2043 _resolver.reportErrorForNode(errorCode, argumentList,
2044 [unnamedParameterCount, positionalArgumentCount]);
2045 }
2046 return resolvedParameters;
2047 } 1970 }
2048 1971
2049 void _resolveBinaryExpression(BinaryExpression node, String methodName) { 1972 void _resolveBinaryExpression(BinaryExpression node, String methodName) {
2050 Expression leftOperand = node.leftOperand; 1973 Expression leftOperand = node.leftOperand;
2051 if (leftOperand != null) { 1974 if (leftOperand != null) {
2052 DartType staticType = _getStaticType(leftOperand); 1975 DartType staticType = _getStaticType(leftOperand);
2053 MethodElement staticMethod = 1976 MethodElement staticMethod =
2054 _lookUpMethod(leftOperand, staticType, methodName); 1977 _lookUpMethod(leftOperand, staticType, methodName);
2055 node.staticElement = staticMethod; 1978 node.staticElement = staticMethod;
2056 DartType propagatedType = _getPropagatedType(leftOperand); 1979 DartType propagatedType = _getPropagatedType(leftOperand);
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
2644 2567
2645 @override 2568 @override
2646 Element get staticElement => null; 2569 Element get staticElement => null;
2647 2570
2648 @override 2571 @override
2649 accept(AstVisitor visitor) => null; 2572 accept(AstVisitor visitor) => null;
2650 2573
2651 @override 2574 @override
2652 void visitChildren(AstVisitor visitor) {} 2575 void visitChildren(AstVisitor visitor) {}
2653 } 2576 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/ast.dart ('k') | pkg/analyzer/lib/src/generated/error_verifier.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698