Chromium Code Reviews| Index: pkg/analyzer/lib/src/task/strong/checker.dart |
| diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart |
| index 19e1c8c02bbc57e12372d140195c568a86a416b5..2aa5af0c0e077eb0da0425eb76c34592e1d4b0a8 100644 |
| --- a/pkg/analyzer/lib/src/task/strong/checker.dart |
| +++ b/pkg/analyzer/lib/src/task/strong/checker.dart |
| @@ -29,6 +29,27 @@ bool isKnownFunction(Expression expression) { |
| element is MethodElement && element.isStatic; |
| } |
| +/// Given an [expression] and a corresponding [typeSystem] and [typeProvider], |
| +/// gets the known static type of the expression. |
| +/// |
| +/// Normally when we ask for an expression's type, we get the type of the |
| +/// storage slot that would contain it. For function types, this is necessarily |
| +/// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're |
| +/// interested in the expression's own type, it can often be a "strict arrow" |
| +/// because we know it evaluates to a specific, concrete function, and we can |
| +/// treat "dynamic" as top for that case, which is more permissive. |
| +DartType getDefiniteType( |
| + Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) { |
| + DartType type = expression.staticType ?? DynamicTypeImpl.instance; |
| + if (typeSystem is StrongTypeSystemImpl && |
| + type is FunctionType && |
| + _hasStrictArrow(expression)) { |
| + // Remove fuzzy arrow if possible. |
| + return typeSystem.functionTypeToConcreteType(typeProvider, type); |
| + } |
| + return type; |
| +} |
| + |
| bool _hasStrictArrow(Expression expression) { |
| var element = _getKnownElement(expression); |
| return element is FunctionElement || element is MethodElement; |
| @@ -187,14 +208,15 @@ class CodeChecker extends RecursiveAstVisitor { |
| void checkBoolean(Expression expr) => |
| checkAssignment(expr, typeProvider.boolType); |
| - void checkFunctionApplication( |
| - Expression node, Expression f, ArgumentList list) { |
| - if (_isDynamicCall(f)) { |
| + void checkFunctionApplication(InvocationExpression node) { |
|
Jennifer Messerly
2016/08/09 12:35:19
fyi -- I did a small refactor in patch set 2, taki
|
| + var ft = _getTypeAsCaller(node); |
| + |
| + if (_isDynamicCall(node, ft)) { |
| // If f is Function and this is a method invocation, we should have |
| // gotten an analyzer error, so no need to issue another error. |
| - _recordDynamicInvoke(node, f); |
| + _recordDynamicInvoke(node, node.function); |
| } else { |
| - checkArgumentList(list, _getTypeAsCaller(f)); |
| + checkArgumentList(node.argumentList, ft); |
| } |
| } |
| @@ -423,7 +445,7 @@ class CodeChecker extends RecursiveAstVisitor { |
| @override |
| void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| - checkFunctionApplication(node, node.function, node.argumentList); |
| + checkFunctionApplication(node); |
| node.visitChildren(this); |
| } |
| @@ -551,7 +573,7 @@ class CodeChecker extends RecursiveAstVisitor { |
| // we call [checkFunctionApplication]. |
| setIsDynamicInvoke(node.methodName, true); |
| } else { |
| - checkFunctionApplication(node, node.methodName, node.argumentList); |
| + checkFunctionApplication(node); |
| } |
| node.visitChildren(this); |
| } |
| @@ -969,42 +991,26 @@ class CodeChecker extends RecursiveAstVisitor { |
| } |
| } |
| - DartType _getStaticType(Expression expr) { |
| - DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| - |
| - // Remove fuzzy arrow if possible. |
| - if (t is FunctionType && _hasStrictArrow(expr)) { |
| - t = rules.functionTypeToConcreteType(typeProvider, t); |
| - } |
| - |
| - return t; |
| - } |
| + DartType _getStaticType(Expression expr) => |
|
vsm
2016/08/10 21:22:21
Maybe rename to _getDefiniteType?
The terminology
Jennifer Messerly
2016/08/10 22:28:09
good catch. Done!
|
| + getDefiniteType(expr, rules, typeProvider); |
| /// Given an expression, return its type assuming it is |
| /// in the caller position of a call (that is, accounting |
| /// for the possibility of a call method). Returns null |
| /// if expression is not statically callable. |
| - FunctionType _getTypeAsCaller(Expression node) { |
| - DartType t = _getStaticType(node); |
| - if (node is SimpleIdentifier) { |
| - Expression parent = node.parent; |
| - if (parent is MethodInvocation) { |
| - t = parent.staticInvokeType; |
| - } |
| - } |
| - if (t is InterfaceType) { |
| - return rules.getCallMethodType(t); |
| - } |
| - if (t is FunctionType) { |
| - return t; |
| + FunctionType _getTypeAsCaller(InvocationExpression node) { |
| + DartType type = node.staticInvokeType; |
| + if (type is FunctionType) { |
| + return type; |
| + } else if (type is InterfaceType) { |
| + return rules.getCallMethodType(type); |
| } |
| return null; |
| } |
| /// Returns `true` if the expression is a dynamic function call or method |
| /// invocation. |
| - bool _isDynamicCall(Expression call) { |
| - var ft = _getTypeAsCaller(call); |
| + bool _isDynamicCall(InvocationExpression call, FunctionType ft) { |
| // TODO(leafp): This will currently return true if t is Function |
| // This is probably the most correct thing to do for now, since |
| // this code is also used by the back end. Maybe revisit at some |
| @@ -1014,7 +1020,7 @@ class CodeChecker extends RecursiveAstVisitor { |
| // a dynamic parameter type requires a dynamic call in general. |
| // However, as an optimization, if we have an original definition, we know |
| // dynamic is reified as Object - in this case a regular call is fine. |
| - if (_hasStrictArrow(call)) { |
| + if (_hasStrictArrow(call.function)) { |
| return false; |
| } |
| return rules.anyParameterType(ft, (pt) => pt.isDynamic); |