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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 57b8060e5a88a58076ae9e7d7b372c382969978a..368da2a31f59b68cec55e1f196e2926ec16f9cf9 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -426,17 +426,26 @@ class ElementResolver extends SimpleAstVisitor<Object> {
@override
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
- // TODO(brianwilkerson) Can we ever resolve the function being invoked?
- Expression expression = node.function;
- if (expression is FunctionExpression) {
- FunctionExpression functionExpression = expression;
- ExecutableElement functionElement = functionExpression.element;
- ArgumentList argumentList = node.argumentList;
- List<ParameterElement> parameters =
- _resolveArgumentsToFunction(false, argumentList, functionElement);
- if (parameters != null) {
- argumentList.correspondingStaticParameters = parameters;
- }
+ Expression function = node.function;
+ DartType staticInvokeType =
+ _resolveGenericMethod(function.staticType, node.typeArguments, node);
+ DartType propagatedInvokeType = _resolveGenericMethod(
+ function.propagatedType, node.typeArguments, node);
+
+ node.staticInvokeType = staticInvokeType;
+ node.propagatedInvokeType =
+ _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
+
+ List<ParameterElement> parameters =
+ _computeCorrespondingParameters(node.argumentList, staticInvokeType);
+ if (parameters != null) {
+ node.argumentList.correspondingStaticParameters = parameters;
+ }
+
+ parameters = _computeCorrespondingParameters(
+ node.argumentList, propagatedInvokeType);
+ if (parameters != null) {
+ node.argumentList.correspondingPropagatedParameters = parameters;
}
return null;
}
@@ -652,17 +661,16 @@ class ElementResolver extends SimpleAstVisitor<Object> {
methodName.propagatedElement = propagatedElement;
node.staticInvokeType = staticInvokeType;
- if (propagatedInvokeType != null &&
- (staticInvokeType == 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;
- } else {
- node.propagatedInvokeType = null;
- }
+ //
+ // Store the propagated invoke type if it's more specific than the static
+ // type.
+ //
+ // We still need to record the propagated parameter elements however,
+ // as they are used in propagatedType downwards inference of lambda
+ // parameters. So we don't want to clear the propagatedInvokeType variable.
+ //
+ node.propagatedInvokeType =
+ _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
ArgumentList argumentList = node.argumentList;
if (staticInvokeType != null) {
@@ -1328,6 +1336,30 @@ class ElementResolver extends SimpleAstVisitor<Object> {
return null;
}
+ DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
+ if (element == null) {
+ // TODO(jmesserly): should we return `dynamic` in this case?
+ // Otherwise we have to guard against `null` every time we use
+ // `staticInvokeType`.
+ // If we do return `dynamic` we need to be careful that this doesn't
+ // adversely affect propagatedType code path. But it shouldn't because
+ // we'll discard `dynamic` anyway (see _propagatedInvokeTypeIfBetter).
+ 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);
+ }
+
+ return _resolveGenericMethod(
+ invokeType, node.typeArguments, node.methodName);
+ }
+
/**
* If the given [element] is a setter, return the getter associated with it.
* Otherwise, return the element unchanged.
@@ -1464,49 +1496,6 @@ 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.
*/
@@ -1751,6 +1740,24 @@ class ElementResolver extends SimpleAstVisitor<Object> {
}
/**
+ * Determines if the [propagatedType] of the invoke is better (more specific)
+ * than the [staticType]. If so it will be returned, otherwise returns null.
+ */
+ // TODO(jmesserly): can we refactor Resolver.recordPropagatedTypeIfBetter to
+ // get some code sharing? Right now, this method is to support
+ // `staticInvokeType` and `propagatedInvokeType`, and the one in Resolver is
+ // for `staticType` and `propagatedType` on Expression.
+ DartType _propagatedInvokeTypeIfBetter(
+ DartType propagatedType, DartType staticType) {
+ if (propagatedType != null &&
+ (staticType == null || propagatedType.isMoreSpecificThan(staticType))) {
+ return propagatedType;
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Record that the given [node] is undefined, causing an error to be reported
* if appropriate. The [declaringElement] is the element inside which no
* declaration was found. If this element is a proxy, no error will be
@@ -2074,6 +2081,36 @@ class ElementResolver extends SimpleAstVisitor<Object> {
}
/**
+ * Check for a generic method & apply type arguments if any were passed.
+ */
+ DartType _resolveGenericMethod(
+ DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
+ // TODO(jmesserly): support generic "call" methods on InterfaceType.
+ if (invokeType is FunctionType) {
+ FunctionType type = invokeType;
+ List<TypeParameterElement> parameters = type.typeFormals;
+
+ NodeList<TypeName> arguments = 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,
+ [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;
+ }
+
+ /**
* Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
* element being invoked. If the returned element is a method, then the method
* will be invoked. If the returned element is a getter, the getter will be
« 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