Resolve call method when defined by an extension

Change-Id: Ic1bc90241207bad2c0c0338dae4b1d2f32c0b021
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111310
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Brian Wilkerson 2019-07-31 18:12:26 +00:00
parent bd049f5b53
commit 0639908ecc
4 changed files with 53 additions and 12 deletions

View file

@ -705,6 +705,13 @@ class MethodInvocationResolver {
if (type is InterfaceType) {
var call = _inheritance.getMember(type, _nameCall);
if (call == null) {
var extension = _extensionMemberResolver.findExtension(
type, _nameCall.name, node.methodName);
if (extension != null) {
call = extension.getMethod(_nameCall.name);
}
}
if (call != null && call.kind == ElementKind.METHOD) {
type = call.type;
}

View file

@ -420,7 +420,7 @@ class ElementResolver extends SimpleAstVisitor<void> {
node.staticInvokeType = staticInvokeType;
List<ParameterElement> parameters =
_computeCorrespondingParameters(node.argumentList, staticInvokeType);
_computeCorrespondingParameters(node, staticInvokeType);
if (parameters != null) {
node.argumentList.correspondingStaticParameters = parameters;
}
@ -999,10 +999,10 @@ class ElementResolver extends SimpleAstVisitor<void> {
* arguments, or `null` if no correspondence could be computed.
*/
List<ParameterElement> _computeCorrespondingParameters(
ArgumentList argumentList, DartType type) {
FunctionExpressionInvocation invocation, DartType type) {
ArgumentList argumentList = invocation.argumentList;
if (type is InterfaceType) {
MethodElement callMethod =
type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
MethodElement callMethod = invocation.staticElement;
if (callMethod != null) {
return _resolveArgumentsToFunction(false, argumentList, callMethod);
}
@ -1083,16 +1083,17 @@ class ElementResolver extends SimpleAstVisitor<void> {
/**
* Check for a generic method & apply type arguments if any were passed.
*/
DartType _instantiateGenericMethod(
DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
DartType _instantiateGenericMethod(DartType invokeType,
TypeArgumentList typeArguments, FunctionExpressionInvocation invocation) {
DartType parameterizableType;
List<TypeParameterElement> parameters;
if (invokeType is FunctionType) {
parameterizableType = invokeType;
parameters = invokeType.typeFormals;
} else if (invokeType is InterfaceType) {
MethodElement callMethod = invokeType.lookUpMethod(
FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
MethodElement callMethod =
_lookUpCallMethod(invokeType, invocation.function);
invocation.staticElement = callMethod;
parameterizableType = callMethod?.type;
parameters = (parameterizableType as FunctionType)?.typeFormals;
}
@ -1102,7 +1103,7 @@ class ElementResolver extends SimpleAstVisitor<void> {
if (arguments != null && arguments.length != parameters.length) {
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
node,
invocation,
[parameterizableType, parameters.length, arguments?.length ?? 0]);
// Wrong number of type arguments. Ignore them.
arguments = null;
@ -1211,7 +1212,25 @@ class ElementResolver extends SimpleAstVisitor<void> {
}
/**
* Look up the getter with the given [name] in the given [type]. Return
* Return the element representing the `call` method that is defined for the
* given [type]. If there are multiple `call` methods defined by extensions,
* use the given [node] to report the error.
*/
MethodElement _lookUpCallMethod(InterfaceType type, Expression node) {
MethodElement callMethod = type.lookUpMethod(
FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
if (callMethod == null) {
var extension = _extensionMemberResolver.findExtension(
type, FunctionElement.CALL_METHOD_NAME, node);
if (extension != null) {
callMethod = extension.getMethod(FunctionElement.CALL_METHOD_NAME);
}
}
return callMethod;
}
/**
* Look up the getter with the given [getterName] in the given [type]. Return
* the element representing the getter that was found, or `null` if there is
* no getter with the given name. The [target] is the target of the
* invocation, or `null` if there is no target.

View file

@ -911,6 +911,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
if (!_checkForNullableDereference(functionExpression) &&
!_checkForUseOfVoidResult(functionExpression) &&
!_checkForUseOfNever(functionExpression) &&
node.staticElement == null &&
!_isFunctionType(expressionType)) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,

View file

@ -168,7 +168,6 @@ f(C c) {
assertInvokeType(invocation, 'int Function(int)');
}
@failingTest
test_instance_call_fromExtension() async {
await assertNoErrorsInCode('''
class C {}
@ -217,6 +216,22 @@ f(C c) {
assertElement(assignment, findElement.method('+', of: 'E'));
}
test_instance_call_fromExtension_int() async {
await assertNoErrorsInCode('''
extension E on int {
int call(int x) => 0;
}
f() {
1(2);
}
''');
var invocation = findNode.functionExpressionInvocation('1(2)');
expect(invocation.staticInvokeType.element,
same(findElement.method('call', of: 'E')));
assertInvokeType(invocation, 'int Function(int)');
}
test_instance_getter_methodInvocation() async {
await assertNoErrorsInCode('''
class C {}
@ -874,7 +889,6 @@ f() {
/// by code internal to (within) the extension declaration.
@reflectiveTest
class ExtensionMethodsInternalReferenceTest extends BaseExtensionMethodsTest {
@failingTest
test_instance_call() async {
await assertNoErrorsInCode('''
class C {}