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'; |
11 import 'package:analyzer/dart/ast/token.dart' show TokenType; | 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
12 import 'package:analyzer/dart/ast/token.dart'; | 12 import 'package:analyzer/dart/ast/token.dart'; |
13 import 'package:analyzer/dart/ast/visitor.dart'; | 13 import 'package:analyzer/dart/ast/visitor.dart'; |
14 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
15 import 'package:analyzer/dart/element/type.dart'; | 15 import 'package:analyzer/dart/element/type.dart'; |
16 import 'package:analyzer/src/dart/element/type.dart'; | 16 import 'package:analyzer/src/dart/element/type.dart'; |
17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; | 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; |
18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; | 18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; |
19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
20 import 'package:analyzer/src/generated/type_system.dart'; | 20 import 'package:analyzer/src/generated/type_system.dart'; |
21 | 21 |
22 import 'ast_properties.dart'; | 22 import 'ast_properties.dart'; |
23 | 23 |
24 bool isKnownFunction(Expression expression) { | 24 bool isKnownFunction(Expression expression, {bool instanceMethods: false}) { |
25 Element element = null; | 25 Element element = null; |
| 26 if (expression is ParenthesizedExpression) { |
| 27 expression = (expression as ParenthesizedExpression).expression; |
| 28 } |
26 if (expression is FunctionExpression) { | 29 if (expression is FunctionExpression) { |
27 return true; | 30 return true; |
28 } else if (expression is PropertyAccess) { | 31 } else if (expression is PropertyAccess) { |
29 element = expression.propertyName.staticElement; | 32 element = expression.propertyName.staticElement; |
30 } else if (expression is Identifier) { | 33 } else if (expression is Identifier) { |
31 element = expression.staticElement; | 34 element = expression.staticElement; |
32 } | 35 } |
33 // First class functions and static methods, where we know the original | 36 // First class functions and static methods, where we know the original |
34 // declaration, will have an exact type, so we know a downcast will fail. | 37 // declaration, will have an exact type, so we know a downcast will fail. |
35 return element is FunctionElement || | 38 return element is FunctionElement || |
36 element is MethodElement && element.isStatic; | 39 element is MethodElement && (instanceMethods || element.isStatic); |
37 } | 40 } |
38 | 41 |
39 DartType _elementType(Element e) { | 42 DartType _elementType(Element e) { |
40 if (e == null) { | 43 if (e == null) { |
41 // Malformed code - just return dynamic. | 44 // Malformed code - just return dynamic. |
42 return DynamicTypeImpl.instance; | 45 return DynamicTypeImpl.instance; |
43 } | 46 } |
44 return (e as dynamic).type; | 47 return (e as dynamic).type; |
45 } | 48 } |
46 | 49 |
(...skipping 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
929 if (type.isDynamic) { | 932 if (type.isDynamic) { |
930 return type; | 933 return type; |
931 } else if (type is InterfaceType && type.element == expectedType.element) { | 934 } else if (type is InterfaceType && type.element == expectedType.element) { |
932 return type.typeArguments[0]; | 935 return type.typeArguments[0]; |
933 } else { | 936 } else { |
934 // Malformed type - fallback on analyzer error. | 937 // Malformed type - fallback on analyzer error. |
935 return null; | 938 return null; |
936 } | 939 } |
937 } | 940 } |
938 | 941 |
939 // Produce a coercion which coerces something of type fromT | |
940 // to something of type toT. | |
941 // Returns the error coercion if the types cannot be coerced | |
942 // according to our current criteria. | |
943 DartType _getStaticType(Expression expr) { | 942 DartType _getStaticType(Expression expr) { |
944 DartType t = expr.staticType ?? DynamicTypeImpl.instance; | 943 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
945 | 944 |
946 // Remove fuzzy arrow if possible. | 945 // Remove fuzzy arrow if possible. |
947 if (t is FunctionType && isKnownFunction(expr)) { | 946 if (t is FunctionType && isKnownFunction(expr)) { |
948 t = rules.functionTypeToConcreteType(typeProvider, t); | 947 t = rules.functionTypeToConcreteType(typeProvider, t); |
949 } | 948 } |
950 | 949 |
951 return t; | 950 return t; |
952 } | 951 } |
(...skipping 25 matching lines...) Expand all Loading... |
978 var ft = _getTypeAsCaller(call); | 977 var ft = _getTypeAsCaller(call); |
979 // TODO(leafp): This will currently return true if t is Function | 978 // TODO(leafp): This will currently return true if t is Function |
980 // This is probably the most correct thing to do for now, since | 979 // This is probably the most correct thing to do for now, since |
981 // this code is also used by the back end. Maybe revisit at some | 980 // this code is also used by the back end. Maybe revisit at some |
982 // point? | 981 // point? |
983 if (ft == null) return true; | 982 if (ft == null) return true; |
984 // Dynamic as the parameter type is treated as bottom. A function with | 983 // Dynamic as the parameter type is treated as bottom. A function with |
985 // a dynamic parameter type requires a dynamic call in general. | 984 // a dynamic parameter type requires a dynamic call in general. |
986 // However, as an optimization, if we have an original definition, we know | 985 // However, as an optimization, if we have an original definition, we know |
987 // dynamic is reified as Object - in this case a regular call is fine. | 986 // dynamic is reified as Object - in this case a regular call is fine. |
988 if (call is SimpleIdentifier) { | 987 if (isKnownFunction(call, instanceMethods: true)) { |
989 var element = call.staticElement; | 988 return false; |
990 if (element is FunctionElement || element is MethodElement) { | |
991 // An original declaration. | |
992 return false; | |
993 } | |
994 } | 989 } |
995 | |
996 return rules.anyParameterType(ft, (pt) => pt.isDynamic); | 990 return rules.anyParameterType(ft, (pt) => pt.isDynamic); |
997 } | 991 } |
998 | 992 |
999 /// Returns `true` if the target expression is dynamic. | 993 /// Returns `true` if the target expression is dynamic. |
1000 bool _isDynamicTarget(Expression node) { | 994 bool _isDynamicTarget(Expression node) { |
1001 if (node == null) return false; | 995 if (node == null) return false; |
1002 | 996 |
1003 if (_isLibraryPrefix(node)) return false; | 997 if (_isLibraryPrefix(node)) return false; |
1004 | 998 |
1005 // Null type happens when we have unknown identifiers, like a dart: import | 999 // Null type happens when we have unknown identifiers, like a dart: import |
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1489 var visited = new Set<InterfaceType>(); | 1483 var visited = new Set<InterfaceType>(); |
1490 do { | 1484 do { |
1491 visited.add(current); | 1485 visited.add(current); |
1492 current.mixins.reversed.forEach( | 1486 current.mixins.reversed.forEach( |
1493 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1487 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
1494 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1488 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
1495 current = current.superclass; | 1489 current = current.superclass; |
1496 } while (!current.isObject && !visited.contains(current)); | 1490 } while (!current.isObject && !visited.contains(current)); |
1497 } | 1491 } |
1498 } | 1492 } |
OLD | NEW |