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

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

Issue 1561233003: support generic methods in FunctionExpressionInvocation node (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';
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 } 419 }
420 420
421 @override 421 @override
422 Object visitFunctionDeclaration(FunctionDeclaration node) { 422 Object visitFunctionDeclaration(FunctionDeclaration node) {
423 setMetadata(node.element, node); 423 setMetadata(node.element, node);
424 return null; 424 return null;
425 } 425 }
426 426
427 @override 427 @override
428 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 428 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
429 // TODO(brianwilkerson) Can we ever resolve the function being invoked? 429 Expression function = node.function;
430 Expression expression = node.function; 430 DartType staticInvokeType =
431 if (expression is FunctionExpression) { 431 _resolveGenericMethod(function.staticType, node.typeArguments, node);
432 FunctionExpression functionExpression = expression; 432 DartType propagatedInvokeType = _resolveGenericMethod(
433 ExecutableElement functionElement = functionExpression.element; 433 function.propagatedType, node.typeArguments, node);
434 ArgumentList argumentList = node.argumentList; 434
435 List<ParameterElement> parameters = 435 node.staticInvokeType = staticInvokeType;
436 _resolveArgumentsToFunction(false, argumentList, functionElement); 436 node.propagatedInvokeType =
437 if (parameters != null) { 437 _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
438 argumentList.correspondingStaticParameters = parameters; 438
439 } 439 List<ParameterElement> parameters =
440 _computeCorrespondingParameters(node.argumentList, staticInvokeType);
441 if (parameters != null) {
442 node.argumentList.correspondingStaticParameters = parameters;
443 }
444
445 parameters = _computeCorrespondingParameters(
446 node.argumentList, propagatedInvokeType);
447 if (parameters != null) {
448 node.argumentList.correspondingPropagatedParameters = parameters;
440 } 449 }
441 return null; 450 return null;
442 } 451 }
443 452
444 @override 453 @override
445 Object visitFunctionTypeAlias(FunctionTypeAlias node) { 454 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
446 setMetadata(node.element, node); 455 setMetadata(node.element, node);
447 return null; 456 return null;
448 } 457 }
449 458
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 DartType propagatedInvokeType = 654 DartType propagatedInvokeType =
646 _computeMethodInvokeType(node, propagatedElement); 655 _computeMethodInvokeType(node, propagatedElement);
647 656
648 // 657 //
649 // Record the results. 658 // Record the results.
650 // 659 //
651 methodName.staticElement = staticElement; 660 methodName.staticElement = staticElement;
652 methodName.propagatedElement = propagatedElement; 661 methodName.propagatedElement = propagatedElement;
653 662
654 node.staticInvokeType = staticInvokeType; 663 node.staticInvokeType = staticInvokeType;
655 if (propagatedInvokeType != null && 664 //
656 (staticInvokeType == null || 665 // Store the propagated invoke type if it's more specific than the static
657 propagatedInvokeType.isMoreSpecificThan(staticInvokeType))) { 666 // type.
658 // Don't store the propagated invoke type unless it's more specific than 667 //
659 // the static type. We still need to record the propagated parameter 668 // We still need to record the propagated parameter elements however,
660 // elements however, as that is used for the propagatedType downwards 669 // as they are used in propagatedType downwards inference of lambda
661 // inference of lambda parameters. 670 // parameters. So we don't want to clear the propagatedInvokeType variable.
662 node.propagatedInvokeType = propagatedInvokeType; 671 //
663 } else { 672 node.propagatedInvokeType =
664 node.propagatedInvokeType = null; 673 _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
665 }
666 674
667 ArgumentList argumentList = node.argumentList; 675 ArgumentList argumentList = node.argumentList;
668 if (staticInvokeType != null) { 676 if (staticInvokeType != null) {
669 List<ParameterElement> parameters = 677 List<ParameterElement> parameters =
670 _computeCorrespondingParameters(argumentList, staticInvokeType); 678 _computeCorrespondingParameters(argumentList, staticInvokeType);
671 if (parameters != null) { 679 if (parameters != null) {
672 argumentList.correspondingStaticParameters = parameters; 680 argumentList.correspondingStaticParameters = parameters;
673 } 681 }
674 } 682 }
675 if (propagatedInvokeType != null) { 683 if (propagatedInvokeType != null) {
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after
1321 if (callMethod != null) { 1329 if (callMethod != null) {
1322 return _resolveArgumentsToFunction(false, argumentList, callMethod); 1330 return _resolveArgumentsToFunction(false, argumentList, callMethod);
1323 } 1331 }
1324 } else if (type is FunctionType) { 1332 } else if (type is FunctionType) {
1325 return _resolveArgumentsToParameters( 1333 return _resolveArgumentsToParameters(
1326 false, argumentList, type.parameters); 1334 false, argumentList, type.parameters);
1327 } 1335 }
1328 return null; 1336 return null;
1329 } 1337 }
1330 1338
1339 DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
1340 if (element == null) {
1341 // TODO(jmesserly): should we return `dynamic` in this case?
1342 // Otherwise we have to guard against `null` every time we use
1343 // `staticInvokeType`.
1344 // If we do return `dynamic` we need to be careful that this doesn't
1345 // adversely affect propagatedType code path. But it shouldn't because
1346 // we'll discard `dynamic` anyway (see _propagatedInvokeTypeIfBetter).
1347 return null;
1348 }
1349
1350 DartType invokeType;
1351 if (element is PropertyAccessorElement) {
1352 invokeType = element.returnType;
1353 } else if (element is ExecutableElement) {
1354 invokeType = element.type;
1355 } else if (element is VariableElement) {
1356 invokeType = _promoteManager.getStaticType(element);
1357 }
1358
1359 return _resolveGenericMethod(
1360 invokeType, node.typeArguments, node.methodName);
1361 }
1362
1331 /** 1363 /**
1332 * If the given [element] is a setter, return the getter associated with it. 1364 * If the given [element] is a setter, return the getter associated with it.
1333 * Otherwise, return the element unchanged. 1365 * Otherwise, return the element unchanged.
1334 */ 1366 */
1335 Element _convertSetterToGetter(Element element) { 1367 Element _convertSetterToGetter(Element element) {
1336 // TODO(brianwilkerson) Determine whether and why the element could ever be 1368 // TODO(brianwilkerson) Determine whether and why the element could ever be
1337 // a setter. 1369 // a setter.
1338 if (element is PropertyAccessorElement) { 1370 if (element is PropertyAccessorElement) {
1339 return element.variable.getter; 1371 return element.variable.getter;
1340 } 1372 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 if (staticType is FunctionType) { 1489 if (staticType is FunctionType) {
1458 // 1490 //
1459 // All function types are subtypes of 'Function', which is itself a 1491 // All function types are subtypes of 'Function', which is itself a
1460 // subclass of 'Object'. 1492 // subclass of 'Object'.
1461 // 1493 //
1462 staticType = _resolver.typeProvider.functionType; 1494 staticType = _resolver.typeProvider.functionType;
1463 } 1495 }
1464 return staticType; 1496 return staticType;
1465 } 1497 }
1466 1498
1467 DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
1468 if (element == null) {
1469 return null;
1470 }
1471
1472 DartType invokeType;
1473 if (element is PropertyAccessorElement) {
1474 invokeType = element.returnType;
1475 } else if (element is ExecutableElement) {
1476 invokeType = element.type;
1477 } else if (element is VariableElement) {
1478 invokeType = _promoteManager.getStaticType(element);
1479 }
1480
1481 //
1482 // Check for a generic method & apply type arguments if any were passed.
1483 //
1484 // TODO(jmesserly): support generic "call" methods on InterfaceType.
1485 if (invokeType is FunctionType) {
1486 FunctionType type = invokeType;
1487 List<TypeParameterElement> parameters = type.typeFormals;
1488
1489 NodeList<TypeName> arguments = node.typeArguments?.arguments;
1490 if (arguments != null && arguments.length != parameters.length) {
1491 // Wrong number of type arguments. Ignore them
1492 arguments = null;
1493 _resolver.reportErrorForNode(
1494 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
1495 node.methodName,
1496 [type, parameters.length, arguments?.length ?? 0]);
1497 }
1498 if (parameters.isNotEmpty) {
1499 if (arguments == null) {
1500 invokeType = _resolver.typeSystem.instantiateToBounds(type);
1501 } else {
1502 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
1503 }
1504 }
1505 }
1506
1507 return invokeType;
1508 }
1509
1510 /** 1499 /**
1511 * Return `true` if the given [expression] is a prefix for a deferred import. 1500 * Return `true` if the given [expression] is a prefix for a deferred import.
1512 */ 1501 */
1513 bool _isDeferredPrefix(Expression expression) { 1502 bool _isDeferredPrefix(Expression expression) {
1514 if (expression is! SimpleIdentifier) { 1503 if (expression is! SimpleIdentifier) {
1515 return false; 1504 return false;
1516 } 1505 }
1517 Element element = (expression as SimpleIdentifier).staticElement; 1506 Element element = (expression as SimpleIdentifier).staticElement;
1518 if (element is! PrefixElement) { 1507 if (element is! PrefixElement) {
1519 return false; 1508 return false;
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
1744 // Internal error: Unmapped assignment operator. 1733 // Internal error: Unmapped assignment operator.
1745 AnalysisEngine.instance.logger.logError( 1734 AnalysisEngine.instance.logger.logError(
1746 "Failed to map ${operator.lexeme} to it's corresponding operator"); 1735 "Failed to map ${operator.lexeme} to it's corresponding operator");
1747 return operator; 1736 return operator;
1748 } 1737 }
1749 break; 1738 break;
1750 } 1739 }
1751 } 1740 }
1752 1741
1753 /** 1742 /**
1743 * Determines if the [propagatedType] of the invoke is better (more specific)
1744 * than the [staticType]. If so it will be returned, otherwise returns null.
1745 */
1746 // TODO(jmesserly): can we refactor Resolver.recordPropagatedTypeIfBetter to
1747 // get some code sharing? Right now, this method is to support
1748 // `staticInvokeType` and `propagatedInvokeType`, and the one in Resolver is
1749 // for `staticType` and `propagatedType` on Expression.
1750 DartType _propagatedInvokeTypeIfBetter(
1751 DartType propagatedType, DartType staticType) {
1752 if (propagatedType != null &&
1753 (staticType == null || propagatedType.isMoreSpecificThan(staticType))) {
1754 return propagatedType;
1755 } else {
1756 return null;
1757 }
1758 }
1759
1760 /**
1754 * Record that the given [node] is undefined, causing an error to be reported 1761 * Record that the given [node] is undefined, causing an error to be reported
1755 * if appropriate. The [declaringElement] is the element inside which no 1762 * if appropriate. The [declaringElement] is the element inside which no
1756 * declaration was found. If this element is a proxy, no error will be 1763 * declaration was found. If this element is a proxy, no error will be
1757 * reported. If null, then an error will always be reported. The [errorCode] 1764 * reported. If null, then an error will always be reported. The [errorCode]
1758 * is the error code to report. The [arguments] are the arguments to the error 1765 * is the error code to report. The [arguments] are the arguments to the error
1759 * message. 1766 * message.
1760 */ 1767 */
1761 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, 1768 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode,
1762 AstNode node, List<Object> arguments) { 1769 AstNode node, List<Object> arguments) {
1763 if (_doesntHaveProxy(declaringElement)) { 1770 if (_doesntHaveProxy(declaringElement)) {
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
2067 if (element == null) { 2074 if (element == null) {
2068 element = classElement.getMethod(name); 2075 element = classElement.getMethod(name);
2069 } 2076 }
2070 if (element != null && element.isAccessibleIn(_definingLibrary)) { 2077 if (element != null && element.isAccessibleIn(_definingLibrary)) {
2071 return element; 2078 return element;
2072 } 2079 }
2073 return null; 2080 return null;
2074 } 2081 }
2075 2082
2076 /** 2083 /**
2084 * Check for a generic method & apply type arguments if any were passed.
2085 */
2086 DartType _resolveGenericMethod(
2087 DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
2088 // TODO(jmesserly): support generic "call" methods on InterfaceType.
2089 if (invokeType is FunctionType) {
2090 FunctionType type = invokeType;
2091 List<TypeParameterElement> parameters = type.typeFormals;
2092
2093 NodeList<TypeName> arguments = typeArguments?.arguments;
2094 if (arguments != null && arguments.length != parameters.length) {
2095 // Wrong number of type arguments. Ignore them
2096 arguments = null;
2097 _resolver.reportErrorForNode(
2098 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
2099 node,
2100 [type, parameters.length, arguments?.length ?? 0]);
2101 }
2102 if (parameters.isNotEmpty) {
2103 if (arguments == null) {
2104 invokeType = _resolver.typeSystem.instantiateToBounds(type);
2105 } else {
2106 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
2107 }
2108 }
2109 }
2110 return invokeType;
2111 }
2112
2113 /**
2077 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the 2114 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
2078 * element being invoked. If the returned element is a method, then the method 2115 * element being invoked. If the returned element is a method, then the method
2079 * will be invoked. If the returned element is a getter, the getter will be 2116 * will be invoked. If the returned element is a getter, the getter will be
2080 * invoked without arguments and the result of that invocation will then be 2117 * invoked without arguments and the result of that invocation will then be
2081 * invoked with the arguments. The [methodName] is the name of the method 2118 * invoked with the arguments. The [methodName] is the name of the method
2082 * being invoked ('m'). 2119 * being invoked ('m').
2083 */ 2120 */
2084 Element _resolveInvokedElement(SimpleIdentifier methodName) { 2121 Element _resolveInvokedElement(SimpleIdentifier methodName) {
2085 // 2122 //
2086 // Look first in the lexical scope. 2123 // Look first in the lexical scope.
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
2570 2607
2571 @override 2608 @override
2572 Element get staticElement => null; 2609 Element get staticElement => null;
2573 2610
2574 @override 2611 @override
2575 accept(AstVisitor visitor) => null; 2612 accept(AstVisitor visitor) => null;
2576 2613
2577 @override 2614 @override
2578 void visitChildren(AstVisitor visitor) {} 2615 void visitChildren(AstVisitor visitor) {}
2579 } 2616 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/ast.dart ('k') | pkg/analyzer/lib/src/generated/static_type_analyzer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698