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 Token, TokenType; | 11 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
12 import 'package:analyzer/dart/ast/visitor.dart'; | 12 import 'package:analyzer/dart/ast/visitor.dart'; |
13 import 'package:analyzer/dart/element/element.dart'; | 13 import 'package:analyzer/dart/element/element.dart'; |
14 import 'package:analyzer/dart/element/type.dart'; | 14 import 'package:analyzer/dart/element/type.dart'; |
| 15 import 'package:analyzer/src/dart/element/element.dart'; |
15 import 'package:analyzer/src/dart/element/type.dart'; | 16 import 'package:analyzer/src/dart/element/type.dart'; |
16 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
17 import 'package:analyzer/src/generated/type_system.dart'; | 18 import 'package:analyzer/src/generated/type_system.dart'; |
18 | 19 |
19 import 'info.dart'; | 20 import 'info.dart'; |
20 | 21 |
21 DartType _elementType(Element e) { | 22 DartType _elementType(Element e) { |
22 if (e == null) { | 23 if (e == null) { |
23 // Malformed code - just return dynamic. | 24 // Malformed code - just return dynamic. |
24 return DynamicTypeImpl.instance; | 25 return DynamicTypeImpl.instance; |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 node.visitChildren(this); | 559 node.visitChildren(this); |
559 } | 560 } |
560 | 561 |
561 @override | 562 @override |
562 void visitYieldStatement(YieldStatement node) { | 563 void visitYieldStatement(YieldStatement node) { |
563 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); | 564 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); |
564 node.visitChildren(this); | 565 node.visitChildren(this); |
565 } | 566 } |
566 | 567 |
567 StaticInfo _checkAssignment(Expression expr, DartType toT) { | 568 StaticInfo _checkAssignment(Expression expr, DartType toT) { |
568 final fromT = expr.staticType ?? DynamicTypeImpl.instance; | 569 final fromT = _getStaticType(expr); |
569 final Coercion c = _coerceTo(fromT, toT); | 570 final Coercion c = _coerceTo(fromT, toT); |
570 if (c is Identity) return null; | 571 if (c is Identity) return null; |
571 if (c is CoercionError) return new StaticTypeError(rules, expr, toT); | 572 if (c is CoercionError) return new StaticTypeError(rules, expr, toT); |
572 if (c is Cast) return DownCast.create(rules, expr, c); | 573 if (c is Cast) return DownCast.create(rules, expr, c); |
573 assert(false); | 574 assert(false); |
574 return null; | 575 return null; |
575 } | 576 } |
576 | 577 |
577 void _checkCompoundAssignment(AssignmentExpression expr) { | 578 void _checkCompoundAssignment(AssignmentExpression expr) { |
578 var op = expr.operator.type; | 579 var op = expr.operator.type; |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 return type; | 764 return type; |
764 } else if (type is InterfaceType && type.element == expectedType.element) { | 765 } else if (type is InterfaceType && type.element == expectedType.element) { |
765 return type.typeArguments[0]; | 766 return type.typeArguments[0]; |
766 } else { | 767 } else { |
767 // Malformed type - fallback on analyzer error. | 768 // Malformed type - fallback on analyzer error. |
768 return null; | 769 return null; |
769 } | 770 } |
770 } | 771 } |
771 | 772 |
772 DartType _getStaticType(Expression expr) { | 773 DartType _getStaticType(Expression expr) { |
773 return expr.staticType ?? DynamicTypeImpl.instance; | 774 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| 775 |
| 776 // Remove fuzzy arrow if possible. |
| 777 if (t is FunctionType && StaticInfo.isKnownFunction(expr)) { |
| 778 t = _removeFuzz(t); |
| 779 } |
| 780 |
| 781 return t; |
| 782 } |
| 783 |
| 784 /// Remove "fuzzy arrow" in this function type. |
| 785 /// |
| 786 /// Normally we treat dynamically typed parameters as bottom for function |
| 787 /// types. This allows type tests such as `if (f is SingleArgFunction)`. |
| 788 /// It also requires a dynamic check on the parameter type to call these |
| 789 /// functions. |
| 790 /// |
| 791 /// When we convert to a strict arrow, dynamically typed parameters become |
| 792 /// top. This is safe to do for known functions, like top-level or local |
| 793 /// functions and static methods. Those functions must already be essentially |
| 794 /// treating dynamic as top. |
| 795 /// |
| 796 /// Only the outer-most arrow can be strict. Any others must be fuzzy, because |
| 797 /// we don't know what function value will be passed there. |
| 798 // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function |
| 799 // type? That would allow us to implement this in the subtype relation. |
| 800 // TODO(jmesserly): we'll need to factor this differently if we want to |
| 801 // move CodeChecker's functionality into existing analyzer. Likely we can |
| 802 // let the Expression have a strict arrow, then in places were we do |
| 803 // inference, convert back to a fuzzy arrow. |
| 804 FunctionType _removeFuzz(FunctionType t) { |
| 805 bool foundFuzz = false; |
| 806 List<ParameterElement> parameters = <ParameterElement>[]; |
| 807 for (ParameterElement p in t.parameters) { |
| 808 ParameterElement newP = _removeParameterFuzz(p); |
| 809 parameters.add(newP); |
| 810 if (p != newP) foundFuzz = true; |
| 811 } |
| 812 if (!foundFuzz) { |
| 813 return t; |
| 814 } |
| 815 |
| 816 FunctionElementImpl function = new FunctionElementImpl("", -1); |
| 817 function.synthetic = true; |
| 818 function.returnType = t.returnType; |
| 819 function.shareTypeParameters(t.typeFormals); |
| 820 function.shareParameters(parameters); |
| 821 return function.type = new FunctionTypeImpl(function); |
| 822 } |
| 823 |
| 824 /// Removes fuzzy arrow, see [_removeFuzz]. |
| 825 ParameterElement _removeParameterFuzz(ParameterElement p) { |
| 826 if (p.type.isDynamic) { |
| 827 return new ParameterElementImpl.synthetic( |
| 828 p.name, typeProvider.objectType, p.parameterKind); |
| 829 } |
| 830 return p; |
774 } | 831 } |
775 | 832 |
776 /// Given an expression, return its type assuming it is | 833 /// Given an expression, return its type assuming it is |
777 /// in the caller position of a call (that is, accounting | 834 /// in the caller position of a call (that is, accounting |
778 /// for the possibility of a call method). Returns null | 835 /// for the possibility of a call method). Returns null |
779 /// if expression is not statically callable. | 836 /// if expression is not statically callable. |
780 FunctionType _getTypeAsCaller(Expression node) { | 837 FunctionType _getTypeAsCaller(Expression node) { |
781 DartType t = node.staticType; | 838 DartType t = node.staticType; |
782 if (node is SimpleIdentifier) { | 839 if (node is SimpleIdentifier) { |
783 Expression parent = node.parent; | 840 Expression parent = node.parent; |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1219 } while (!current.isObject && !visited.contains(current)); | 1276 } while (!current.isObject && !visited.contains(current)); |
1220 } | 1277 } |
1221 | 1278 |
1222 void _recordMessage(StaticInfo info) { | 1279 void _recordMessage(StaticInfo info) { |
1223 if (info == null) return; | 1280 if (info == null) return; |
1224 var error = info.toAnalysisError(); | 1281 var error = info.toAnalysisError(); |
1225 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; | 1282 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; |
1226 _reporter.onError(error); | 1283 _reporter.onError(error); |
1227 } | 1284 } |
1228 } | 1285 } |
OLD | NEW |