Chromium Code Reviews| 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'; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 NodeList<Expression> list = node.arguments; | 179 NodeList<Expression> list = node.arguments; |
| 180 int len = list.length; | 180 int len = list.length; |
| 181 for (int i = 0; i < len; ++i) { | 181 for (int i = 0; i < len; ++i) { |
| 182 Expression arg = list[i]; | 182 Expression arg = list[i]; |
| 183 ParameterElement element = arg.staticParameterElement; | 183 ParameterElement element = arg.staticParameterElement; |
| 184 if (element == null) { | 184 if (element == null) { |
| 185 // We found an argument mismatch, the analyzer will report this too, | 185 // We found an argument mismatch, the analyzer will report this too, |
| 186 // so no need to insert an error for this here. | 186 // so no need to insert an error for this here. |
| 187 continue; | 187 continue; |
| 188 } | 188 } |
| 189 DartType expectedType = _elementType(element); | 189 checkArgument(arg, _elementType(element)); |
| 190 if (expectedType == null) expectedType = DynamicTypeImpl.instance; | |
| 191 checkArgument(arg, expectedType); | |
| 192 } | 190 } |
| 193 } | 191 } |
| 194 | 192 |
| 195 void checkAssignment(Expression expr, DartType type) { | 193 void checkAssignment(Expression expr, DartType type) { |
| 196 if (expr is ParenthesizedExpression) { | 194 if (expr is ParenthesizedExpression) { |
| 197 checkAssignment(expr.expression, type); | 195 checkAssignment(expr.expression, type); |
| 198 } else { | 196 } else { |
| 199 if (_checkNonNullAssignment(expr, type)) { | 197 if (_checkNonNullAssignment(expr, type)) { |
| 200 _checkDowncast(expr, type); | 198 _checkDowncast(expr, type); |
| 201 } | 199 } |
| (...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 694 _recordDynamicInvoke(expr, expr.leftHandSide); | 692 _recordDynamicInvoke(expr, expr.leftHandSide); |
| 695 } else { | 693 } else { |
| 696 // Sanity check the operator. | 694 // Sanity check the operator. |
| 697 assert(methodElement.isOperator); | 695 assert(methodElement.isOperator); |
| 698 var functionType = methodElement.type; | 696 var functionType = methodElement.type; |
| 699 var paramTypes = functionType.normalParameterTypes; | 697 var paramTypes = functionType.normalParameterTypes; |
| 700 assert(paramTypes.length == 1); | 698 assert(paramTypes.length == 1); |
| 701 assert(functionType.namedParameterTypes.isEmpty); | 699 assert(functionType.namedParameterTypes.isEmpty); |
| 702 assert(functionType.optionalParameterTypes.isEmpty); | 700 assert(functionType.optionalParameterTypes.isEmpty); |
| 703 | 701 |
| 704 // Check the LHS type. | 702 // Refine the return type. |
| 705 var rhsType = _getDefiniteType(expr.rightHandSide); | 703 var rhsType = _getDefiniteType(expr.rightHandSide); |
| 706 var lhsType = _getDefiniteType(expr.leftHandSide); | 704 var lhsType = _getDefiniteType(expr.leftHandSide); |
| 707 var returnType = rules.refineBinaryExpressionType( | 705 var returnType = rules.refineBinaryExpressionType( |
| 708 typeProvider, lhsType, op, rhsType, functionType.returnType); | 706 typeProvider, lhsType, op, rhsType, functionType.returnType); |
| 709 | 707 |
| 710 if (!rules.isSubtypeOf(returnType, lhsType)) { | 708 // Check the argument for an implicit cast. |
| 711 final numType = typeProvider.numType; | 709 _checkDowncast(expr.rightHandSide, paramTypes[0], from: rhsType); |
|
Jennifer Messerly
2016/08/25 22:27:15
this is my attempt to fix by simplification :)
Leaf
2016/08/25 22:35:34
:)
| |
| 712 // TODO(jmesserly): this seems to duplicate logic in StaticTypeAnalyzer. | 710 |
| 713 // Try to fix up the numerical case if possible. | 711 // Check the return type for an implicit cast. |
| 714 if (rules.isSubtypeOf(lhsType, numType) && | 712 // |
| 715 rules.isSubtypeOf(lhsType, rhsType)) { | 713 // If needed, mark the left size to indicate a down cast when we assign |
|
Leaf
2016/08/25 22:35:34
size -> side?
| |
| 716 // This is also slightly different from spec, but allows us to keep | 714 // back to it. so these two implicit casts are equivalent: |
| 717 // compound operators in the int += num and num += dynamic cases. | 715 // |
| 718 _recordImplicitCast(expr.rightHandSide, rhsType, lhsType); | 716 // y = /*implicit cast*/(y + 42); |
| 719 } else { | 717 // y/*implicit cast*/ += 42; |
| 720 // TODO(jmesserly): this results in a duplicate error, because | 718 // |
| 721 // ErrorVerifier also reports it. | 719 // TODO(jmesserly): this is an unambiguous way to represent it, but it's |
|
Jennifer Messerly
2016/08/25 22:27:15
https://github.com/dart-lang/dev_compiler/issues/6
| |
| 722 _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR, | 720 // a bit sneaky. We can't use the rightHandSide because that could be a |
| 723 [expr, returnType, lhsType]); | 721 // downcast on its own, and we can't use the entire expression because its |
| 724 } | 722 // result value could used and then implicitly downcast. |
| 725 } else { | 723 _checkDowncast(expr.leftHandSide, lhsType, from: returnType); |
| 726 // Check the RHS type. | |
| 727 // | |
| 728 // This is only needed if we didn't already need a cast, and avoids | |
| 729 // emitting two messages for the same expression. | |
| 730 _checkDowncast(expr.rightHandSide, paramTypes.first); | |
| 731 } | |
| 732 } | 724 } |
| 733 } | 725 } |
| 734 | 726 |
| 735 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. | 727 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. |
| 736 /// | 728 /// |
| 737 /// If [from] is omitted, uses the static type of [expr]. | 729 /// If [from] is omitted, uses the static type of [expr]. |
| 738 /// | 730 /// |
| 739 /// If [expr] does not require a downcast because it is not related to [to] | 731 /// If [expr] does not require a downcast because it is not related to [to] |
| 740 /// or is already a subtype of it, does nothing. | 732 /// or is already a subtype of it, does nothing. |
| 741 void _checkDowncast(Expression expr, DartType to, {DartType from}) { | 733 void _checkDowncast(Expression expr, DartType to, {DartType from}) { |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1477 var visited = new Set<InterfaceType>(); | 1469 var visited = new Set<InterfaceType>(); |
| 1478 do { | 1470 do { |
| 1479 visited.add(current); | 1471 visited.add(current); |
| 1480 current.mixins.reversed.forEach( | 1472 current.mixins.reversed.forEach( |
| 1481 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1473 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1482 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1474 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1483 current = current.superclass; | 1475 current = current.superclass; |
| 1484 } while (!current.isObject && !visited.contains(current)); | 1476 } while (!current.isObject && !visited.contains(current)); |
| 1485 } | 1477 } |
| 1486 } | 1478 } |
| OLD | NEW |