| Index: pkg/analyzer/lib/src/task/strong/checker.dart
|
| diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
|
| index 9831fb67ca9a59b79fcc1490f6dae3b952eff307..acf01ff9b4a0f044a607405403f188888c1ab400 100644
|
| --- a/pkg/analyzer/lib/src/task/strong/checker.dart
|
| +++ b/pkg/analyzer/lib/src/task/strong/checker.dart
|
| @@ -145,7 +145,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
| if (expr is ParenthesizedExpression) {
|
| checkAssignment(expr.expression, type);
|
| } else {
|
| - _recordMessage(_checkAssignment(expr, type));
|
| + _checkDowncast(expr, type);
|
| }
|
| }
|
|
|
| @@ -565,25 +565,15 @@ class CodeChecker extends RecursiveAstVisitor {
|
| node.visitChildren(this);
|
| }
|
|
|
| - StaticInfo _checkAssignment(Expression expr, DartType toT) {
|
| - final fromT = _getStaticType(expr);
|
| - final Coercion c = _coerceTo(fromT, toT);
|
| - if (c is Identity) return null;
|
| - if (c is CoercionError) return new StaticTypeError(rules, expr, toT);
|
| - if (c is Cast) return DownCast.create(rules, expr, c);
|
| - assert(false);
|
| - return null;
|
| - }
|
| -
|
| void _checkCompoundAssignment(AssignmentExpression expr) {
|
| var op = expr.operator.type;
|
| assert(op.isAssignmentOperator && op != TokenType.EQ);
|
| var methodElement = expr.staticElement;
|
| if (methodElement == null) {
|
| - // Dynamic invocation
|
| + // Dynamic invocation.
|
| _recordDynamicInvoke(expr, expr.leftHandSide);
|
| } else {
|
| - // Sanity check the operator
|
| + // Sanity check the operator.
|
| assert(methodElement.isOperator);
|
| var functionType = methodElement.type;
|
| var paramTypes = functionType.normalParameterTypes;
|
| @@ -591,7 +581,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
| assert(functionType.namedParameterTypes.isEmpty);
|
| assert(functionType.optionalParameterTypes.isEmpty);
|
|
|
| - // Check the lhs type
|
| + // Check the LHS type.
|
| var staticInfo;
|
| var rhsType = _getStaticType(expr.rightHandSide);
|
| var lhsType = _getStaticType(expr.leftHandSide);
|
| @@ -606,10 +596,9 @@ class CodeChecker extends RecursiveAstVisitor {
|
| // This is also slightly different from spec, but allows us to keep
|
| // compound operators in the int += num and num += dynamic cases.
|
| staticInfo = DownCast.create(
|
| - rules, expr.rightHandSide, Coercion.cast(rhsType, lhsType));
|
| + rules, expr.rightHandSide, new Cast(rhsType, lhsType));
|
| rhsType = lhsType;
|
| } else {
|
| - // Static type error
|
| staticInfo = new StaticTypeError(rules, expr, lhsType);
|
| }
|
| _recordMessage(staticInfo);
|
| @@ -618,8 +607,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
| // Check the rhs type
|
| if (staticInfo is! CoercionInfo) {
|
| var paramType = paramTypes.first;
|
| - staticInfo = _checkAssignment(expr.rightHandSide, paramType);
|
| - _recordMessage(staticInfo);
|
| + _checkDowncast(expr.rightHandSide, paramType);
|
| }
|
| }
|
| }
|
| @@ -675,12 +663,18 @@ class CodeChecker extends RecursiveAstVisitor {
|
| }
|
| }
|
|
|
| - Coercion _coerceTo(DartType fromT, DartType toT) {
|
| - // We can use anything as void
|
| - if (toT.isVoid) return Coercion.identity(toT);
|
| + /// Records a [DownCast] of [expr] to [toT], if there is one.
|
| + ///
|
| + /// If [expr] does not require a downcast because it is not related to [toT]
|
| + /// or is already a subtype of it, does nothing.
|
| + void _checkDowncast(Expression expr, DartType toT) {
|
| + DartType fromT = _getStaticType(expr);
|
| +
|
| + // We can use anything as void.
|
| + if (toT.isVoid) return;
|
|
|
| - // fromT <: toT, no coercion needed
|
| - if (rules.isSubtypeOf(fromT, toT)) return Coercion.identity(toT);
|
| + // fromT <: toT, no coercion needed.
|
| + if (rules.isSubtypeOf(fromT, toT)) return;
|
|
|
| // TODO(vsm): We can get rid of the second clause if we disallow
|
| // all sideways casts - see TODO below.
|
| @@ -690,11 +684,14 @@ class CodeChecker extends RecursiveAstVisitor {
|
| // well for consistency.
|
| if ((fromT is FunctionType && rules.getCallMethodType(toT) != null) ||
|
| (toT is FunctionType && rules.getCallMethodType(fromT) != null)) {
|
| - return Coercion.error();
|
| + return;
|
| }
|
|
|
| // Downcast if toT <: fromT
|
| - if (rules.isSubtypeOf(toT, fromT)) return Coercion.cast(fromT, toT);
|
| + if (rules.isSubtypeOf(toT, fromT)) {
|
| + _recordMessage(DownCast.create(rules, expr, new Cast(fromT, toT)));
|
| + return;
|
| + }
|
|
|
| // TODO(vsm): Once we have generic methods, we should delete this
|
| // workaround. These sideways casts are always ones we warn about
|
| @@ -707,10 +704,8 @@ class CodeChecker extends RecursiveAstVisitor {
|
| // Iterable<T> for some concrete T (e.g. Object). These are unrelated
|
| // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
|
| if (fromT.isAssignableTo(toT)) {
|
| - return Coercion.cast(fromT, toT);
|
| + _recordMessage(DownCast.create(rules, expr, new Cast(fromT, toT)));
|
| }
|
| -
|
| - return Coercion.error();
|
| }
|
|
|
| // Produce a coercion which coerces something of type fromT
|
|
|