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

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?
Brian Wilkerson 2016/01/08 01:02:21 No. (1) We use `null` to mean that there is no ty
Jennifer Messerly 2016/01/11 18:49:09 So right now this method is used to populate "stat
Brian Wilkerson 2016/01/11 18:56:41 No. I was distracted by the propagated path. We sh
1342 return null;
1343 }
1344
1345 DartType invokeType;
1346 if (element is PropertyAccessorElement) {
1347 invokeType = element.returnType;
1348 } else if (element is ExecutableElement) {
1349 invokeType = element.type;
1350 } else if (element is VariableElement) {
1351 invokeType = _promoteManager.getStaticType(element);
1352 }
1353
1354 return _resolveGenericMethod(
1355 invokeType, node.typeArguments, node.methodName);
1356 }
1357
1331 /** 1358 /**
1332 * If the given [element] is a setter, return the getter associated with it. 1359 * If the given [element] is a setter, return the getter associated with it.
1333 * Otherwise, return the element unchanged. 1360 * Otherwise, return the element unchanged.
1334 */ 1361 */
1335 Element _convertSetterToGetter(Element element) { 1362 Element _convertSetterToGetter(Element element) {
1336 // TODO(brianwilkerson) Determine whether and why the element could ever be 1363 // TODO(brianwilkerson) Determine whether and why the element could ever be
1337 // a setter. 1364 // a setter.
1338 if (element is PropertyAccessorElement) { 1365 if (element is PropertyAccessorElement) {
1339 return element.variable.getter; 1366 return element.variable.getter;
1340 } 1367 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 if (staticType is FunctionType) { 1484 if (staticType is FunctionType) {
1458 // 1485 //
1459 // All function types are subtypes of 'Function', which is itself a 1486 // All function types are subtypes of 'Function', which is itself a
1460 // subclass of 'Object'. 1487 // subclass of 'Object'.
1461 // 1488 //
1462 staticType = _resolver.typeProvider.functionType; 1489 staticType = _resolver.typeProvider.functionType;
1463 } 1490 }
1464 return staticType; 1491 return staticType;
1465 } 1492 }
1466 1493
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 /** 1494 /**
1511 * Return `true` if the given [expression] is a prefix for a deferred import. 1495 * Return `true` if the given [expression] is a prefix for a deferred import.
1512 */ 1496 */
1513 bool _isDeferredPrefix(Expression expression) { 1497 bool _isDeferredPrefix(Expression expression) {
1514 if (expression is! SimpleIdentifier) { 1498 if (expression is! SimpleIdentifier) {
1515 return false; 1499 return false;
1516 } 1500 }
1517 Element element = (expression as SimpleIdentifier).staticElement; 1501 Element element = (expression as SimpleIdentifier).staticElement;
1518 if (element is! PrefixElement) { 1502 if (element is! PrefixElement) {
1519 return false; 1503 return false;
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
1744 // Internal error: Unmapped assignment operator. 1728 // Internal error: Unmapped assignment operator.
1745 AnalysisEngine.instance.logger.logError( 1729 AnalysisEngine.instance.logger.logError(
1746 "Failed to map ${operator.lexeme} to it's corresponding operator"); 1730 "Failed to map ${operator.lexeme} to it's corresponding operator");
1747 return operator; 1731 return operator;
1748 } 1732 }
1749 break; 1733 break;
1750 } 1734 }
1751 } 1735 }
1752 1736
1753 /** 1737 /**
1738 * Determines if the [propagatedType] of the invoke is better (more specific)
1739 * than the [staticType]. If so it will be returned, otherwise returns null.
1740 */
1741 DartType _propagatedInvokeTypeIfBetter(
Brian Wilkerson 2016/01/08 01:02:21 I think this is now being done in multiple places.
Jennifer Messerly 2016/01/11 18:49:09 Yeah, good idea, we can try and merge this logic w
1742 DartType propagatedType, DartType staticType) {
1743 if (propagatedType != null &&
1744 (staticType == null || propagatedType.isMoreSpecificThan(staticType))) {
1745 return propagatedType;
1746 } else {
1747 return null;
1748 }
1749 }
1750
1751 /**
1754 * Record that the given [node] is undefined, causing an error to be reported 1752 * Record that the given [node] is undefined, causing an error to be reported
1755 * if appropriate. The [declaringElement] is the element inside which no 1753 * if appropriate. The [declaringElement] is the element inside which no
1756 * declaration was found. If this element is a proxy, no error will be 1754 * 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] 1755 * 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 1756 * is the error code to report. The [arguments] are the arguments to the error
1759 * message. 1757 * message.
1760 */ 1758 */
1761 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, 1759 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode,
1762 AstNode node, List<Object> arguments) { 1760 AstNode node, List<Object> arguments) {
1763 if (_doesntHaveProxy(declaringElement)) { 1761 if (_doesntHaveProxy(declaringElement)) {
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
2067 if (element == null) { 2065 if (element == null) {
2068 element = classElement.getMethod(name); 2066 element = classElement.getMethod(name);
2069 } 2067 }
2070 if (element != null && element.isAccessibleIn(_definingLibrary)) { 2068 if (element != null && element.isAccessibleIn(_definingLibrary)) {
2071 return element; 2069 return element;
2072 } 2070 }
2073 return null; 2071 return null;
2074 } 2072 }
2075 2073
2076 /** 2074 /**
2075 * Check for a generic method & apply type arguments if any were passed.
2076 */
2077 DartType _resolveGenericMethod(
Brian Wilkerson 2016/01/08 01:02:21 Ditto
Jennifer Messerly 2016/01/11 18:49:09 Yeah, I was trying to make this method be the shar
Brian Wilkerson 2016/01/11 18:56:41 Agreed. A later CL is fine.
2078 DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
2079 // TODO(jmesserly): support generic "call" methods on InterfaceType.
2080 if (invokeType is FunctionType) {
2081 FunctionType type = invokeType;
2082 List<TypeParameterElement> parameters = type.typeFormals;
2083
2084 NodeList<TypeName> arguments = typeArguments?.arguments;
2085 if (arguments != null && arguments.length != parameters.length) {
2086 // Wrong number of type arguments. Ignore them
2087 arguments = null;
2088 _resolver.reportErrorForNode(
2089 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
2090 node,
2091 [type, parameters.length, arguments?.length ?? 0]);
2092 }
2093 if (parameters.isNotEmpty) {
2094 if (arguments == null) {
2095 invokeType = _resolver.typeSystem.instantiateToBounds(type);
2096 } else {
2097 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
2098 }
2099 }
2100 }
2101 return invokeType;
2102 }
2103
2104 /**
2077 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the 2105 * 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 2106 * 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 2107 * 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 2108 * 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 2109 * invoked with the arguments. The [methodName] is the name of the method
2082 * being invoked ('m'). 2110 * being invoked ('m').
2083 */ 2111 */
2084 Element _resolveInvokedElement(SimpleIdentifier methodName) { 2112 Element _resolveInvokedElement(SimpleIdentifier methodName) {
2085 // 2113 //
2086 // Look first in the lexical scope. 2114 // Look first in the lexical scope.
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
2570 2598
2571 @override 2599 @override
2572 Element get staticElement => null; 2600 Element get staticElement => null;
2573 2601
2574 @override 2602 @override
2575 accept(AstVisitor visitor) => null; 2603 accept(AstVisitor visitor) => null;
2576 2604
2577 @override 2605 @override
2578 void visitChildren(AstVisitor visitor) {} 2606 void visitChildren(AstVisitor visitor) {}
2579 } 2607 }
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