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/visitor.dart'; | 11 import 'package:analyzer/dart/ast/visitor.dart'; |
12 import 'package:analyzer/dart/element/element.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
13 import 'package:analyzer/dart/element/type.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
| 14 import 'package:analyzer/src/dart/element/element.dart'; |
14 import 'package:analyzer/src/dart/element/type.dart'; | 15 import 'package:analyzer/src/dart/element/type.dart'; |
15 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 16 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
16 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; | 17 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; |
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. |
(...skipping 534 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 var reason = null; | 573 var reason = null; |
573 | 574 |
574 var errors = <String>[]; | 575 var errors = <String>[]; |
575 | 576 |
576 var ok = _inferExpression(expr, toT, errors); | 577 var ok = _inferExpression(expr, toT, errors); |
577 if (ok) return InferredType.create(rules, expr, toT); | 578 if (ok) return InferredType.create(rules, expr, toT); |
578 reason = (errors.isNotEmpty) ? errors.first : null; | 579 reason = (errors.isNotEmpty) ? errors.first : null; |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 return type; | 772 return type; |
772 } else if (type is InterfaceType && type.element == expectedType.element) { | 773 } else if (type is InterfaceType && type.element == expectedType.element) { |
773 return type.typeArguments[0]; | 774 return type.typeArguments[0]; |
774 } else { | 775 } else { |
775 // Malformed type - fallback on analyzer error. | 776 // Malformed type - fallback on analyzer error. |
776 return null; | 777 return null; |
777 } | 778 } |
778 } | 779 } |
779 | 780 |
780 DartType _getStaticType(Expression expr) { | 781 DartType _getStaticType(Expression expr) { |
781 return expr.staticType ?? DynamicTypeImpl.instance; | 782 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| 783 |
| 784 // Remove fuzzy arrow if possible. |
| 785 if (t is FunctionType && StaticInfo.isKnownFunction(expr)) { |
| 786 t = _removeFuzz(t); |
| 787 } |
| 788 |
| 789 return t; |
| 790 } |
| 791 |
| 792 /// Remove "fuzzy arrow" in this function type. |
| 793 /// |
| 794 /// Normally we treat dynamically typed parameters as bottom for function |
| 795 /// types. This allows type tests such as `if (f is SingleArgFunction)`. |
| 796 /// It also requires a dynamic check on the parameter type to call these |
| 797 /// functions. |
| 798 /// |
| 799 /// When we convert to a strict arrow, dynamically typed parameters become |
| 800 /// top. This is safe to do for known functions, like top-level or local |
| 801 /// functions and static methods. Those functions must already be essentially |
| 802 /// treating dynamic as top. |
| 803 /// |
| 804 /// Only the outer-most arrow can be strict. Any others must be fuzzy, because |
| 805 /// we don't know what function value will be passed there. |
| 806 FunctionType _removeFuzz(FunctionType t) { |
| 807 bool foundFuzz = false; |
| 808 List<ParameterElement> parameters = <ParameterElement>[]; |
| 809 for (ParameterElement p in t.parameters) { |
| 810 ParameterElement newP = _removeParameterFuzz(p); |
| 811 parameters.add(newP); |
| 812 if (p != newP) foundFuzz = true; |
| 813 } |
| 814 if (!foundFuzz) { |
| 815 return t; |
| 816 } |
| 817 |
| 818 FunctionElementImpl function = new FunctionElementImpl("", -1); |
| 819 function.synthetic = true; |
| 820 function.returnType = t.returnType; |
| 821 function.shareTypeParameters(t.typeFormals); |
| 822 function.shareParameters(parameters); |
| 823 return function.type = new FunctionTypeImpl(function); |
| 824 } |
| 825 |
| 826 /// Removes fuzzy arrow, see [_removeFuzz]. |
| 827 ParameterElement _removeParameterFuzz(ParameterElement p) { |
| 828 if (p.type.isDynamic) { |
| 829 return new ParameterElementImpl.synthetic( |
| 830 p.name, typeProvider.objectType, p.parameterKind); |
| 831 } |
| 832 return p; |
782 } | 833 } |
783 | 834 |
784 /// Given an expression, return its type assuming it is | 835 /// Given an expression, return its type assuming it is |
785 /// in the caller position of a call (that is, accounting | 836 /// in the caller position of a call (that is, accounting |
786 /// for the possibility of a call method). Returns null | 837 /// for the possibility of a call method). Returns null |
787 /// if expression is not statically callable. | 838 /// if expression is not statically callable. |
788 FunctionType _getTypeAsCaller(Expression node) { | 839 FunctionType _getTypeAsCaller(Expression node) { |
789 DartType t = node.staticType; | 840 DartType t = node.staticType; |
790 if (node is SimpleIdentifier) { | 841 if (node is SimpleIdentifier) { |
791 Expression parent = node.parent; | 842 Expression parent = node.parent; |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1238 } while (!current.isObject && !visited.contains(current)); | 1289 } while (!current.isObject && !visited.contains(current)); |
1239 } | 1290 } |
1240 | 1291 |
1241 void _recordMessage(StaticInfo info) { | 1292 void _recordMessage(StaticInfo info) { |
1242 if (info == null) return; | 1293 if (info == null) return; |
1243 var error = info.toAnalysisError(); | 1294 var error = info.toAnalysisError(); |
1244 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; | 1295 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; |
1245 _reporter.onError(error); | 1296 _reporter.onError(error); |
1246 } | 1297 } |
1247 } | 1298 } |
OLD | NEW |