Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 2212233003: fix #26393, treat tear offs as definite functions (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: add regression test Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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, {bool instanceMethods: false}) { 24 bool isKnownFunction(Expression expression) {
25 Element element = null; 25 var element = _getKnownElement(expression);
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.
28 return element is FunctionElement ||
29 element is MethodElement && element.isStatic;
30 }
31
32 bool _hasStrictArrow(Expression expression) {
33 var element = _getKnownElement(expression);
34 return element is FunctionElement || element is MethodElement;
35 }
36
37 Element _getKnownElement(Expression expression) {
26 if (expression is ParenthesizedExpression) { 38 if (expression is ParenthesizedExpression) {
27 expression = (expression as ParenthesizedExpression).expression; 39 expression = (expression as ParenthesizedExpression).expression;
28 } 40 }
29 if (expression is FunctionExpression) { 41 if (expression is FunctionExpression) {
30 return true; 42 return expression.element;
31 } else if (expression is PropertyAccess) { 43 } else if (expression is PropertyAccess) {
32 element = expression.propertyName.staticElement; 44 return expression.propertyName.staticElement;
33 } else if (expression is Identifier) { 45 } else if (expression is Identifier) {
34 element = expression.staticElement; 46 return expression.staticElement;
35 } 47 }
36 // First class functions and static methods, where we know the original 48 return null;
37 // declaration, will have an exact type, so we know a downcast will fail.
38 return element is FunctionElement ||
39 element is MethodElement && (instanceMethods || element.isStatic);
40 } 49 }
41 50
42 DartType _elementType(Element e) { 51 DartType _elementType(Element e) {
43 if (e == null) { 52 if (e == null) {
44 // Malformed code - just return dynamic. 53 // Malformed code - just return dynamic.
45 return DynamicTypeImpl.instance; 54 return DynamicTypeImpl.instance;
46 } 55 }
47 return (e as dynamic).type; 56 return (e as dynamic).type;
48 } 57 }
49 58
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 baseMethod = type.getSetter(memberName); 113 baseMethod = type.getSetter(memberName);
105 } else { 114 } else {
106 baseMethod = type.getMethod(memberName); 115 baseMethod = type.getMethod(memberName);
107 } 116 }
108 } catch (e) { 117 } catch (e) {
109 // TODO(sigmund): remove this try-catch block (see issue #48). 118 // TODO(sigmund): remove this try-catch block (see issue #48).
110 } 119 }
111 if (baseMethod == null || baseMethod.isStatic) return null; 120 if (baseMethod == null || baseMethod.isStatic) return null;
112 return baseMethod.type; 121 return baseMethod.type;
113 } 122 }
123
114 return f; 124 return f;
115 } 125 }
116 126
117 typedef FunctionType _MemberTypeGetter(InterfaceType type); 127 typedef FunctionType _MemberTypeGetter(InterfaceType type);
118 128
119 /// Checks the body of functions and properties. 129 /// Checks the body of functions and properties.
120 class CodeChecker extends RecursiveAstVisitor { 130 class CodeChecker extends RecursiveAstVisitor {
121 final StrongTypeSystemImpl rules; 131 final StrongTypeSystemImpl rules;
122 final TypeProvider typeProvider; 132 final TypeProvider typeProvider;
123 final AnalysisErrorListener reporter; 133 final AnalysisErrorListener reporter;
(...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 } else { 966 } else {
957 // Malformed type - fallback on analyzer error. 967 // Malformed type - fallback on analyzer error.
958 return null; 968 return null;
959 } 969 }
960 } 970 }
961 971
962 DartType _getStaticType(Expression expr) { 972 DartType _getStaticType(Expression expr) {
963 DartType t = expr.staticType ?? DynamicTypeImpl.instance; 973 DartType t = expr.staticType ?? DynamicTypeImpl.instance;
964 974
965 // Remove fuzzy arrow if possible. 975 // Remove fuzzy arrow if possible.
966 if (t is FunctionType && isKnownFunction(expr)) { 976 if (t is FunctionType && _hasStrictArrow(expr)) {
967 t = rules.functionTypeToConcreteType(typeProvider, t); 977 t = rules.functionTypeToConcreteType(typeProvider, t);
968 } 978 }
969 979
970 return t; 980 return t;
971 } 981 }
972 982
973 /// Given an expression, return its type assuming it is 983 /// Given an expression, return its type assuming it is
974 /// in the caller position of a call (that is, accounting 984 /// in the caller position of a call (that is, accounting
975 /// for the possibility of a call method). Returns null 985 /// for the possibility of a call method). Returns null
976 /// if expression is not statically callable. 986 /// if expression is not statically callable.
977 FunctionType _getTypeAsCaller(Expression node) { 987 FunctionType _getTypeAsCaller(Expression node) {
978 DartType t = node.staticType; 988 DartType t = _getStaticType(node);
979 if (node is SimpleIdentifier) { 989 if (node is SimpleIdentifier) {
980 Expression parent = node.parent; 990 Expression parent = node.parent;
981 if (parent is MethodInvocation) { 991 if (parent is MethodInvocation) {
982 t = parent.staticInvokeType; 992 t = parent.staticInvokeType;
983 } 993 }
984 } 994 }
985 if (t is InterfaceType) { 995 if (t is InterfaceType) {
986 return rules.getCallMethodType(t); 996 return rules.getCallMethodType(t);
987 } 997 }
988 if (t is FunctionType) { 998 if (t is FunctionType) {
989 return t; 999 return t;
990 } 1000 }
991 return null; 1001 return null;
992 } 1002 }
993 1003
994 /// Returns `true` if the expression is a dynamic function call or method 1004 /// Returns `true` if the expression is a dynamic function call or method
995 /// invocation. 1005 /// invocation.
996 bool _isDynamicCall(Expression call) { 1006 bool _isDynamicCall(Expression call) {
997 var ft = _getTypeAsCaller(call); 1007 var ft = _getTypeAsCaller(call);
998 // TODO(leafp): This will currently return true if t is Function 1008 // TODO(leafp): This will currently return true if t is Function
999 // This is probably the most correct thing to do for now, since 1009 // This is probably the most correct thing to do for now, since
1000 // this code is also used by the back end. Maybe revisit at some 1010 // this code is also used by the back end. Maybe revisit at some
1001 // point? 1011 // point?
1002 if (ft == null) return true; 1012 if (ft == null) return true;
1003 // Dynamic as the parameter type is treated as bottom. A function with 1013 // Dynamic as the parameter type is treated as bottom. A function with
1004 // a dynamic parameter type requires a dynamic call in general. 1014 // a dynamic parameter type requires a dynamic call in general.
1005 // However, as an optimization, if we have an original definition, we know 1015 // However, as an optimization, if we have an original definition, we know
1006 // dynamic is reified as Object - in this case a regular call is fine. 1016 // dynamic is reified as Object - in this case a regular call is fine.
1007 if (isKnownFunction(call, instanceMethods: true)) { 1017 if (_hasStrictArrow(call)) {
1008 return false; 1018 return false;
1009 } 1019 }
1010 return rules.anyParameterType(ft, (pt) => pt.isDynamic); 1020 return rules.anyParameterType(ft, (pt) => pt.isDynamic);
1011 } 1021 }
1012 1022
1013 /// Returns `true` if the target expression is dynamic. 1023 /// Returns `true` if the target expression is dynamic.
1014 bool _isDynamicTarget(Expression node) { 1024 bool _isDynamicTarget(Expression node) {
1015 if (node == null) return false; 1025 if (node == null) return false;
1016 1026
1017 if (_isLibraryPrefix(node)) return false; 1027 if (_isLibraryPrefix(node)) return false;
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 AstNode errorLocation, 1291 AstNode errorLocation,
1282 Set<String> seen, 1292 Set<String> seen,
1283 bool isSubclass) { 1293 bool isSubclass) {
1284 void checkHelper(ExecutableElement e) { 1294 void checkHelper(ExecutableElement e) {
1285 if (e.isStatic) return; 1295 if (e.isStatic) return;
1286 if (seen.contains(e.name)) return; 1296 if (seen.contains(e.name)) return;
1287 if (_checkSingleOverride(e, baseType, null, errorLocation, isSubclass)) { 1297 if (_checkSingleOverride(e, baseType, null, errorLocation, isSubclass)) {
1288 seen.add(e.name); 1298 seen.add(e.name);
1289 } 1299 }
1290 } 1300 }
1301
1291 subType.methods.forEach(checkHelper); 1302 subType.methods.forEach(checkHelper);
1292 subType.accessors.forEach(checkHelper); 1303 subType.accessors.forEach(checkHelper);
1293 } 1304 }
1294 1305
1295 /// Checks that [cls] and its super classes (including mixins) correctly 1306 /// Checks that [cls] and its super classes (including mixins) correctly
1296 /// overrides each interface in [interfaces]. If [includeParents] is false, 1307 /// overrides each interface in [interfaces]. If [includeParents] is false,
1297 /// then mixins are still checked, but the base type and it's transitive 1308 /// then mixins are still checked, but the base type and it's transitive
1298 /// supertypes are not. 1309 /// supertypes are not.
1299 /// 1310 ///
1300 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For 1311 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
1503 var visited = new Set<InterfaceType>(); 1514 var visited = new Set<InterfaceType>();
1504 do { 1515 do {
1505 visited.add(current); 1516 visited.add(current);
1506 current.mixins.reversed.forEach( 1517 current.mixins.reversed.forEach(
1507 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1518 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1508 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1519 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1509 current = current.superclass; 1520 current = current.superclass;
1510 } while (!current.isObject && !visited.contains(current)); 1521 } while (!current.isObject && !visited.contains(current));
1511 } 1522 }
1512 } 1523 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698