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 |