Fix #33194, handle type parameters on implicit call tearoffs.
Bug: 33194
Change-Id: Iecf3d2bdf1dcd1a05ef128f10cd2fa374f9b47ca
Reviewed-on: https://dart-review.googlesource.com/64822
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Jenny Messerly <jmesserly@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index ac71287..56213b8 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -520,6 +520,11 @@
E accept<E>(AstVisitor<E> visitor);
/**
+ * Return the token before [target] or `null` if it cannot be found.
+ */
+ Token findPrevious(Token target);
+
+ /**
* Return the most immediate ancestor of this node for which the [predicate]
* returns `true`, or `null` if there is no such ancestor. Note that this node
* will never be returned.
@@ -533,11 +538,6 @@
E getProperty<E>(String name);
/**
- * Return the token before [target] or `null` if it cannot be found.
- */
- Token findPrevious(Token target);
-
- /**
* Set the value of the property with the given [name] to the given [value].
* If the value is `null`, the property will effectively be removed.
*/
@@ -4469,9 +4469,9 @@
* information, or `null` if the AST structure has not been resolved, or if
* the invoke could not be resolved.
*
- * This will usually be a [FunctionType], but it can also be an
- * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
- * interface type that implements `Function`.
+ * This will usually be a [FunctionType], but it can also be `dynamic` or
+ * `Function`. In the case of interface types that have a `call` method, we
+ * store the type of that `call` method here as parameterized.
*/
DartType get staticInvokeType;
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 94c6855..a782664 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -1622,33 +1622,45 @@
*/
DartType _instantiateGenericMethod(
DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
- // TODO(jmesserly): support generic "call" methods on InterfaceType.
+ DartType parameterizableType;
+ List<TypeParameterElement> parameters;
if (invokeType is FunctionType) {
- List<TypeParameterElement> parameters = invokeType.typeFormals;
+ parameterizableType = invokeType;
+ parameters = invokeType.typeFormals;
+ } else if (invokeType is InterfaceType) {
+ MethodElement callMethod = invokeType.lookUpMethod(
+ FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
+ parameterizableType = callMethod?.type;
+ parameters = (parameterizableType as FunctionType)?.typeFormals;
+ }
+ if (parameterizableType is ParameterizedType) {
NodeList<TypeAnnotation> arguments = typeArguments?.arguments;
if (arguments != null && arguments.length != parameters.length) {
if (_resolver.strongMode) {
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
node,
- [invokeType, parameters.length, arguments?.length ?? 0]);
+ [parameterizableType, parameters.length, arguments?.length ?? 0]);
} else {
_resolver.errorReporter.reportErrorForNode(
HintCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
node,
- [invokeType, parameters.length, arguments?.length ?? 0]);
+ [parameterizableType, parameters.length, arguments?.length ?? 0]);
}
// Wrong number of type arguments. Ignore them.
arguments = null;
}
if (parameters.isNotEmpty) {
if (arguments == null) {
- return _resolver.typeSystem.instantiateToBounds(invokeType);
+ return _resolver.typeSystem.instantiateToBounds(parameterizableType);
} else {
- return invokeType.instantiate(arguments.map((n) => n.type).toList());
+ return parameterizableType
+ .instantiate(arguments.map((n) => n.type).toList());
}
}
+
+ return parameterizableType;
}
return invokeType;
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1371020..25343f2 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -467,10 +467,10 @@
_checkForAbstractSuperMemberReference(realTarget, node.methodName);
_checkForNullAwareHints(node, node.operator);
DartType staticInvokeType = node.staticInvokeType;
- if (staticInvokeType is InterfaceType) {
- MethodElement methodElement = staticInvokeType.lookUpMethod(
- FunctionElement.CALL_METHOD_NAME, _currentLibrary);
- _checkForDeprecatedMemberUse(methodElement, node);
+ Element callElement = staticInvokeType?.element;
+ if (callElement is MethodElement &&
+ callElement.name == FunctionElement.CALL_METHOD_NAME) {
+ _checkForDeprecatedMemberUse(callElement, node);
}
return super.visitMethodInvocation(node);
}
@@ -793,9 +793,8 @@
} else if (displayName == FunctionElement.CALL_METHOD_NAME &&
node is MethodInvocation &&
node.staticInvokeType is InterfaceType) {
- displayName = "${resolutionMap
- .staticInvokeTypeForInvocationExpression(node)
- .displayName}.${element.displayName}";
+ displayName =
+ "${resolutionMap.staticInvokeTypeForInvocationExpression(node).displayName}.${element.displayName}";
}
_errorReporter.reportErrorForNode(
HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
@@ -4706,8 +4705,7 @@
typeAnalyzer.thisType = enclosingClass?.type;
if (enclosingClass == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for class declaration ${node.name
- .name} in ${definingLibrary.source.fullName}",
+ "Missing element for class declaration ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
// Don't try to re-resolve the initializers if we cannot set up the
// right name scope for resolution.
@@ -7443,8 +7441,7 @@
try {
if (classElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for class declaration ${node.name
- .name} in ${definingLibrary.source.fullName}",
+ "Missing element for class declaration ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
super.visitClassDeclaration(node);
} else {
@@ -7572,8 +7569,7 @@
try {
if (classElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for enum declaration ${node.name
- .name} in ${definingLibrary.source.fullName}",
+ "Missing element for enum declaration ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
super.visitEnumDeclaration(node);
} else {
@@ -7689,8 +7685,7 @@
try {
if (functionElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for top-level function ${node.name
- .name} in ${definingLibrary.source.fullName}",
+ "Missing element for top-level function ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new FunctionScope(nameScope, functionElement);
@@ -7766,8 +7761,7 @@
ParameterElement parameterElement = node.element;
if (parameterElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for function typed formal parameter ${node
- .identifier.name} in ${definingLibrary.source.fullName}",
+ "Missing element for function typed formal parameter ${node.identifier.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new EnclosedScope(nameScope);
@@ -7868,8 +7862,7 @@
ExecutableElement methodElement = node.element;
if (methodElement == null) {
AnalysisEngine.instance.logger.logInformation(
- "Missing element for method ${node.name.name} in ${definingLibrary
- .source.fullName}",
+ "Missing element for method ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
nameScope = new FunctionScope(nameScope, methodElement);
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 4992e56..c47e992 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -4966,6 +4966,21 @@
verify([source]);
}
+ test_parametricCallFunction() async {
+ Source source = addSource(r'''
+f() {
+ var c = new C();
+ c<String>().codeUnits;
+}
+
+class C {
+ T call<T>() => null;
+}''');
+ await computeAnalysisResult(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
test_prefixCollidesWithTopLevelMembers() async {
addNamedSource("/lib.dart", r'''
library lib;