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

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

Issue 2221233002: fix #27036, pass definite function types to LUB (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: small refactor for checker & InvocationExpressions 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';
(...skipping 11 matching lines...) Expand all
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/static_type_analyzer.dart ('k') | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698