Issue 49842. Resolve call() invocation without a receiver.

Bug: https://github.com/dart-lang/sdk/issues/49842
Change-Id: I44a274da4ca209b34710d6bfc3ae3d18ee62058c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256704
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-08-30 15:47:38 +00:00 committed by Commit Bot
parent 36affd7014
commit 8e4dc26b2a
4 changed files with 104 additions and 39 deletions

View file

@ -175,13 +175,6 @@ class MethodInvocationResolver with ScopeHelpers {
receiverType = _typeSystem.promoteToNonNull(receiverType);
}
if (_typeSystem.isFunctionBounded(receiverType)) {
_resolveReceiverFunctionBounded(
node, receiver, receiverType, nameNode, name, whyNotPromotedList,
contextType: contextType);
return;
}
if (receiver is TypeLiteralImpl &&
receiver.type.typeArguments != null &&
receiver.type.type is FunctionType) {
@ -487,36 +480,6 @@ class MethodInvocationResolver with ScopeHelpers {
.resolveInvocation(rawType: rawType);
}
void _resolveReceiverFunctionBounded(
MethodInvocationImpl node,
Expression receiver,
DartType receiverType,
SimpleIdentifierImpl nameNode,
String name,
List<WhyNotPromotedGetter> whyNotPromotedList,
{required DartType? contextType}) {
if (name == FunctionElement.CALL_METHOD_NAME) {
_setResolution(node, receiverType, whyNotPromotedList,
contextType: contextType);
// TODO(scheglov) Replace this with using FunctionType directly.
// Here was erase resolution that _setResolution() sets.
nameNode.staticElement = null;
nameNode.staticType = _dynamicType;
return;
}
_resolveReceiverType(
node: node,
receiver: receiver,
receiverType: receiverType,
nameNode: nameNode,
name: name,
receiverErrorNode: nameNode,
whyNotPromotedList: whyNotPromotedList,
contextType: contextType,
);
}
void _resolveReceiverNever(MethodInvocationImpl node, Expression receiver,
DartType receiverType, List<WhyNotPromotedGetter> whyNotPromotedList,
{required DartType? contextType}) {
@ -790,6 +753,18 @@ class MethodInvocationResolver with ScopeHelpers {
nameErrorEntity: nameNode,
);
final callFunctionType = result.callFunctionType;
if (callFunctionType != null) {
assert(name == FunctionElement.CALL_METHOD_NAME);
_setResolution(node, callFunctionType, whyNotPromotedList,
contextType: contextType);
// TODO(scheglov) Replace this with using FunctionType directly.
// Here was erase resolution that _setResolution() sets.
nameNode.staticElement = null;
nameNode.staticType = _dynamicType;
return;
}
var target = result.getter;
if (target != null) {
nameNode.staticElement = target;

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
/// The result of attempting to resolve an identifier to elements.
class ResolutionResult {
@ -43,6 +44,9 @@ class ResolutionResult {
/// when `dynamicTarget.foo`).
final bool needsSetterError;
/// The [FunctionType] referenced with `call`.
final FunctionType? callFunctionType;
/// Initialize a newly created result to represent resolving a single
/// reading and / or writing result.
ResolutionResult({
@ -50,6 +54,7 @@ class ResolutionResult {
this.needsGetterError = true,
this.setter,
this.needsSetterError = true,
this.callFunctionType,
}) : state = _ResolutionResultState.single;
/// Initialize a newly created result with no elements and the given [state].
@ -57,7 +62,8 @@ class ResolutionResult {
: getter = null,
needsGetterError = true,
setter = null,
needsSetterError = true;
needsSetterError = true,
callFunctionType = null;
/// Return `true` if this result represents the case where multiple ambiguous
/// elements were found.

View file

@ -186,7 +186,13 @@ class TypePropertyResolver {
if (receiverTypeResolved is FunctionType &&
_name == FunctionElement.CALL_METHOD_NAME) {
return _toResult();
return ResolutionResult(
getter: null,
needsGetterError: false,
setter: null,
needsSetterError: false,
callFunctionType: receiverTypeResolved,
);
}
if (receiverTypeResolved is NeverType) {

View file

@ -7432,6 +7432,84 @@ MethodInvocation
}
}
test_noReceiver_call_extension_on_FunctionType() async {
await assertNoErrorsInCode(r'''
extension E on int Function() {
void f() {
call();
}
}
''');
final node = findNode.methodInvocation('call()');
if (isNullSafetyEnabled) {
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: call
staticElement: <null>
staticType: dynamic
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int Function()
staticType: int
''');
} else {
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: call
staticElement: <null>
staticType: dynamic
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int* Function()*
staticType: int*
''');
}
}
test_noReceiver_call_extension_on_FunctionType_bounded() async {
await assertNoErrorsInCode(r'''
extension E<T extends int Function()> on T {
void f() {
call();
}
}
''');
final node = findNode.methodInvocation('call()');
if (isNullSafetyEnabled) {
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: call
staticElement: <null>
staticType: dynamic
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int Function()
staticType: int
''');
} else {
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: call
staticElement: <null>
staticType: dynamic
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int* Function()*
staticType: int*
''');
}
}
test_noReceiver_getter_superClass() async {
await assertNoErrorsInCode(r'''
class A {