| 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 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 var staticInfo = | 320 var staticInfo = |
| 321 new InvalidParameterDeclaration(rules, node, fieldType); | 321 new InvalidParameterDeclaration(rules, node, fieldType); |
| 322 _recordMessage(staticInfo); | 322 _recordMessage(staticInfo); |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 node.visitChildren(this); | 325 node.visitChildren(this); |
| 326 } | 326 } |
| 327 | 327 |
| 328 @override | 328 @override |
| 329 void visitForEachStatement(ForEachStatement node) { | 329 void visitForEachStatement(ForEachStatement node) { |
| 330 // Check that the expression is an Iterable. | |
| 331 var expr = node.iterable; | |
| 332 var iterableType = node.awaitKeyword != null | |
| 333 ? typeProvider.streamType | |
| 334 : typeProvider.iterableType; | |
| 335 var loopVariable = node.identifier != null | 330 var loopVariable = node.identifier != null |
| 336 ? node.identifier | 331 ? node.identifier |
| 337 : node.loopVariable?.identifier; | 332 : node.loopVariable?.identifier; |
| 333 |
| 334 // Safely handle malformed statements. |
| 338 if (loopVariable != null) { | 335 if (loopVariable != null) { |
| 339 var iteratorType = loopVariable.staticType; | 336 // Find the element type of the sequence. |
| 340 var checkedType = iterableType.instantiate([iteratorType]); | 337 var sequenceInterface = node.awaitKeyword != null |
| 341 checkAssignment(expr, checkedType); | 338 ? typeProvider.streamType |
| 339 : typeProvider.iterableType; |
| 340 var iterableType = _getStaticType(node.iterable); |
| 341 var elementType = |
| 342 rules.mostSpecificTypeArgument(iterableType, sequenceInterface); |
| 343 |
| 344 // If the sequence is not an Iterable (or Stream for await for) but is a |
| 345 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then |
| 346 // we'll do a separate cast of the dynamic element to the variable's type. |
| 347 if (elementType == null) { |
| 348 var sequenceType = sequenceInterface.instantiate([DynamicTypeImpl.instan
ce]); |
| 349 |
| 350 if (rules.isSubtypeOf(sequenceType, iterableType)) { |
| 351 _recordMessage(DownCast.create( |
| 352 rules, node.iterable, iterableType, sequenceType)); |
| 353 elementType = DynamicTypeImpl.instance; |
| 354 } |
| 355 } |
| 356 |
| 357 // If the sequence doesn't implement the interface at all, [ErrorVerifier] |
| 358 // will report the error, so ignore it here. |
| 359 if (elementType != null) { |
| 360 // Insert a cast from the sequence's element type to the loop variable's |
| 361 // if needed. |
| 362 _checkDowncast(loopVariable, _getStaticType(loopVariable), |
| 363 from: elementType); |
| 364 } |
| 342 } | 365 } |
| 366 |
| 343 node.visitChildren(this); | 367 node.visitChildren(this); |
| 344 } | 368 } |
| 345 | 369 |
| 346 @override | 370 @override |
| 347 void visitForStatement(ForStatement node) { | 371 void visitForStatement(ForStatement node) { |
| 348 if (node.condition != null) { | 372 if (node.condition != null) { |
| 349 checkBoolean(node.condition); | 373 checkBoolean(node.condition); |
| 350 } | 374 } |
| 351 node.visitChildren(this); | 375 node.visitChildren(this); |
| 352 } | 376 } |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 var returnType = _specializedBinaryReturnType( | 612 var returnType = _specializedBinaryReturnType( |
| 589 op, lhsType, rhsType, functionType.returnType); | 613 op, lhsType, rhsType, functionType.returnType); |
| 590 | 614 |
| 591 if (!rules.isSubtypeOf(returnType, lhsType)) { | 615 if (!rules.isSubtypeOf(returnType, lhsType)) { |
| 592 final numType = typeProvider.numType; | 616 final numType = typeProvider.numType; |
| 593 // Try to fix up the numerical case if possible. | 617 // Try to fix up the numerical case if possible. |
| 594 if (rules.isSubtypeOf(lhsType, numType) && | 618 if (rules.isSubtypeOf(lhsType, numType) && |
| 595 rules.isSubtypeOf(lhsType, rhsType)) { | 619 rules.isSubtypeOf(lhsType, rhsType)) { |
| 596 // This is also slightly different from spec, but allows us to keep | 620 // This is also slightly different from spec, but allows us to keep |
| 597 // compound operators in the int += num and num += dynamic cases. | 621 // compound operators in the int += num and num += dynamic cases. |
| 598 staticInfo = DownCast.create( | 622 staticInfo = |
| 599 rules, expr.rightHandSide, rhsType, lhsType); | 623 DownCast.create(rules, expr.rightHandSide, rhsType, lhsType); |
| 600 rhsType = lhsType; | 624 rhsType = lhsType; |
| 601 } else { | 625 } else { |
| 602 staticInfo = new StaticTypeError(rules, expr, lhsType); | 626 staticInfo = new StaticTypeError(rules, expr, lhsType); |
| 603 } | 627 } |
| 604 _recordMessage(staticInfo); | 628 _recordMessage(staticInfo); |
| 605 } | 629 } |
| 606 | 630 |
| 607 // Check the rhs type | 631 // Check the rhs type |
| 608 if (staticInfo is! CoercionInfo) { | 632 if (staticInfo is! CoercionInfo) { |
| 609 var paramType = paramTypes.first; | 633 var paramType = paramTypes.first; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 op.type == TokenType.MINUS_MINUS) { | 680 op.type == TokenType.MINUS_MINUS) { |
| 657 if (_isDynamicTarget(node.operand)) { | 681 if (_isDynamicTarget(node.operand)) { |
| 658 _recordDynamicInvoke(node, node.operand); | 682 _recordDynamicInvoke(node, node.operand); |
| 659 } | 683 } |
| 660 // For ++ and --, even if it is not dynamic, we still need to check | 684 // For ++ and --, even if it is not dynamic, we still need to check |
| 661 // that the user defined method accepts an `int` as the RHS. | 685 // that the user defined method accepts an `int` as the RHS. |
| 662 // We assume Analyzer has done this already. | 686 // We assume Analyzer has done this already. |
| 663 } | 687 } |
| 664 } | 688 } |
| 665 | 689 |
| 666 /// Records a [DownCast] of [expr] to [toT], if there is one. | 690 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. |
| 667 /// | 691 /// |
| 668 /// If [expr] does not require a downcast because it is not related to [toT] | 692 /// If [from] is omitted, uses the static type of [expr]. |
| 693 /// |
| 694 /// If [expr] does not require a downcast because it is not related to [to] |
| 669 /// or is already a subtype of it, does nothing. | 695 /// or is already a subtype of it, does nothing. |
| 670 void _checkDowncast(Expression expr, DartType toT) { | 696 void _checkDowncast(Expression expr, DartType to, {DartType from}) { |
| 671 DartType fromT = _getStaticType(expr); | 697 if (from == null) { |
| 698 from = _getStaticType(expr); |
| 699 } |
| 672 | 700 |
| 673 // We can use anything as void. | 701 // We can use anything as void. |
| 674 if (toT.isVoid) return; | 702 if (to.isVoid) return; |
| 675 | 703 |
| 676 // fromT <: toT, no coercion needed. | 704 // fromT <: toT, no coercion needed. |
| 677 if (rules.isSubtypeOf(fromT, toT)) return; | 705 if (rules.isSubtypeOf(from, to)) return; |
| 678 | 706 |
| 679 // TODO(vsm): We can get rid of the second clause if we disallow | 707 // TODO(vsm): We can get rid of the second clause if we disallow |
| 680 // all sideways casts - see TODO below. | 708 // all sideways casts - see TODO below. |
| 681 // ------- | 709 // ------- |
| 682 // Note: a function type is never assignable to a class per the Dart | 710 // Note: a function type is never assignable to a class per the Dart |
| 683 // spec - even if it has a compatible call method. We disallow as | 711 // spec - even if it has a compatible call method. We disallow as |
| 684 // well for consistency. | 712 // well for consistency. |
| 685 if ((fromT is FunctionType && rules.getCallMethodType(toT) != null) || | 713 if ((from is FunctionType && rules.getCallMethodType(to) != null) || |
| 686 (toT is FunctionType && rules.getCallMethodType(fromT) != null)) { | 714 (to is FunctionType && rules.getCallMethodType(from) != null)) { |
| 687 return; | 715 return; |
| 688 } | 716 } |
| 689 | 717 |
| 690 // Downcast if toT <: fromT | 718 // Downcast if toT <: fromT |
| 691 if (rules.isSubtypeOf(toT, fromT)) { | 719 if (rules.isSubtypeOf(to, from)) { |
| 692 _recordMessage(DownCast.create(rules, expr, fromT, toT)); | 720 _recordMessage(DownCast.create(rules, expr, from, to)); |
| 693 return; | 721 return; |
| 694 } | 722 } |
| 695 | 723 |
| 696 // TODO(vsm): Once we have generic methods, we should delete this | 724 // TODO(vsm): Once we have generic methods, we should delete this |
| 697 // workaround. These sideways casts are always ones we warn about | 725 // workaround. These sideways casts are always ones we warn about |
| 698 // - i.e., we think they are likely to fail at runtime. | 726 // - i.e., we think they are likely to fail at runtime. |
| 699 // ------- | 727 // ------- |
| 700 // Downcast if toT <===> fromT | 728 // Downcast if toT <===> fromT |
| 701 // The intention here is to allow casts that are sideways in the restricted | 729 // The intention here is to allow casts that are sideways in the restricted |
| 702 // type system, but allowed in the regular dart type system, since these | 730 // type system, but allowed in the regular dart type system, since these |
| 703 // are likely to succeed. The canonical example is List<dynamic> and | 731 // are likely to succeed. The canonical example is List<dynamic> and |
| 704 // Iterable<T> for some concrete T (e.g. Object). These are unrelated | 732 // Iterable<T> for some concrete T (e.g. Object). These are unrelated |
| 705 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. | 733 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. |
| 706 if (fromT.isAssignableTo(toT)) { | 734 if (from.isAssignableTo(to)) { |
| 707 _recordMessage(DownCast.create(rules, expr, fromT, toT)); | 735 _recordMessage(DownCast.create(rules, expr, from, to)); |
| 708 } | 736 } |
| 709 } | 737 } |
| 710 | 738 |
| 711 // Produce a coercion which coerces something of type fromT | 739 // Produce a coercion which coerces something of type fromT |
| 712 // to something of type toT. | 740 // to something of type toT. |
| 713 // Returns the error coercion if the types cannot be coerced | 741 // Returns the error coercion if the types cannot be coerced |
| 714 // according to our current criteria. | 742 // according to our current criteria. |
| 715 /// Gets the expected return type of the given function [body], either from | 743 /// Gets the expected return type of the given function [body], either from |
| 716 /// a normal return/yield, or from a yield*. | 744 /// a normal return/yield, or from a yield*. |
| 717 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { | 745 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1271 } while (!current.isObject && !visited.contains(current)); | 1299 } while (!current.isObject && !visited.contains(current)); |
| 1272 } | 1300 } |
| 1273 | 1301 |
| 1274 void _recordMessage(StaticInfo info) { | 1302 void _recordMessage(StaticInfo info) { |
| 1275 if (info == null) return; | 1303 if (info == null) return; |
| 1276 var error = info.toAnalysisError(); | 1304 var error = info.toAnalysisError(); |
| 1277 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; | 1305 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; |
| 1278 _reporter.onError(error); | 1306 _reporter.onError(error); |
| 1279 } | 1307 } |
| 1280 } | 1308 } |
| OLD | NEW |