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

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: deprecate FunctionMember 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 =
Brian Wilkerson 2016/01/06 21:57:34 If the propagatedInvokeType is not `null` and is n
Jennifer Messerly 2016/01/06 22:25:51 Yeah that's a good point. I think we get this for
Brian Wilkerson 2016/01/06 22:47:01 Unfortunately, no. It's perfectly valid for both t
Jennifer Messerly 2016/01/06 22:52:48 Ah that makes sense. Does something like this look
Brian Wilkerson 2016/01/07 00:24:22 See ResolverVisitor.recordPropagatedTypeIfBetter.
Jennifer Messerly 2016/01/07 00:33:29 Ah, nice! Looking through there, I think the logic
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 node.propagatedInvokeType = propagatedInvokeType;
656
689 ArgumentList argumentList = node.argumentList; 657 ArgumentList argumentList = node.argumentList;
690 if (staticElement != null) { 658 if (staticInvokeType != null) {
691 List<ParameterElement> parameters = 659 List<ParameterElement> parameters =
692 _computeCorrespondingParameters(argumentList, staticElement); 660 _computeCorrespondingParameters(argumentList, staticInvokeType);
693 if (parameters != null) { 661 if (parameters != null) {
694 argumentList.correspondingStaticParameters = parameters; 662 argumentList.correspondingStaticParameters = parameters;
695 } 663 }
696 } 664 }
697 if (propagatedElement != null) { 665 if (propagatedInvokeType != null) {
698 List<ParameterElement> parameters = 666 List<ParameterElement> parameters =
699 _computeCorrespondingParameters(argumentList, propagatedElement); 667 _computeCorrespondingParameters(argumentList, propagatedInvokeType);
700 if (parameters != null) { 668 if (parameters != null) {
701 argumentList.correspondingPropagatedParameters = parameters; 669 argumentList.correspondingPropagatedParameters = parameters;
702 } 670 }
703 } 671 }
704 // 672 //
705 // Then check for error conditions. 673 // Then check for error conditions.
706 // 674 //
707 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); 675 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement);
708 bool generatedWithTypePropagation = false; 676 bool generatedWithTypePropagation = false;
709 if (_enableHints && errorCode == null && staticElement == null) { 677 if (_enableHints && errorCode == null && staticElement == null) {
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
1329 return false; 1297 return false;
1330 } 1298 }
1331 1299
1332 /** 1300 /**
1333 * Given an [argumentList] and the executable [element] that will be invoked 1301 * Given an [argumentList] and the executable [element] that will be invoked
1334 * using those arguments, compute the list of parameters that correspond to 1302 * using those arguments, compute the list of parameters that correspond to
1335 * the list of arguments. Return the parameters that correspond to the 1303 * the list of arguments. Return the parameters that correspond to the
1336 * arguments, or `null` if no correspondence could be computed. 1304 * arguments, or `null` if no correspondence could be computed.
1337 */ 1305 */
1338 List<ParameterElement> _computeCorrespondingParameters( 1306 List<ParameterElement> _computeCorrespondingParameters(
1339 ArgumentList argumentList, Element element) { 1307 ArgumentList argumentList, DartType type) {
1340 if (element is PropertyAccessorElement) { 1308 if (type is InterfaceType) {
1341 // 1309 MethodElement callMethod =
1342 // This is an invocation of the call method defined on the value returned 1310 type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1343 // by the getter. 1311 if (callMethod != null) {
1344 // 1312 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 } 1313 }
1359 } else if (element is ExecutableElement) { 1314 } else if (type is FunctionType) {
1360 return _resolveArgumentsToFunction(false, argumentList, element); 1315 return _resolveArgumentsToParameters(
1361 } else if (element is VariableElement) { 1316 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 } 1317 }
1378 return null; 1318 return null;
1379 } 1319 }
1380 1320
1381 /** 1321 /**
1382 * If the given [element] is a setter, return the getter associated with it. 1322 * If the given [element] is a setter, return the getter associated with it.
1383 * Otherwise, return the element unchanged. 1323 * Otherwise, return the element unchanged.
1384 */ 1324 */
1385 Element _convertSetterToGetter(Element element) { 1325 Element _convertSetterToGetter(Element element) {
1386 // TODO(brianwilkerson) Determine whether and why the element could ever be 1326 // 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) { 1447 if (staticType is FunctionType) {
1508 // 1448 //
1509 // All function types are subtypes of 'Function', which is itself a 1449 // All function types are subtypes of 'Function', which is itself a
1510 // subclass of 'Object'. 1450 // subclass of 'Object'.
1511 // 1451 //
1512 staticType = _resolver.typeProvider.functionType; 1452 staticType = _resolver.typeProvider.functionType;
1513 } 1453 }
1514 return staticType; 1454 return staticType;
1515 } 1455 }
1516 1456
1457 DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
1458 if (element == null) {
1459 return null;
1460 }
1461
1462 DartType invokeType;
1463 if (element is PropertyAccessorElement) {
1464 invokeType = element.returnType;
1465 } else if (element is ExecutableElement) {
1466 invokeType = element.type;
1467 } else if (element is VariableElement) {
1468 invokeType = _promoteManager.getStaticType(element);
1469 }
1470
1471 //
1472 // Check for a generic method & apply type arguments if any were passed.
1473 //
1474 // TODO(jmesserly): should we support for generic "call" methods on
Brian Wilkerson 2016/01/06 21:57:34 "should we support for"?
Jennifer Messerly 2016/01/06 22:25:51 DOH. Good catch! It got stuck halfway between an e
1475 // InterfaceType?
1476 if (invokeType is FunctionType) {
1477 FunctionType type = invokeType;
1478 List<TypeParameterElement> parameters = type.typeFormals;
1479
1480 NodeList<TypeName> arguments = node.typeArguments?.arguments;
1481 if (arguments != null && arguments.length != parameters.length) {
1482 // Wrong number of type arguments. Ignore them
1483 arguments = null;
1484 _resolver.reportErrorForNode(
1485 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
1486 node.methodName,
1487 [type, parameters.length, arguments.length]);
1488 }
1489 if (parameters.isNotEmpty) {
1490 if (arguments == null) {
1491 invokeType = _resolver.typeSystem.instantiateToBounds(type);
1492 } else {
1493 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
1494 }
1495 }
1496 }
1497
1498 return invokeType;
1499 }
1500
1517 /** 1501 /**
1518 * Return `true` if the given [expression] is a prefix for a deferred import. 1502 * Return `true` if the given [expression] is a prefix for a deferred import.
1519 */ 1503 */
1520 bool _isDeferredPrefix(Expression expression) { 1504 bool _isDeferredPrefix(Expression expression) {
1521 if (expression is! SimpleIdentifier) { 1505 if (expression is! SimpleIdentifier) {
1522 return false; 1506 return false;
1523 } 1507 }
1524 Element element = (expression as SimpleIdentifier).staticElement; 1508 Element element = (expression as SimpleIdentifier).staticElement;
1525 if (element is! PrefixElement) { 1509 if (element is! PrefixElement) {
1526 return false; 1510 return false;
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
1966 * Given an [argumentList] and the [parameters] related to the element that 1950 * Given an [argumentList] and the [parameters] related to the element that
1967 * will be invoked using those arguments, compute the list of parameters that 1951 * 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 1952 * 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] 1953 * the arguments cannot be matched to a parameter. The flag [reportError]
1970 * should be `true` if a compile-time error should be reported; or `false` if 1954 * 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 1955 * a compile-time warning should be reported. Return the parameters that
1972 * correspond to the arguments. 1956 * correspond to the arguments.
1973 */ 1957 */
1974 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, 1958 List<ParameterElement> _resolveArgumentsToParameters(bool reportError,
1975 ArgumentList argumentList, List<ParameterElement> parameters) { 1959 ArgumentList argumentList, List<ParameterElement> parameters) {
1976 List<ParameterElement> requiredParameters = new List<ParameterElement>(); 1960 return ResolverVisitor.resolveArgumentsToParameters(
1977 List<ParameterElement> positionalParameters = new List<ParameterElement>(); 1961 argumentList, parameters, _resolver.reportErrorForNode,
1978 HashMap<String, ParameterElement> namedParameters = 1962 reportError: reportError);
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 } 1963 }
2048 1964
2049 void _resolveBinaryExpression(BinaryExpression node, String methodName) { 1965 void _resolveBinaryExpression(BinaryExpression node, String methodName) {
2050 Expression leftOperand = node.leftOperand; 1966 Expression leftOperand = node.leftOperand;
2051 if (leftOperand != null) { 1967 if (leftOperand != null) {
2052 DartType staticType = _getStaticType(leftOperand); 1968 DartType staticType = _getStaticType(leftOperand);
2053 MethodElement staticMethod = 1969 MethodElement staticMethod =
2054 _lookUpMethod(leftOperand, staticType, methodName); 1970 _lookUpMethod(leftOperand, staticType, methodName);
2055 node.staticElement = staticMethod; 1971 node.staticElement = staticMethod;
2056 DartType propagatedType = _getPropagatedType(leftOperand); 1972 DartType propagatedType = _getPropagatedType(leftOperand);
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
2644 2560
2645 @override 2561 @override
2646 Element get staticElement => null; 2562 Element get staticElement => null;
2647 2563
2648 @override 2564 @override
2649 accept(AstVisitor visitor) => null; 2565 accept(AstVisitor visitor) => null;
2650 2566
2651 @override 2567 @override
2652 void visitChildren(AstVisitor visitor) {} 2568 void visitChildren(AstVisitor visitor) {}
2653 } 2569 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698