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

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

Issue 2362563004: re-land fix #27110 with proper DDC side of changes (Closed)
Patch Set: add tests Created 4 years, 2 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 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 _checkDowncast(expr, type); 197 _checkImplicitCast(expr, type);
200 } 198 }
201 } 199 }
202 200
203 /// Analyzer checks boolean conversions, but we need to check too, because 201 /// Analyzer checks boolean conversions, but we need to check too, because
204 /// it uses the default assignability rules that allow `dynamic` and `Object` 202 /// it uses the default assignability rules that allow `dynamic` and `Object`
205 /// to be assigned to bool with no message. 203 /// to be assigned to bool with no message.
206 void checkBoolean(Expression expr) => 204 void checkBoolean(Expression expr) =>
207 checkAssignment(expr, typeProvider.boolType); 205 checkAssignment(expr, typeProvider.boolType);
208 206
209 void checkFunctionApplication(InvocationExpression node) { 207 void checkFunctionApplication(InvocationExpression node) {
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 rules.mostSpecificTypeArgument(iterableType, sequenceInterface); 400 rules.mostSpecificTypeArgument(iterableType, sequenceInterface);
403 401
404 // If the sequence is not an Iterable (or Stream for await for) but is a 402 // If the sequence is not an Iterable (or Stream for await for) but is a
405 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then 403 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then
406 // we'll do a separate cast of the dynamic element to the variable's type. 404 // we'll do a separate cast of the dynamic element to the variable's type.
407 if (elementType == null) { 405 if (elementType == null) {
408 var sequenceType = 406 var sequenceType =
409 sequenceInterface.instantiate([DynamicTypeImpl.instance]); 407 sequenceInterface.instantiate([DynamicTypeImpl.instance]);
410 408
411 if (rules.isSubtypeOf(sequenceType, iterableType)) { 409 if (rules.isSubtypeOf(sequenceType, iterableType)) {
412 _recordImplicitCast(node.iterable, iterableType, sequenceType); 410 _recordImplicitCast(node.iterable, sequenceType, from: iterableType);
413 elementType = DynamicTypeImpl.instance; 411 elementType = DynamicTypeImpl.instance;
414 } 412 }
415 } 413 }
416 414
417 // If the sequence doesn't implement the interface at all, [ErrorVerifier] 415 // If the sequence doesn't implement the interface at all, [ErrorVerifier]
418 // will report the error, so ignore it here. 416 // will report the error, so ignore it here.
419 if (elementType != null) { 417 if (elementType != null) {
420 // Insert a cast from the sequence's element type to the loop variable's 418 // Insert a cast from the sequence's element type to the loop variable's
421 // if needed. 419 // if needed.
422 _checkDowncast(loopVariable, _getDefiniteType(loopVariable), 420 _checkImplicitCast(loopVariable, _getDefiniteType(loopVariable),
423 from: elementType); 421 from: elementType);
424 } 422 }
425 } 423 }
426 424
427 node.visitChildren(this); 425 node.visitChildren(this);
428 } 426 }
429 427
430 @override 428 @override
431 void visitForStatement(ForStatement node) { 429 void visitForStatement(ForStatement node) {
432 if (node.condition != null) { 430 if (node.condition != null) {
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 // we call [checkFunctionApplication]. 568 // we call [checkFunctionApplication].
571 setIsDynamicInvoke(node.methodName, true); 569 setIsDynamicInvoke(node.methodName, true);
572 } else { 570 } else {
573 checkFunctionApplication(node); 571 checkFunctionApplication(node);
574 } 572 }
575 node.visitChildren(this); 573 node.visitChildren(this);
576 } 574 }
577 575
578 @override 576 @override
579 void visitPostfixExpression(PostfixExpression node) { 577 void visitPostfixExpression(PostfixExpression node) {
580 _checkUnary(node, node.staticElement); 578 _checkUnary(node.operand, node.operator, node.staticElement);
581 node.visitChildren(this); 579 node.visitChildren(this);
582 } 580 }
583 581
584 @override 582 @override
585 void visitPrefixedIdentifier(PrefixedIdentifier node) { 583 void visitPrefixedIdentifier(PrefixedIdentifier node) {
586 _checkFieldAccess(node, node.prefix, node.identifier); 584 _checkFieldAccess(node, node.prefix, node.identifier);
587 } 585 }
588 586
589 @override 587 @override
590 void visitPrefixExpression(PrefixExpression node) { 588 void visitPrefixExpression(PrefixExpression node) {
591 if (node.operator.type == TokenType.BANG) { 589 if (node.operator.type == TokenType.BANG) {
592 checkBoolean(node.operand); 590 checkBoolean(node.operand);
593 } else { 591 } else {
594 _checkUnary(node, node.staticElement); 592 _checkUnary(node.operand, node.operator, node.staticElement);
595 } 593 }
596 node.visitChildren(this); 594 node.visitChildren(this);
597 } 595 }
598 596
599 @override 597 @override
600 void visitPropertyAccess(PropertyAccess node) { 598 void visitPropertyAccess(PropertyAccess node) {
601 _checkFieldAccess(node, node.realTarget, node.propertyName); 599 _checkFieldAccess(node, node.realTarget, node.propertyName);
602 } 600 }
603 601
604 @override 602 @override
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 _recordDynamicInvoke(expr, expr.leftHandSide); 690 _recordDynamicInvoke(expr, expr.leftHandSide);
693 } else { 691 } else {
694 // Sanity check the operator. 692 // Sanity check the operator.
695 assert(methodElement.isOperator); 693 assert(methodElement.isOperator);
696 var functionType = methodElement.type; 694 var functionType = methodElement.type;
697 var paramTypes = functionType.normalParameterTypes; 695 var paramTypes = functionType.normalParameterTypes;
698 assert(paramTypes.length == 1); 696 assert(paramTypes.length == 1);
699 assert(functionType.namedParameterTypes.isEmpty); 697 assert(functionType.namedParameterTypes.isEmpty);
700 assert(functionType.optionalParameterTypes.isEmpty); 698 assert(functionType.optionalParameterTypes.isEmpty);
701 699
702 // Check the LHS type. 700 // Refine the return type.
703 var rhsType = _getDefiniteType(expr.rightHandSide); 701 var rhsType = _getDefiniteType(expr.rightHandSide);
704 var lhsType = _getDefiniteType(expr.leftHandSide); 702 var lhsType = _getDefiniteType(expr.leftHandSide);
705 var returnType = rules.refineBinaryExpressionType( 703 var returnType = rules.refineBinaryExpressionType(
706 typeProvider, lhsType, op, rhsType, functionType.returnType); 704 typeProvider, lhsType, op, rhsType, functionType.returnType);
707 705
708 if (!rules.isSubtypeOf(returnType, lhsType)) { 706 // Check the argument for an implicit cast.
709 final numType = typeProvider.numType; 707 _checkImplicitCast(expr.rightHandSide, paramTypes[0], from: rhsType);
710 // TODO(jmesserly): this seems to duplicate logic in StaticTypeAnalyzer. 708
711 // Try to fix up the numerical case if possible. 709 // Check the return type for an implicit cast.
712 if (rules.isSubtypeOf(lhsType, numType) && 710 //
713 rules.isSubtypeOf(lhsType, rhsType)) { 711 // If needed, mark the assignment to indicate a down cast when we assign
714 // This is also slightly different from spec, but allows us to keep 712 // back to it. So these two implicit casts are equivalent:
715 // compound operators in the int += num and num += dynamic cases. 713 //
716 _recordImplicitCast(expr.rightHandSide, rhsType, lhsType); 714 // y = /*implicit cast*/(y + 42);
717 } else { 715 // /*implicit assignment cast*/y += 42;
718 // TODO(jmesserly): this results in a duplicate error, because 716 //
719 // ErrorVerifier also reports it. 717 _checkImplicitCast(expr.leftHandSide, lhsType,
720 _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR, 718 from: returnType, opAssign: true);
721 [expr, returnType, lhsType]);
722 }
723 } else {
724 // Check the RHS type.
725 //
726 // This is only needed if we didn't already need a cast, and avoids
727 // emitting two messages for the same expression.
728 _checkDowncast(expr.rightHandSide, paramTypes.first);
729 }
730 } 719 }
731 } 720 }
732 721
733 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. 722 /// Returns true if we need an implicit cast of [expr] from [from] type to
723 /// [to] type, otherwise returns false.
734 /// 724 ///
735 /// If [from] is omitted, uses the static type of [expr]. 725 /// If [from] is omitted, uses the static type of [expr].
736 /// 726 bool _needsImplicitCast(Expression expr, DartType to, {DartType from}) {
737 /// If [expr] does not require a downcast because it is not related to [to] 727 from ??= _getDefiniteType(expr);
738 /// or is already a subtype of it, does nothing.
739 void _checkDowncast(Expression expr, DartType to, {DartType from}) {
740 if (from == null) {
741 from = _getDefiniteType(expr);
742 }
743 728
744 if (!_checkNonNullAssignment(expr, to, from)) return; 729 if (!_checkNonNullAssignment(expr, to, from)) return false;
745 730
746 // We can use anything as void. 731 // We can use anything as void.
747 if (to.isVoid) return; 732 if (to.isVoid) return false;
748 733
749 // fromT <: toT, no coercion needed. 734 // fromT <: toT, no coercion needed.
750 if (rules.isSubtypeOf(from, to)) return; 735 if (rules.isSubtypeOf(from, to)) return false;
751 736
752 // Note: a function type is never assignable to a class per the Dart 737 // Note: a function type is never assignable to a class per the Dart
753 // spec - even if it has a compatible call method. We disallow as 738 // spec - even if it has a compatible call method. We disallow as
754 // well for consistency. 739 // well for consistency.
755 if (from is FunctionType && rules.getCallMethodType(to) != null) { 740 if (from is FunctionType && rules.getCallMethodType(to) != null) {
756 return; 741 return false;
757 } 742 }
758 743
759 // Downcast if toT <: fromT 744 // Downcast if toT <: fromT
760 if (rules.isSubtypeOf(to, from)) { 745 if (rules.isSubtypeOf(to, from)) {
761 _recordImplicitCast(expr, from, to); 746 return true;
762 return;
763 } 747 }
764 748
765 // Anything else is an illegal sideways cast. 749 // Anything else is an illegal sideways cast.
766 // However, these will have been reported already in error_verifier, so we 750 // However, these will have been reported already in error_verifier, so we
767 // don't need to report them again. 751 // don't need to report them again.
752 return false;
753 }
754
755 /// Checks if an implicit cast of [expr] from [from] type to [to] type is
756 /// needed, and if so records it.
757 ///
758 /// If [from] is omitted, uses the static type of [expr].
759 ///
760 /// If [expr] does not require an implicit cast because it is not related to
761 /// [to] or is already a subtype of it, does nothing.
762 void _checkImplicitCast(Expression expr, DartType to,
763 {DartType from, bool opAssign: false}) {
764 from ??= _getDefiniteType(expr);
765
766 if (_needsImplicitCast(expr, to, from: from)) {
767 _recordImplicitCast(expr, to, from: from, opAssign: opAssign);
768 }
768 } 769 }
769 770
770 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { 771 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
771 if (field.staticElement == null && 772 if (field.staticElement == null &&
772 !typeProvider.isObjectMember(field.name)) { 773 !typeProvider.isObjectMember(field.name)) {
773 _recordDynamicInvoke(node, target); 774 _recordDynamicInvoke(node, target);
774 } 775 }
775 node.visitChildren(this); 776 node.visitChildren(this);
776 } 777 }
777 778
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 if (expression != null) checkAssignment(expression, type); 902 if (expression != null) checkAssignment(expression, type);
902 } 903 }
903 904
904 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) { 905 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
905 var type = getType(typeName); 906 var type = getType(typeName);
906 if (!rules.isGroundType(type)) { 907 if (!rules.isGroundType(type)) {
907 _recordMessage(node, StrongModeCode.NON_GROUND_TYPE_CHECK_INFO, [type]); 908 _recordMessage(node, StrongModeCode.NON_GROUND_TYPE_CHECK_INFO, [type]);
908 } 909 }
909 } 910 }
910 911
911 void _checkUnary( 912 void _checkUnary(Expression operand, Token op, MethodElement element) {
912 /*PrefixExpression|PostfixExpression*/ node, 913 bool isIncrementAssign =
913 Element element) { 914 op.type == TokenType.PLUS_PLUS || op.type == TokenType.MINUS_MINUS;
914 var op = node.operator; 915 if (op.isUserDefinableOperator || isIncrementAssign) {
915 if (op.isUserDefinableOperator ||
916 op.type == TokenType.PLUS_PLUS ||
917 op.type == TokenType.MINUS_MINUS) {
918 if (element == null) { 916 if (element == null) {
919 _recordDynamicInvoke(node, node.operand); 917 _recordDynamicInvoke(operand.parent, operand);
918 } else if (isIncrementAssign) {
919 // For ++ and --, even if it is not dynamic, we still need to check
920 // that the user defined method accepts an `int` as the RHS.
921 //
922 // We assume Analyzer has done this already (in ErrorVerifier).
923 //
924 // However, we also need to check the return type.
925
926 // Refine the return type.
927 var functionType = element.type;
928 var rhsType = typeProvider.intType;
929 var lhsType = _getDefiniteType(operand);
930 var returnType = rules.refineBinaryExpressionType(typeProvider, lhsType,
931 TokenType.PLUS, rhsType, functionType.returnType);
932
933 // Skip the argument check - `int` cannot be downcast.
934 //
935 // Check the return type for an implicit cast.
936 //
937 // If needed, mark the assignment to indicate a down cast when we assign
938 // back to it. So these two implicit casts are equivalent:
939 //
940 // y = /*implicit cast*/(y + 1);
941 // /*implicit assignment cast*/y++;
942 //
943 _checkImplicitCast(operand, lhsType, from: returnType, opAssign: true);
920 } 944 }
921 // For ++ and --, even if it is not dynamic, we still need to check
922 // that the user defined method accepts an `int` as the RHS.
923 // We assume Analyzer has done this already.
924 } 945 }
925 } 946 }
926 947
927 DartType _getDefiniteType(Expression expr) => 948 DartType _getDefiniteType(Expression expr) =>
928 getDefiniteType(expr, rules, typeProvider); 949 getDefiniteType(expr, rules, typeProvider);
929 950
930 /// Gets the expected return type of the given function [body], either from 951 /// Gets the expected return type of the given function [body], either from
931 /// a normal return/yield, or from a yield*. 952 /// a normal return/yield, or from a yield*.
932 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { 953 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
933 FunctionType functionType; 954 FunctionType functionType;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 } 1035 }
1015 1036
1016 void _recordDynamicInvoke(AstNode node, Expression target) { 1037 void _recordDynamicInvoke(AstNode node, Expression target) {
1017 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]); 1038 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]);
1018 // TODO(jmesserly): we may eventually want to record if the whole operation 1039 // TODO(jmesserly): we may eventually want to record if the whole operation
1019 // (node) was dynamic, rather than the target, but this is an easier fit 1040 // (node) was dynamic, rather than the target, but this is an easier fit
1020 // with what we used to do. 1041 // with what we used to do.
1021 if (target != null) setIsDynamicInvoke(target, true); 1042 if (target != null) setIsDynamicInvoke(target, true);
1022 } 1043 }
1023 1044
1024 /// Records an implicit cast for the [expression] from [fromType] to [toType]. 1045 /// Records an implicit cast for the [expr] from [from] to [to].
1025 /// 1046 ///
1026 /// This will emit the appropriate error/warning/hint message as well as mark 1047 /// This will emit the appropriate error/warning/hint message as well as mark
1027 /// the AST node. 1048 /// the AST node.
1028 void _recordImplicitCast( 1049 void _recordImplicitCast(Expression expr, DartType to,
1029 Expression expression, DartType fromType, DartType toType) { 1050 {DartType from, bool opAssign: false}) {
1030 // toT <:_R fromT => to <: fromT 1051 assert(rules.isSubtypeOf(to, from));
1031 // NB: classes with call methods are subtypes of function
1032 // types, but the function type is not assignable to the class
1033 assert(toType.isSubtypeOf(fromType));
1034 1052
1035 // Inference "casts": 1053 // Inference "casts":
1036 if (expression is Literal || expression is FunctionExpression) { 1054 if (expr is Literal || expr is FunctionExpression) {
1037 // fromT should be an exact type - this will almost certainly fail at 1055 // fromT should be an exact type - this will almost certainly fail at
1038 // runtime. 1056 // runtime.
1039 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, 1057 _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR, [expr, from, to]);
1040 [expression, fromType, toType]);
1041 return; 1058 return;
1042 } 1059 }
1043 1060
1044 if (expression is InstanceCreationExpression) { 1061 if (expr is InstanceCreationExpression) {
1045 ConstructorElement e = expression.staticElement; 1062 ConstructorElement e = expr.staticElement;
1046 if (e == null || !e.isFactory) { 1063 if (e == null || !e.isFactory) {
1047 // fromT should be an exact type - this will almost certainly fail at 1064 // fromT should be an exact type - this will almost certainly fail at
1048 // runtime. 1065 // runtime.
1049 1066
1050 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, 1067 _recordMessage(
1051 [expression, fromType, toType]); 1068 expr, StrongModeCode.STATIC_TYPE_ERROR, [expr, from, to]);
1052 return; 1069 return;
1053 } 1070 }
1054 } 1071 }
1055 1072
1056 if (isKnownFunction(expression)) { 1073 if (isKnownFunction(expr)) {
1057 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, 1074 _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR, [expr, from, to]);
1058 [expression, fromType, toType]);
1059 return; 1075 return;
1060 } 1076 }
1061 1077
1062 // TODO(vsm): Change this to an assert when we have generic methods and 1078 // Composite cast: these are more likely to fail.
1063 // fix TypeRules._coerceTo to disallow implicit sideways casts.
1064 bool downCastComposite = false; 1079 bool downCastComposite = false;
1065 if (!rules.isSubtypeOf(toType, fromType)) { 1080 if (!rules.isGroundType(to)) {
1066 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
1067 downCastComposite = true;
1068 }
1069
1070 // Composite cast: these are more likely to fail.
1071 if (!rules.isGroundType(toType)) {
1072 // This cast is (probably) due to our different treatment of dynamic. 1081 // This cast is (probably) due to our different treatment of dynamic.
1073 // It may be more likely to fail at runtime. 1082 // It may be more likely to fail at runtime.
1074 if (fromType is InterfaceType) { 1083 if (from is InterfaceType) {
1075 // For class types, we'd like to allow non-generic down casts, e.g., 1084 // For class types, we'd like to allow non-generic down casts, e.g.,
1076 // Iterable<T> to List<T>. The intuition here is that raw (generic) 1085 // Iterable<T> to List<T>. The intuition here is that raw (generic)
1077 // casts are problematic, and we should complain about those. 1086 // casts are problematic, and we should complain about those.
1078 var typeArgs = fromType.typeArguments; 1087 var typeArgs = from.typeArguments;
1079 downCastComposite = 1088 downCastComposite =
1080 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic); 1089 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
1081 } else { 1090 } else {
1082 downCastComposite = true; 1091 downCastComposite = true;
1083 } 1092 }
1084 } 1093 }
1085 1094
1086 var parent = expression.parent; 1095 var parent = expr.parent;
1087 ErrorCode errorCode; 1096 ErrorCode errorCode;
1088 if (downCastComposite) { 1097 if (downCastComposite) {
1089 errorCode = StrongModeCode.DOWN_CAST_COMPOSITE; 1098 errorCode = StrongModeCode.DOWN_CAST_COMPOSITE;
1090 } else if (fromType.isDynamic) { 1099 } else if (from.isDynamic) {
1091 errorCode = StrongModeCode.DYNAMIC_CAST; 1100 errorCode = StrongModeCode.DYNAMIC_CAST;
1092 } else if (parent is VariableDeclaration && 1101 } else if (parent is VariableDeclaration && parent.initializer == expr) {
1093 parent.initializer == expression) {
1094 errorCode = StrongModeCode.ASSIGNMENT_CAST; 1102 errorCode = StrongModeCode.ASSIGNMENT_CAST;
1095 } else { 1103 } else {
1096 errorCode = StrongModeCode.DOWN_CAST_IMPLICIT; 1104 errorCode = opAssign
1105 ? StrongModeCode.DOWN_CAST_IMPLICIT_ASSIGN
1106 : StrongModeCode.DOWN_CAST_IMPLICIT;
1097 } 1107 }
1098 1108 _recordMessage(expr, errorCode, [from, to]);
1099 _recordMessage(expression, errorCode, [fromType, toType]); 1109 if (opAssign) {
1100 setImplicitCast(expression, toType); 1110 setImplicitAssignmentCast(expr, to);
1111 } else {
1112 setImplicitCast(expr, to);
1113 }
1101 _hasImplicitCasts = true; 1114 _hasImplicitCasts = true;
1102 } 1115 }
1103 1116
1104 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) { 1117 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) {
1105 var severity = errorCode.errorSeverity; 1118 var severity = errorCode.errorSeverity;
1106 if (severity == ErrorSeverity.ERROR) _failure = true; 1119 if (severity == ErrorSeverity.ERROR) _failure = true;
1107 if (severity != ErrorSeverity.INFO || _options.strongModeHints) { 1120 if (severity != ErrorSeverity.INFO || _options.strongModeHints) {
1108 int begin = node is AnnotatedNode 1121 int begin = node is AnnotatedNode
1109 ? node.firstTokenAfterCommentAndMetadata.offset 1122 ? node.firstTokenAfterCommentAndMetadata.offset
1110 : node.offset; 1123 : node.offset;
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after
1464 var visited = new Set<InterfaceType>(); 1477 var visited = new Set<InterfaceType>();
1465 do { 1478 do {
1466 visited.add(current); 1479 visited.add(current);
1467 current.mixins.reversed.forEach( 1480 current.mixins.reversed.forEach(
1468 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1481 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1469 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1482 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1470 current = current.superclass; 1483 current = current.superclass;
1471 } while (!current.isObject && !visited.contains(current)); 1484 } while (!current.isObject && !visited.contains(current));
1472 } 1485 }
1473 } 1486 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/task/strong/ast_properties.dart ('k') | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698