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

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: Handle supertypes of Iterable and Stream. 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 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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/error_verifier.dart ('k') | pkg/analyzer/lib/src/task/strong/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698