mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
Make MethodInvocationImpl.methodNameType a synonym of staticInvokeType if the target element is not a getter.
So, that type inference that updates staticInvokeType later, in StaticTypeAnalyzer._inferGenericInvocationExpression() also implicitly updates methodNameType. This fixes the new set of exceptions that we saw right before holidays. I'm running them now, most are green, no reds yet. R=brianwilkerson@google.com, paulberry@google.com Change-Id: I53030a1a62a2a669549a47680c6c0c98b4031383 Reviewed-on: https://dart-review.googlesource.com/c/88227 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
c32737cc4c
commit
d200089583
4 changed files with 107 additions and 24 deletions
|
@ -7766,15 +7766,10 @@ class MethodInvocationImpl extends InvocationExpressionImpl
|
|||
SimpleIdentifierImpl _methodName;
|
||||
|
||||
/**
|
||||
* The type invoke of the [methodName].
|
||||
*
|
||||
* If the target element is a [MethodElement], this is the same as the
|
||||
* [staticInvokeType]. If the target element is a [PropertyAccessorElement],
|
||||
* presumably returning an [ExecutableElement] so that it can be invoked
|
||||
* in this [MethodInvocation], then this type is the type of the accessor,
|
||||
* and the [staticInvokeType] is the invoked type of the returned element.
|
||||
* The invoke type of the [methodName] if the target element is a getter,
|
||||
* or `null` otherwise.
|
||||
*/
|
||||
DartType methodNameType;
|
||||
DartType _methodNameType;
|
||||
|
||||
/**
|
||||
* Initialize a newly created method invocation. The [target] and [operator]
|
||||
|
@ -7826,6 +7821,26 @@ class MethodInvocationImpl extends InvocationExpressionImpl
|
|||
_methodName = _becomeParentOf(identifier as SimpleIdentifierImpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* The invoke type of the [methodName].
|
||||
*
|
||||
* If the target element is a [MethodElement], this is the same as the
|
||||
* [staticInvokeType]. If the target element is a getter, presumably
|
||||
* returning an [ExecutableElement] so that it can be invoked in this
|
||||
* [MethodInvocation], then this type is the type of the getter, and the
|
||||
* [staticInvokeType] is the invoked type of the returned element.
|
||||
*/
|
||||
DartType get methodNameType => _methodNameType ?? staticInvokeType;
|
||||
|
||||
/**
|
||||
* Set the [methodName] invoke type, only if the target element is a getter.
|
||||
* Otherwise, the target element itself is invoked, [_methodNameType] is
|
||||
* `null`, and the getter will return [staticInvokeType].
|
||||
*/
|
||||
set methodNameType(DartType methodNameType) {
|
||||
_methodNameType = methodNameType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get precedence => 15;
|
||||
|
||||
|
|
|
@ -139,9 +139,14 @@ class MethodInvocationResolver {
|
|||
return null;
|
||||
}
|
||||
|
||||
DartType _getCalleeType(FunctionType targetType) {
|
||||
/// If the element of the invoked [targetType] is a getter, then actually
|
||||
/// the return type of the [targetType] is invoked. So, remember the
|
||||
/// [targetType] into [MethodInvocationImpl.methodNameType] and return the
|
||||
/// actual invoked type.
|
||||
DartType _getCalleeType(MethodInvocation node, FunctionType targetType) {
|
||||
if (targetType.element.kind == ElementKind.GETTER) {
|
||||
var calleeType = (targetType as FunctionTypeImpl).returnType;
|
||||
(node as MethodInvocationImpl).methodNameType = targetType;
|
||||
var calleeType = targetType.returnType;
|
||||
calleeType = _resolveTypeParameter(calleeType);
|
||||
return calleeType;
|
||||
}
|
||||
|
@ -328,9 +333,7 @@ class MethodInvocationResolver {
|
|||
|
||||
var targetType = _inheritance.getMember(receiverType, _currentName);
|
||||
if (targetType != null) {
|
||||
(node as MethodInvocationImpl).methodNameType = targetType;
|
||||
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
var calleeType = _getCalleeType(node, targetType);
|
||||
|
||||
// TODO(scheglov) This is bad, we have to create members here.
|
||||
// Find a way to avoid this.
|
||||
|
@ -382,7 +385,7 @@ class MethodInvocationResolver {
|
|||
element = multiply.conflictingElements[0];
|
||||
}
|
||||
if (element is ExecutableElement) {
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
var calleeType = _getCalleeType(node, element.type);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
if (element is VariableElement) {
|
||||
|
@ -407,7 +410,7 @@ class MethodInvocationResolver {
|
|||
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
var calleeType = _getCalleeType(node, targetType);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
|
||||
|
@ -456,7 +459,7 @@ class MethodInvocationResolver {
|
|||
}
|
||||
|
||||
if (element is ExecutableElement) {
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
var calleeType = _getCalleeType(node, element.type);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
|
||||
|
@ -479,7 +482,7 @@ class MethodInvocationResolver {
|
|||
// If there is that concrete dispatch target, then we are done.
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
var calleeType = _getCalleeType(node, targetType);
|
||||
_setResolution(node, calleeType);
|
||||
return;
|
||||
}
|
||||
|
@ -490,7 +493,7 @@ class MethodInvocationResolver {
|
|||
targetType = _inheritance.getInherited(receiverType, _currentName);
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
var calleeType = _getCalleeType(node, targetType);
|
||||
_setResolution(node, calleeType);
|
||||
|
||||
ClassElementImpl receiverSuperClass = AbstractClassElementImpl.getImpl(
|
||||
|
@ -525,7 +528,7 @@ class MethodInvocationResolver {
|
|||
if (element != null) {
|
||||
if (element is ExecutableElement) {
|
||||
nameNode.staticElement = element;
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
var calleeType = _getCalleeType(node, element.type);
|
||||
_setResolution(node, calleeType);
|
||||
} else {
|
||||
_reportInvocationOfNonFunction(node);
|
||||
|
|
|
@ -282,7 +282,11 @@ main(C c) {
|
|||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
_assertInvalidInvocation('c.foo();', findElement.getter('foo'));
|
||||
_assertInvalidInvocation(
|
||||
'c.foo();',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → dynamic',
|
||||
);
|
||||
}
|
||||
|
||||
test_error_invocationOfNonFunction_OK_dynamicGetter_superClass() async {
|
||||
|
@ -299,7 +303,11 @@ class B extends A {
|
|||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
_assertInvalidInvocation('foo();', findElement.getter('foo'));
|
||||
_assertInvalidInvocation(
|
||||
'foo();',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → dynamic',
|
||||
);
|
||||
}
|
||||
|
||||
test_error_invocationOfNonFunction_OK_dynamicGetter_thisClass() async {
|
||||
|
@ -314,7 +322,11 @@ class C {
|
|||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
_assertInvalidInvocation('foo();', findElement.getter('foo'));
|
||||
_assertInvalidInvocation(
|
||||
'foo();',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → dynamic',
|
||||
);
|
||||
}
|
||||
|
||||
test_error_invocationOfNonFunction_OK_Function() async {
|
||||
|
@ -346,6 +358,7 @@ class C<T extends MyFunction> {
|
|||
findNode.methodInvocation('foo(0)'),
|
||||
findElement.getter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → T',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -366,6 +379,7 @@ main() {
|
|||
_assertInvalidInvocation(
|
||||
'foo()',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → int',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -386,6 +400,7 @@ class C {
|
|||
_assertInvalidInvocation(
|
||||
'foo()',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → int',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -408,6 +423,7 @@ class B extends A {
|
|||
_assertInvalidInvocation(
|
||||
'foo()',
|
||||
findElement.getter('foo'),
|
||||
expectedMethodNameType: '() → int',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -822,6 +838,7 @@ main(C<void> c) {
|
|||
'c.foo()',
|
||||
findElement.getter('foo'),
|
||||
expectedNameType: 'void',
|
||||
expectedMethodNameType: '() → void',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -878,6 +895,7 @@ main() {
|
|||
'foo()',
|
||||
findElement.topGet('foo'),
|
||||
expectedNameType: 'void',
|
||||
expectedMethodNameType: '() → void',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -996,6 +1014,7 @@ main() {
|
|||
invocation,
|
||||
findElement.getter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
assertClassRef(invocation.target, findElement.class_('C'));
|
||||
}
|
||||
|
@ -1113,6 +1132,7 @@ main() {
|
|||
invocation,
|
||||
import.topGetter('foo'),
|
||||
'(int, int) → int',
|
||||
expectedMethodNameType: '() → <T>(T, T) → T',
|
||||
);
|
||||
assertImportPrefix(invocation.target, import.prefix);
|
||||
}
|
||||
|
@ -1161,6 +1181,7 @@ main(C c) {
|
|||
invocation,
|
||||
findElement.getter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1182,6 +1203,31 @@ main(C c) {
|
|||
invocation,
|
||||
findElement.method('foo'),
|
||||
'(int) → void',
|
||||
expectedMethodNameType: '(int) → void',
|
||||
);
|
||||
}
|
||||
|
||||
test_hasReceiver_instance_method_generic() async {
|
||||
addTestFile(r'''
|
||||
class C {
|
||||
T foo<T>(T a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
main(C c) {
|
||||
c.foo(0);
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
|
||||
var invocation = findNode.methodInvocation('foo(0);');
|
||||
assertMethodInvocation(
|
||||
invocation,
|
||||
findElement.method('foo'),
|
||||
'(int) → int',
|
||||
expectedMethodNameType: '(int) → int',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1265,6 +1311,7 @@ main() {
|
|||
invocation,
|
||||
import.class_('C').getGetter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
|
||||
PrefixedIdentifier target = invocation.target;
|
||||
|
@ -1323,6 +1370,7 @@ class B extends A {
|
|||
invocation,
|
||||
findElement.getter('foo', of: 'A'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
assertSuperExpression(invocation.target);
|
||||
}
|
||||
|
@ -1392,6 +1440,7 @@ class B extends A {
|
|||
invocation,
|
||||
findElement.getter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1413,6 +1462,7 @@ class C {
|
|||
invocation,
|
||||
findElement.getter('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1570,6 +1620,7 @@ main() {
|
|||
invocation,
|
||||
findElement.topFunction('foo'),
|
||||
'(int) → void',
|
||||
expectedMethodNameType: '(int) → void',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1589,6 +1640,7 @@ main() {
|
|||
invocation,
|
||||
findElement.topGet('foo'),
|
||||
'(int) → double',
|
||||
expectedMethodNameType: '() → (int) → double',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1608,6 +1660,7 @@ main() {
|
|||
invocation,
|
||||
findElement.topGet('foo'),
|
||||
'(int) → void',
|
||||
expectedMethodNameType: '() → (int) → void',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1643,7 +1696,9 @@ main() {
|
|||
}
|
||||
|
||||
void _assertInvalidInvocation(String search, Element expectedElement,
|
||||
{String expectedNameType, bool dynamicNameType: false}) {
|
||||
{String expectedMethodNameType,
|
||||
String expectedNameType,
|
||||
bool dynamicNameType: false}) {
|
||||
var invocation = findNode.methodInvocation(search);
|
||||
if (dynamicNameType) {
|
||||
assertTypeDynamic(invocation.methodName);
|
||||
|
@ -1653,6 +1708,7 @@ main() {
|
|||
invocation,
|
||||
expectedElement,
|
||||
'dynamic',
|
||||
expectedMethodNameType: expectedMethodNameType,
|
||||
expectedNameType: expectedNameType,
|
||||
expectedType: 'dynamic',
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:analyzer/dart/ast/ast.dart';
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/element/handle.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
|
@ -249,7 +250,11 @@ mixin ResolutionTest implements ResourceProviderMixin {
|
|||
|
||||
void assertMethodInvocation(MethodInvocation invocation,
|
||||
Element expectedElement, String expectedInvokeType,
|
||||
{String expectedNameType, String expectedType}) {
|
||||
{String expectedMethodNameType,
|
||||
String expectedNameType,
|
||||
String expectedType}) {
|
||||
MethodInvocationImpl invocationImpl = invocation;
|
||||
|
||||
// TODO(scheglov) Check for Member.
|
||||
var element = invocation.methodName.staticElement;
|
||||
if (element is Member) {
|
||||
|
@ -273,6 +278,10 @@ mixin ResolutionTest implements ResourceProviderMixin {
|
|||
|
||||
expectedType ??= _extractReturnType(expectedInvokeType);
|
||||
assertType(invocation, expectedType);
|
||||
|
||||
expectedMethodNameType ??= expectedInvokeType;
|
||||
assertElementTypeString(
|
||||
invocationImpl.methodNameType, expectedMethodNameType);
|
||||
}
|
||||
|
||||
void assertPropertyAccess(
|
||||
|
|
Loading…
Reference in a new issue