Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
| 6 // refactored to fit into analyzer. | 6 // refactored to fit into analyzer. |
| 7 library analyzer.src.task.strong.checker; | 7 library analyzer.src.task.strong.checker; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 import 'ast_properties.dart'; | 22 import 'ast_properties.dart'; |
| 23 | 23 |
| 24 bool isKnownFunction(Expression expression) { | 24 bool isKnownFunction(Expression expression) { |
| 25 var element = _getKnownElement(expression); | 25 var element = _getKnownElement(expression); |
| 26 // First class functions and static methods, where we know the original | 26 // First class functions and static methods, where we know the original |
| 27 // declaration, will have an exact type, so we know a downcast will fail. | 27 // declaration, will have an exact type, so we know a downcast will fail. |
| 28 return element is FunctionElement || | 28 return element is FunctionElement || |
| 29 element is MethodElement && element.isStatic; | 29 element is MethodElement && element.isStatic; |
| 30 } | 30 } |
| 31 | 31 |
| 32 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider], | |
| 33 /// gets the known static type of the expression. | |
| 34 /// | |
| 35 /// Normally when we ask for an expression's type, we get the type of the | |
| 36 /// storage slot that would contain it. For function types, this is necessarily | |
| 37 /// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're | |
| 38 /// interested in the expression's own type, it can often be a "strict arrow" | |
| 39 /// because we know it evaluates to a specific, concrete function, and we can | |
| 40 /// treat "dynamic" as top for that case, which is more permissive. | |
| 41 DartType getDefiniteType( | |
| 42 Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) { | |
| 43 DartType type = expression.staticType ?? DynamicTypeImpl.instance; | |
| 44 if (typeSystem is StrongTypeSystemImpl && | |
| 45 type is FunctionType && | |
| 46 _hasStrictArrow(expression)) { | |
| 47 // Remove fuzzy arrow if possible. | |
| 48 return typeSystem.functionTypeToConcreteType(typeProvider, type); | |
| 49 } | |
| 50 return type; | |
| 51 } | |
| 52 | |
| 32 bool _hasStrictArrow(Expression expression) { | 53 bool _hasStrictArrow(Expression expression) { |
| 33 var element = _getKnownElement(expression); | 54 var element = _getKnownElement(expression); |
| 34 return element is FunctionElement || element is MethodElement; | 55 return element is FunctionElement || element is MethodElement; |
| 35 } | 56 } |
| 36 | 57 |
| 37 Element _getKnownElement(Expression expression) { | 58 Element _getKnownElement(Expression expression) { |
| 38 if (expression is ParenthesizedExpression) { | 59 if (expression is ParenthesizedExpression) { |
| 39 expression = (expression as ParenthesizedExpression).expression; | 60 expression = (expression as ParenthesizedExpression).expression; |
| 40 } | 61 } |
| 41 if (expression is FunctionExpression) { | 62 if (expression is FunctionExpression) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 } | 201 } |
| 181 } | 202 } |
| 182 } | 203 } |
| 183 | 204 |
| 184 /// Analyzer checks boolean conversions, but we need to check too, because | 205 /// Analyzer checks boolean conversions, but we need to check too, because |
| 185 /// it uses the default assignability rules that allow `dynamic` and `Object` | 206 /// it uses the default assignability rules that allow `dynamic` and `Object` |
| 186 /// to be assigned to bool with no message. | 207 /// to be assigned to bool with no message. |
| 187 void checkBoolean(Expression expr) => | 208 void checkBoolean(Expression expr) => |
| 188 checkAssignment(expr, typeProvider.boolType); | 209 checkAssignment(expr, typeProvider.boolType); |
| 189 | 210 |
| 190 void checkFunctionApplication( | 211 void checkFunctionApplication(InvocationExpression node) { |
|
Jennifer Messerly
2016/08/09 12:35:19
fyi -- I did a small refactor in patch set 2, taki
| |
| 191 Expression node, Expression f, ArgumentList list) { | 212 var ft = _getTypeAsCaller(node); |
| 192 if (_isDynamicCall(f)) { | 213 |
| 214 if (_isDynamicCall(node, ft)) { | |
| 193 // If f is Function and this is a method invocation, we should have | 215 // If f is Function and this is a method invocation, we should have |
| 194 // gotten an analyzer error, so no need to issue another error. | 216 // gotten an analyzer error, so no need to issue another error. |
| 195 _recordDynamicInvoke(node, f); | 217 _recordDynamicInvoke(node, node.function); |
| 196 } else { | 218 } else { |
| 197 checkArgumentList(list, _getTypeAsCaller(f)); | 219 checkArgumentList(node.argumentList, ft); |
| 198 } | 220 } |
| 199 } | 221 } |
| 200 | 222 |
| 201 DartType getType(TypeName name) { | 223 DartType getType(TypeName name) { |
| 202 return (name == null) ? DynamicTypeImpl.instance : name.type; | 224 return (name == null) ? DynamicTypeImpl.instance : name.type; |
| 203 } | 225 } |
| 204 | 226 |
| 205 void reset() { | 227 void reset() { |
| 206 _failure = false; | 228 _failure = false; |
| 207 } | 229 } |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 } | 438 } |
| 417 | 439 |
| 418 @override | 440 @override |
| 419 void visitFunctionExpression(FunctionExpression node) { | 441 void visitFunctionExpression(FunctionExpression node) { |
| 420 _checkForUnsafeBlockClosureInference(node); | 442 _checkForUnsafeBlockClosureInference(node); |
| 421 super.visitFunctionExpression(node); | 443 super.visitFunctionExpression(node); |
| 422 } | 444 } |
| 423 | 445 |
| 424 @override | 446 @override |
| 425 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 447 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 426 checkFunctionApplication(node, node.function, node.argumentList); | 448 checkFunctionApplication(node); |
| 427 node.visitChildren(this); | 449 node.visitChildren(this); |
| 428 } | 450 } |
| 429 | 451 |
| 430 @override | 452 @override |
| 431 void visitIfStatement(IfStatement node) { | 453 void visitIfStatement(IfStatement node) { |
| 432 checkBoolean(node.condition); | 454 checkBoolean(node.condition); |
| 433 node.visitChildren(this); | 455 node.visitChildren(this); |
| 434 } | 456 } |
| 435 | 457 |
| 436 @override | 458 @override |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 // | 566 // |
| 545 // ... from case like: | 567 // ... from case like: |
| 546 // | 568 // |
| 547 // SomeType s; | 569 // SomeType s; |
| 548 // s.someDynamicField(...); // static get, followed by dynamic call. | 570 // s.someDynamicField(...); // static get, followed by dynamic call. |
| 549 // | 571 // |
| 550 // The first case is handled here, the second case is handled below when | 572 // The first case is handled here, the second case is handled below when |
| 551 // we call [checkFunctionApplication]. | 573 // we call [checkFunctionApplication]. |
| 552 setIsDynamicInvoke(node.methodName, true); | 574 setIsDynamicInvoke(node.methodName, true); |
| 553 } else { | 575 } else { |
| 554 checkFunctionApplication(node, node.methodName, node.argumentList); | 576 checkFunctionApplication(node); |
| 555 } | 577 } |
| 556 node.visitChildren(this); | 578 node.visitChildren(this); |
| 557 } | 579 } |
| 558 | 580 |
| 559 @override | 581 @override |
| 560 void visitPostfixExpression(PostfixExpression node) { | 582 void visitPostfixExpression(PostfixExpression node) { |
| 561 _checkUnary(node); | 583 _checkUnary(node); |
| 562 node.visitChildren(this); | 584 node.visitChildren(this); |
| 563 } | 585 } |
| 564 | 586 |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 if (type.isDynamic) { | 984 if (type.isDynamic) { |
| 963 return type; | 985 return type; |
| 964 } else if (type is InterfaceType && type.element == expectedType.element) { | 986 } else if (type is InterfaceType && type.element == expectedType.element) { |
| 965 return type.typeArguments[0]; | 987 return type.typeArguments[0]; |
| 966 } else { | 988 } else { |
| 967 // Malformed type - fallback on analyzer error. | 989 // Malformed type - fallback on analyzer error. |
| 968 return null; | 990 return null; |
| 969 } | 991 } |
| 970 } | 992 } |
| 971 | 993 |
| 972 DartType _getStaticType(Expression expr) { | 994 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!
| |
| 973 DartType t = expr.staticType ?? DynamicTypeImpl.instance; | 995 getDefiniteType(expr, rules, typeProvider); |
| 974 | |
| 975 // Remove fuzzy arrow if possible. | |
| 976 if (t is FunctionType && _hasStrictArrow(expr)) { | |
| 977 t = rules.functionTypeToConcreteType(typeProvider, t); | |
| 978 } | |
| 979 | |
| 980 return t; | |
| 981 } | |
| 982 | 996 |
| 983 /// Given an expression, return its type assuming it is | 997 /// Given an expression, return its type assuming it is |
| 984 /// in the caller position of a call (that is, accounting | 998 /// in the caller position of a call (that is, accounting |
| 985 /// for the possibility of a call method). Returns null | 999 /// for the possibility of a call method). Returns null |
| 986 /// if expression is not statically callable. | 1000 /// if expression is not statically callable. |
| 987 FunctionType _getTypeAsCaller(Expression node) { | 1001 FunctionType _getTypeAsCaller(InvocationExpression node) { |
| 988 DartType t = _getStaticType(node); | 1002 DartType type = node.staticInvokeType; |
| 989 if (node is SimpleIdentifier) { | 1003 if (type is FunctionType) { |
| 990 Expression parent = node.parent; | 1004 return type; |
| 991 if (parent is MethodInvocation) { | 1005 } else if (type is InterfaceType) { |
| 992 t = parent.staticInvokeType; | 1006 return rules.getCallMethodType(type); |
| 993 } | |
| 994 } | |
| 995 if (t is InterfaceType) { | |
| 996 return rules.getCallMethodType(t); | |
| 997 } | |
| 998 if (t is FunctionType) { | |
| 999 return t; | |
| 1000 } | 1007 } |
| 1001 return null; | 1008 return null; |
| 1002 } | 1009 } |
| 1003 | 1010 |
| 1004 /// Returns `true` if the expression is a dynamic function call or method | 1011 /// Returns `true` if the expression is a dynamic function call or method |
| 1005 /// invocation. | 1012 /// invocation. |
| 1006 bool _isDynamicCall(Expression call) { | 1013 bool _isDynamicCall(InvocationExpression call, FunctionType ft) { |
| 1007 var ft = _getTypeAsCaller(call); | |
| 1008 // TODO(leafp): This will currently return true if t is Function | 1014 // TODO(leafp): This will currently return true if t is Function |
| 1009 // This is probably the most correct thing to do for now, since | 1015 // This is probably the most correct thing to do for now, since |
| 1010 // this code is also used by the back end. Maybe revisit at some | 1016 // this code is also used by the back end. Maybe revisit at some |
| 1011 // point? | 1017 // point? |
| 1012 if (ft == null) return true; | 1018 if (ft == null) return true; |
| 1013 // Dynamic as the parameter type is treated as bottom. A function with | 1019 // Dynamic as the parameter type is treated as bottom. A function with |
| 1014 // a dynamic parameter type requires a dynamic call in general. | 1020 // a dynamic parameter type requires a dynamic call in general. |
| 1015 // However, as an optimization, if we have an original definition, we know | 1021 // However, as an optimization, if we have an original definition, we know |
| 1016 // dynamic is reified as Object - in this case a regular call is fine. | 1022 // dynamic is reified as Object - in this case a regular call is fine. |
| 1017 if (_hasStrictArrow(call)) { | 1023 if (_hasStrictArrow(call.function)) { |
| 1018 return false; | 1024 return false; |
| 1019 } | 1025 } |
| 1020 return rules.anyParameterType(ft, (pt) => pt.isDynamic); | 1026 return rules.anyParameterType(ft, (pt) => pt.isDynamic); |
| 1021 } | 1027 } |
| 1022 | 1028 |
| 1023 /// Returns `true` if the target expression is dynamic. | 1029 /// Returns `true` if the target expression is dynamic. |
| 1024 bool _isDynamicTarget(Expression node) { | 1030 bool _isDynamicTarget(Expression node) { |
| 1025 if (node == null) return false; | 1031 if (node == null) return false; |
| 1026 | 1032 |
| 1027 if (_isLibraryPrefix(node)) return false; | 1033 if (_isLibraryPrefix(node)) return false; |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1514 var visited = new Set<InterfaceType>(); | 1520 var visited = new Set<InterfaceType>(); |
| 1515 do { | 1521 do { |
| 1516 visited.add(current); | 1522 visited.add(current); |
| 1517 current.mixins.reversed.forEach( | 1523 current.mixins.reversed.forEach( |
| 1518 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1524 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1519 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1525 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1520 current = current.superclass; | 1526 current = current.superclass; |
| 1521 } while (!current.isObject && !visited.contains(current)); | 1527 } while (!current.isObject && !visited.contains(current)); |
| 1522 } | 1528 } |
| 1523 } | 1529 } |
| OLD | NEW |