Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 1823793002: Better casting of for-in loops. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 up the element type of the sequence.
vsm 2016/03/21 21:25:20 s/up//
Bob Nystrom 2016/03/21 22:44:55 Done.
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 dynamic, cast it to Iterable<dynamic> or
345 // Stream<dynamic>. Then we'll do a separate cast of the dynamic element
346 // to the variable's type.
347 if (iterableType.isDynamic) {
vsm 2016/03/21 21:25:20 Should we just do checkAssignment(node.iterable, s
Bob Nystrom 2016/03/21 22:44:55 I don't think we want that because we don't want a
vsm 2016/03/21 22:50:35 It'd be a cast to Iterable, not Iterable<int> - i.
Bob Nystrom 2016/03/21 23:00:44 OK, then we're thinking the same thing. That's wha
348 _recordMessage(DownCast.create(
349 rules, node.iterable, iterableType, sequenceInterface));
350 elementType = DynamicTypeImpl.instance;
351 }
352
353 // If the sequence doesn't implement the interface at all, [ErrorVerifier]
354 // will report the error, so ignore it here.
355 if (elementType != null) {
356 // Insert a cast from the sequence's element type to the loop variable's
357 // if needed.
358 _checkDowncast(loopVariable, _getStaticType(loopVariable),
359 from: elementType);
360 }
342 } 361 }
362
343 node.visitChildren(this); 363 node.visitChildren(this);
344 } 364 }
345 365
346 @override 366 @override
347 void visitForStatement(ForStatement node) { 367 void visitForStatement(ForStatement node) {
348 if (node.condition != null) { 368 if (node.condition != null) {
349 checkBoolean(node.condition); 369 checkBoolean(node.condition);
350 } 370 }
351 node.visitChildren(this); 371 node.visitChildren(this);
352 } 372 }
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 var returnType = _specializedBinaryReturnType( 608 var returnType = _specializedBinaryReturnType(
589 op, lhsType, rhsType, functionType.returnType); 609 op, lhsType, rhsType, functionType.returnType);
590 610
591 if (!rules.isSubtypeOf(returnType, lhsType)) { 611 if (!rules.isSubtypeOf(returnType, lhsType)) {
592 final numType = typeProvider.numType; 612 final numType = typeProvider.numType;
593 // Try to fix up the numerical case if possible. 613 // Try to fix up the numerical case if possible.
594 if (rules.isSubtypeOf(lhsType, numType) && 614 if (rules.isSubtypeOf(lhsType, numType) &&
595 rules.isSubtypeOf(lhsType, rhsType)) { 615 rules.isSubtypeOf(lhsType, rhsType)) {
596 // This is also slightly different from spec, but allows us to keep 616 // This is also slightly different from spec, but allows us to keep
597 // compound operators in the int += num and num += dynamic cases. 617 // compound operators in the int += num and num += dynamic cases.
598 staticInfo = DownCast.create( 618 staticInfo =
599 rules, expr.rightHandSide, rhsType, lhsType); 619 DownCast.create(rules, expr.rightHandSide, rhsType, lhsType);
600 rhsType = lhsType; 620 rhsType = lhsType;
601 } else { 621 } else {
602 staticInfo = new StaticTypeError(rules, expr, lhsType); 622 staticInfo = new StaticTypeError(rules, expr, lhsType);
603 } 623 }
604 _recordMessage(staticInfo); 624 _recordMessage(staticInfo);
605 } 625 }
606 626
607 // Check the rhs type 627 // Check the rhs type
608 if (staticInfo is! CoercionInfo) { 628 if (staticInfo is! CoercionInfo) {
609 var paramType = paramTypes.first; 629 var paramType = paramTypes.first;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 op.type == TokenType.MINUS_MINUS) { 676 op.type == TokenType.MINUS_MINUS) {
657 if (_isDynamicTarget(node.operand)) { 677 if (_isDynamicTarget(node.operand)) {
658 _recordDynamicInvoke(node, node.operand); 678 _recordDynamicInvoke(node, node.operand);
659 } 679 }
660 // For ++ and --, even if it is not dynamic, we still need to check 680 // 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. 681 // that the user defined method accepts an `int` as the RHS.
662 // We assume Analyzer has done this already. 682 // We assume Analyzer has done this already.
663 } 683 }
664 } 684 }
665 685
666 /// Records a [DownCast] of [expr] to [toT], if there is one. 686 /// Records a [DownCast] of [expr] from [from] to [to], if there is one.
667 /// 687 ///
668 /// If [expr] does not require a downcast because it is not related to [toT] 688 /// If [from] is omitted, uses the static type of [expr].
689 ///
690 /// If [expr] does not require a downcast because it is not related to [to]
669 /// or is already a subtype of it, does nothing. 691 /// or is already a subtype of it, does nothing.
670 void _checkDowncast(Expression expr, DartType toT) { 692 void _checkDowncast(Expression expr, DartType to, {DartType from}) {
671 DartType fromT = _getStaticType(expr); 693 if (from == null) {
694 from = _getStaticType(expr);
695 }
672 696
673 // We can use anything as void. 697 // We can use anything as void.
674 if (toT.isVoid) return; 698 if (to.isVoid) return;
675 699
676 // fromT <: toT, no coercion needed. 700 // fromT <: toT, no coercion needed.
677 if (rules.isSubtypeOf(fromT, toT)) return; 701 if (rules.isSubtypeOf(from, to)) return;
678 702
679 // TODO(vsm): We can get rid of the second clause if we disallow 703 // TODO(vsm): We can get rid of the second clause if we disallow
680 // all sideways casts - see TODO below. 704 // all sideways casts - see TODO below.
681 // ------- 705 // -------
682 // Note: a function type is never assignable to a class per the Dart 706 // 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 707 // spec - even if it has a compatible call method. We disallow as
684 // well for consistency. 708 // well for consistency.
685 if ((fromT is FunctionType && rules.getCallMethodType(toT) != null) || 709 if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
686 (toT is FunctionType && rules.getCallMethodType(fromT) != null)) { 710 (to is FunctionType && rules.getCallMethodType(from) != null)) {
687 return; 711 return;
688 } 712 }
689 713
690 // Downcast if toT <: fromT 714 // Downcast if toT <: fromT
691 if (rules.isSubtypeOf(toT, fromT)) { 715 if (rules.isSubtypeOf(to, from)) {
692 _recordMessage(DownCast.create(rules, expr, fromT, toT)); 716 _recordMessage(DownCast.create(rules, expr, from, to));
693 return; 717 return;
694 } 718 }
695 719
696 // TODO(vsm): Once we have generic methods, we should delete this 720 // TODO(vsm): Once we have generic methods, we should delete this
697 // workaround. These sideways casts are always ones we warn about 721 // workaround. These sideways casts are always ones we warn about
698 // - i.e., we think they are likely to fail at runtime. 722 // - i.e., we think they are likely to fail at runtime.
699 // ------- 723 // -------
700 // Downcast if toT <===> fromT 724 // Downcast if toT <===> fromT
701 // The intention here is to allow casts that are sideways in the restricted 725 // 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 726 // type system, but allowed in the regular dart type system, since these
703 // are likely to succeed. The canonical example is List<dynamic> and 727 // are likely to succeed. The canonical example is List<dynamic> and
704 // Iterable<T> for some concrete T (e.g. Object). These are unrelated 728 // Iterable<T> for some concrete T (e.g. Object). These are unrelated
705 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. 729 // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
706 if (fromT.isAssignableTo(toT)) { 730 if (from.isAssignableTo(to)) {
707 _recordMessage(DownCast.create(rules, expr, fromT, toT)); 731 _recordMessage(DownCast.create(rules, expr, from, to));
708 } 732 }
709 } 733 }
710 734
711 // Produce a coercion which coerces something of type fromT 735 // Produce a coercion which coerces something of type fromT
712 // to something of type toT. 736 // to something of type toT.
713 // Returns the error coercion if the types cannot be coerced 737 // Returns the error coercion if the types cannot be coerced
714 // according to our current criteria. 738 // according to our current criteria.
715 /// Gets the expected return type of the given function [body], either from 739 /// Gets the expected return type of the given function [body], either from
716 /// a normal return/yield, or from a yield*. 740 /// a normal return/yield, or from a yield*.
717 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { 741 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after
1271 } while (!current.isObject && !visited.contains(current)); 1295 } while (!current.isObject && !visited.contains(current));
1272 } 1296 }
1273 1297
1274 void _recordMessage(StaticInfo info) { 1298 void _recordMessage(StaticInfo info) {
1275 if (info == null) return; 1299 if (info == null) return;
1276 var error = info.toAnalysisError(); 1300 var error = info.toAnalysisError();
1277 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; 1301 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
1278 _reporter.onError(error); 1302 _reporter.onError(error);
1279 } 1303 }
1280 } 1304 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/task/strong/info.dart » ('j') | pkg/analyzer/test/src/task/strong/checker_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698