| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.type_checker; | 4 library kernel.type_checker; |
| 5 | 5 |
| 6 import 'ast.dart'; | 6 import 'ast.dart'; |
| 7 import 'class_hierarchy.dart'; | 7 import 'class_hierarchy.dart'; |
| 8 import 'core_types.dart'; | 8 import 'core_types.dart'; |
| 9 import 'type_algebra.dart'; | 9 import 'type_algebra.dart'; |
| 10 import 'type_environment.dart'; | 10 import 'type_environment.dart'; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 checkAssignable(ownMember, getterType(host, ownMember), | 78 checkAssignable(ownMember, getterType(host, ownMember), |
| 79 getterType(host, superMember)); | 79 getterType(host, superMember)); |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 /// Check that [from] is a subtype of [to]. | 83 /// Check that [from] is a subtype of [to]. |
| 84 /// | 84 /// |
| 85 /// [where] is an AST node indicating roughly where the check is required. | 85 /// [where] is an AST node indicating roughly where the check is required. |
| 86 void checkAssignable(TreeNode where, DartType from, DartType to); | 86 void checkAssignable(TreeNode where, DartType from, DartType to); |
| 87 | 87 |
| 88 /// Checks that [expression], which has type [from], can be assigned to [to]. |
| 89 /// |
| 90 /// Should return a downcast if necessary, or [expression] if no cast is |
| 91 /// needed. |
| 92 Expression checkAndDowncastExpression( |
| 93 Expression expression, DartType from, DartType to) { |
| 94 checkAssignable(expression, from, to); |
| 95 return expression; |
| 96 } |
| 97 |
| 88 /// Indicates that type checking failed. | 98 /// Indicates that type checking failed. |
| 89 void fail(TreeNode where, String message); | 99 void fail(TreeNode where, String message); |
| 90 } | 100 } |
| 91 | 101 |
| 92 class TypeCheckingVisitor | 102 class TypeCheckingVisitor |
| 93 implements | 103 implements |
| 94 ExpressionVisitor<DartType>, | 104 ExpressionVisitor<DartType>, |
| 95 StatementVisitor<Null>, | 105 StatementVisitor<Null>, |
| 96 MemberVisitor<Null>, | 106 MemberVisitor<Null>, |
| 97 InitializerVisitor<Null> { | 107 InitializerVisitor<Null> { |
| 98 final TypeChecker checker; | 108 final TypeChecker checker; |
| 99 final TypeEnvironment environment; | 109 final TypeEnvironment environment; |
| 100 | 110 |
| 101 CoreTypes get coreTypes => environment.coreTypes; | 111 CoreTypes get coreTypes => environment.coreTypes; |
| 102 ClassHierarchy get hierarchy => environment.hierarchy; | 112 ClassHierarchy get hierarchy => environment.hierarchy; |
| 103 Class get currentClass => environment.thisType.classNode; | 113 Class get currentClass => environment.thisType.classNode; |
| 104 | 114 |
| 105 TypeCheckingVisitor(this.checker, this.environment); | 115 TypeCheckingVisitor(this.checker, this.environment); |
| 106 | 116 |
| 107 void checkAssignable(TreeNode where, DartType from, DartType to) { | 117 void checkAssignable(TreeNode where, DartType from, DartType to) { |
| 108 checker.checkAssignable(where, from, to); | 118 checker.checkAssignable(where, from, to); |
| 109 } | 119 } |
| 110 | 120 |
| 111 void checkAssignableExpression(Expression from, DartType to) { | 121 Expression checkAndDowncastExpression(Expression from, DartType to) { |
| 112 checker.checkAssignable(from, visitExpression(from), to); | 122 var parent = from.parent; |
| 123 var type = visitExpression(from); |
| 124 var result = checker.checkAndDowncastExpression(from, type, to); |
| 125 result.parent = parent; |
| 126 return result; |
| 127 } |
| 128 |
| 129 void checkExpressionNoDowncast(Expression expression, DartType to) { |
| 130 checkAssignable(expression, visitExpression(expression), to); |
| 113 } | 131 } |
| 114 | 132 |
| 115 void fail(TreeNode node, String message) { | 133 void fail(TreeNode node, String message) { |
| 116 checker.fail(node, message); | 134 checker.fail(node, message); |
| 117 } | 135 } |
| 118 | 136 |
| 119 DartType visitExpression(Expression node) => node.accept(this); | 137 DartType visitExpression(Expression node) => node.accept(this); |
| 120 | 138 |
| 121 void visitStatement(Statement node) { | 139 void visitStatement(Statement node) { |
| 122 node.accept(this); | 140 node.accept(this); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 139 defaultStatement(Statement node) { | 157 defaultStatement(Statement node) { |
| 140 throw 'Unexpected statement ${node.runtimeType}'; | 158 throw 'Unexpected statement ${node.runtimeType}'; |
| 141 } | 159 } |
| 142 | 160 |
| 143 defaultInitializer(Initializer node) { | 161 defaultInitializer(Initializer node) { |
| 144 throw 'Unexpected initializer ${node.runtimeType}'; | 162 throw 'Unexpected initializer ${node.runtimeType}'; |
| 145 } | 163 } |
| 146 | 164 |
| 147 visitField(Field node) { | 165 visitField(Field node) { |
| 148 if (node.initializer != null) { | 166 if (node.initializer != null) { |
| 149 checkAssignableExpression(node.initializer, node.type); | 167 node.initializer = |
| 168 checkAndDowncastExpression(node.initializer, node.type); |
| 150 } | 169 } |
| 151 } | 170 } |
| 152 | 171 |
| 153 visitConstructor(Constructor node) { | 172 visitConstructor(Constructor node) { |
| 154 environment.returnType = null; | 173 environment.returnType = null; |
| 155 environment.yieldType = null; | 174 environment.yieldType = null; |
| 156 node.initializers.forEach(visitInitializer); | 175 node.initializers.forEach(visitInitializer); |
| 157 handleFunctionNode(node.function); | 176 handleFunctionNode(node.function); |
| 158 } | 177 } |
| 159 | 178 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 181 var oldYield = environment.yieldType; | 200 var oldYield = environment.yieldType; |
| 182 environment.returnType = _getInternalReturnType(node); | 201 environment.returnType = _getInternalReturnType(node); |
| 183 environment.yieldType = _getYieldType(node); | 202 environment.yieldType = _getYieldType(node); |
| 184 handleFunctionNode(node); | 203 handleFunctionNode(node); |
| 185 environment.returnType = oldReturn; | 204 environment.returnType = oldReturn; |
| 186 environment.yieldType = oldYield; | 205 environment.yieldType = oldYield; |
| 187 } | 206 } |
| 188 | 207 |
| 189 void handleOptionalParameter(VariableDeclaration parameter) { | 208 void handleOptionalParameter(VariableDeclaration parameter) { |
| 190 if (parameter.initializer != null) { | 209 if (parameter.initializer != null) { |
| 191 checkAssignableExpression(parameter.initializer, parameter.type); | 210 // Default parameter values cannot be downcast. |
| 211 checkExpressionNoDowncast(parameter.initializer, parameter.type); |
| 192 } | 212 } |
| 193 } | 213 } |
| 194 | 214 |
| 195 Substitution getReceiverType( | 215 Substitution getReceiverType( |
| 196 TreeNode access, Expression receiver, Member member) { | 216 TreeNode access, Expression receiver, Member member) { |
| 197 var type = visitExpression(receiver); | 217 var type = visitExpression(receiver); |
| 198 Class superclass = member.enclosingClass; | 218 Class superclass = member.enclosingClass; |
| 199 if (superclass.supertype == null) { | 219 if (superclass.supertype == null) { |
| 200 return Substitution.empty; // Members on Object are always accessible. | 220 return Substitution.empty; // Members on Object are always accessible. |
| 201 } | 221 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 var substitution = Substitution.combine(receiver, instantiation); | 268 var substitution = Substitution.combine(receiver, instantiation); |
| 249 for (int i = 0; i < typeParameters.length; ++i) { | 269 for (int i = 0; i < typeParameters.length; ++i) { |
| 250 var argument = arguments.types[i]; | 270 var argument = arguments.types[i]; |
| 251 var bound = substitution.substituteType(typeParameters[i].bound); | 271 var bound = substitution.substituteType(typeParameters[i].bound); |
| 252 checkAssignable(arguments, argument, bound); | 272 checkAssignable(arguments, argument, bound); |
| 253 } | 273 } |
| 254 for (int i = 0; i < arguments.positional.length; ++i) { | 274 for (int i = 0; i < arguments.positional.length; ++i) { |
| 255 var expectedType = substitution.substituteType( | 275 var expectedType = substitution.substituteType( |
| 256 function.positionalParameters[i].type, | 276 function.positionalParameters[i].type, |
| 257 contravariant: true); | 277 contravariant: true); |
| 258 checkAssignableExpression(arguments.positional[i], expectedType); | 278 arguments.positional[i] = |
| 279 checkAndDowncastExpression(arguments.positional[i], expectedType); |
| 259 } | 280 } |
| 260 for (int i = 0; i < arguments.named.length; ++i) { | 281 for (int i = 0; i < arguments.named.length; ++i) { |
| 261 var argument = arguments.named[i]; | 282 var argument = arguments.named[i]; |
| 262 bool found = false; | 283 bool found = false; |
| 263 for (int j = 0; j < function.namedParameters.length; ++j) { | 284 for (int j = 0; j < function.namedParameters.length; ++j) { |
| 264 if (argument.name == function.namedParameters[j].name) { | 285 if (argument.name == function.namedParameters[j].name) { |
| 265 var expectedType = substitution.substituteType( | 286 var expectedType = substitution.substituteType( |
| 266 function.namedParameters[j].type, | 287 function.namedParameters[j].type, |
| 267 contravariant: true); | 288 contravariant: true); |
| 268 checkAssignableExpression(argument.value, expectedType); | 289 argument.value = |
| 290 checkAndDowncastExpression(argument.value, expectedType); |
| 269 found = true; | 291 found = true; |
| 270 break; | 292 break; |
| 271 } | 293 } |
| 272 } | 294 } |
| 273 if (!found) { | 295 if (!found) { |
| 274 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); | 296 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); |
| 275 return const BottomType(); | 297 return const BottomType(); |
| 276 } | 298 } |
| 277 } | 299 } |
| 278 return substitution.substituteType(function.returnType); | 300 return substitution.substituteType(function.returnType); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 return environment.unfutureType(visitExpression(node.operand)); | 359 return environment.unfutureType(visitExpression(node.operand)); |
| 338 } | 360 } |
| 339 | 361 |
| 340 @override | 362 @override |
| 341 DartType visitBoolLiteral(BoolLiteral node) { | 363 DartType visitBoolLiteral(BoolLiteral node) { |
| 342 return environment.boolType; | 364 return environment.boolType; |
| 343 } | 365 } |
| 344 | 366 |
| 345 @override | 367 @override |
| 346 DartType visitConditionalExpression(ConditionalExpression node) { | 368 DartType visitConditionalExpression(ConditionalExpression node) { |
| 347 checkAssignableExpression(node.condition, environment.boolType); | 369 node.condition = |
| 348 checkAssignableExpression(node.then, node.staticType); | 370 checkAndDowncastExpression(node.condition, environment.boolType); |
| 349 checkAssignableExpression(node.otherwise, node.staticType); | 371 node.then = checkAndDowncastExpression(node.then, node.staticType); |
| 372 node.otherwise = |
| 373 checkAndDowncastExpression(node.otherwise, node.staticType); |
| 350 return node.staticType; | 374 return node.staticType; |
| 351 } | 375 } |
| 352 | 376 |
| 353 @override | 377 @override |
| 354 DartType visitConstructorInvocation(ConstructorInvocation node) { | 378 DartType visitConstructorInvocation(ConstructorInvocation node) { |
| 355 Constructor target = node.target; | 379 Constructor target = node.target; |
| 356 Arguments arguments = node.arguments; | 380 Arguments arguments = node.arguments; |
| 357 Class class_ = target.enclosingClass; | 381 Class class_ = target.enclosingClass; |
| 358 handleCall(arguments, target.function, | 382 handleCall(arguments, target.function, |
| 359 typeParameters: class_.typeParameters); | 383 typeParameters: class_.typeParameters); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 DartType visitLet(Let node) { | 436 DartType visitLet(Let node) { |
| 413 var value = visitExpression(node.variable.initializer); | 437 var value = visitExpression(node.variable.initializer); |
| 414 if (node.variable.type is DynamicType) { | 438 if (node.variable.type is DynamicType) { |
| 415 node.variable.type = value; | 439 node.variable.type = value; |
| 416 } | 440 } |
| 417 return visitExpression(node.body); | 441 return visitExpression(node.body); |
| 418 } | 442 } |
| 419 | 443 |
| 420 @override | 444 @override |
| 421 DartType visitListLiteral(ListLiteral node) { | 445 DartType visitListLiteral(ListLiteral node) { |
| 422 for (var item in node.expressions) { | 446 for (int i = 0; i < node.expressions.length; ++i) { |
| 423 checkAssignableExpression(item, node.typeArgument); | 447 node.expressions[i] = |
| 448 checkAndDowncastExpression(node.expressions[i], node.typeArgument); |
| 424 } | 449 } |
| 425 return environment.literalListType(node.typeArgument); | 450 return environment.literalListType(node.typeArgument); |
| 426 } | 451 } |
| 427 | 452 |
| 428 @override | 453 @override |
| 429 DartType visitLogicalExpression(LogicalExpression node) { | 454 DartType visitLogicalExpression(LogicalExpression node) { |
| 430 checkAssignableExpression(node.left, environment.boolType); | 455 node.left = checkAndDowncastExpression(node.left, environment.boolType); |
| 431 checkAssignableExpression(node.right, environment.boolType); | 456 node.right = checkAndDowncastExpression(node.right, environment.boolType); |
| 432 return environment.boolType; | 457 return environment.boolType; |
| 433 } | 458 } |
| 434 | 459 |
| 435 @override | 460 @override |
| 436 DartType visitMapLiteral(MapLiteral node) { | 461 DartType visitMapLiteral(MapLiteral node) { |
| 437 for (var entry in node.entries) { | 462 for (var entry in node.entries) { |
| 438 checkAssignableExpression(entry.key, node.keyType); | 463 entry.key = checkAndDowncastExpression(entry.key, node.keyType); |
| 439 checkAssignableExpression(entry.value, node.valueType); | 464 entry.value = checkAndDowncastExpression(entry.value, node.valueType); |
| 440 } | 465 } |
| 441 return environment.literalMapType(node.keyType, node.valueType); | 466 return environment.literalMapType(node.keyType, node.valueType); |
| 442 } | 467 } |
| 443 | 468 |
| 444 DartType handleDynamicCall(DartType receiver, Arguments arguments) { | 469 DartType handleDynamicCall(DartType receiver, Arguments arguments) { |
| 445 arguments.positional.forEach(visitExpression); | 470 arguments.positional.forEach(visitExpression); |
| 446 arguments.named.forEach((NamedExpression n) => visitExpression(n.value)); | 471 arguments.named.forEach((NamedExpression n) => visitExpression(n.value)); |
| 447 return const DynamicType(); | 472 return const DynamicType(); |
| 448 } | 473 } |
| 449 | 474 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 460 if (function.typeParameters.length != arguments.types.length) { | 485 if (function.typeParameters.length != arguments.types.length) { |
| 461 fail(access, 'Wrong number of type arguments'); | 486 fail(access, 'Wrong number of type arguments'); |
| 462 return const BottomType(); | 487 return const BottomType(); |
| 463 } | 488 } |
| 464 var instantiation = | 489 var instantiation = |
| 465 Substitution.fromPairs(function.typeParameters, arguments.types); | 490 Substitution.fromPairs(function.typeParameters, arguments.types); |
| 466 for (int i = 0; i < arguments.positional.length; ++i) { | 491 for (int i = 0; i < arguments.positional.length; ++i) { |
| 467 var expectedType = instantiation.substituteType( | 492 var expectedType = instantiation.substituteType( |
| 468 function.positionalParameters[i], | 493 function.positionalParameters[i], |
| 469 contravariant: true); | 494 contravariant: true); |
| 470 checkAssignableExpression(arguments.positional[i], expectedType); | 495 arguments.positional[i] = |
| 496 checkAndDowncastExpression(arguments.positional[i], expectedType); |
| 471 } | 497 } |
| 472 for (int i = 0; i < arguments.named.length; ++i) { | 498 for (int i = 0; i < arguments.named.length; ++i) { |
| 473 var argument = arguments.named[i]; | 499 var argument = arguments.named[i]; |
| 474 bool found = false; | 500 bool found = false; |
| 475 for (int j = 0; j < function.namedParameters.length; ++j) { | 501 for (int j = 0; j < function.namedParameters.length; ++j) { |
| 476 if (argument.name == function.namedParameters[j].name) { | 502 if (argument.name == function.namedParameters[j].name) { |
| 477 var expectedType = instantiation.substituteType( | 503 var expectedType = instantiation.substituteType( |
| 478 function.namedParameters[j].type, | 504 function.namedParameters[j].type, |
| 479 contravariant: true); | 505 contravariant: true); |
| 480 checkAssignableExpression(argument.value, expectedType); | 506 argument.value = |
| 507 checkAndDowncastExpression(argument.value, expectedType); |
| 481 found = true; | 508 found = true; |
| 482 break; | 509 break; |
| 483 } | 510 } |
| 484 } | 511 } |
| 485 if (!found) { | 512 if (!found) { |
| 486 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); | 513 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); |
| 487 return const BottomType(); | 514 return const BottomType(); |
| 488 } | 515 } |
| 489 } | 516 } |
| 490 return instantiation.substituteType(function.returnType); | 517 return instantiation.substituteType(function.returnType); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 | 694 |
| 668 @override | 695 @override |
| 669 visitBreakStatement(BreakStatement node) {} | 696 visitBreakStatement(BreakStatement node) {} |
| 670 | 697 |
| 671 @override | 698 @override |
| 672 visitContinueSwitchStatement(ContinueSwitchStatement node) {} | 699 visitContinueSwitchStatement(ContinueSwitchStatement node) {} |
| 673 | 700 |
| 674 @override | 701 @override |
| 675 visitDoStatement(DoStatement node) { | 702 visitDoStatement(DoStatement node) { |
| 676 visitStatement(node.body); | 703 visitStatement(node.body); |
| 677 checkAssignableExpression(node.condition, environment.boolType); | 704 node.condition = |
| 705 checkAndDowncastExpression(node.condition, environment.boolType); |
| 678 } | 706 } |
| 679 | 707 |
| 680 @override | 708 @override |
| 681 visitEmptyStatement(EmptyStatement node) {} | 709 visitEmptyStatement(EmptyStatement node) {} |
| 682 | 710 |
| 683 @override | 711 @override |
| 684 visitExpressionStatement(ExpressionStatement node) { | 712 visitExpressionStatement(ExpressionStatement node) { |
| 685 visitExpression(node.expression); | 713 visitExpression(node.expression); |
| 686 } | 714 } |
| 687 | 715 |
| 688 @override | 716 @override |
| 689 visitForInStatement(ForInStatement node) { | 717 visitForInStatement(ForInStatement node) { |
| 690 var iterable = visitExpression(node.iterable); | 718 var iterable = visitExpression(node.iterable); |
| 691 // TODO(asgerf): Store interface targets on for-in loops or desugar them, | 719 // TODO(asgerf): Store interface targets on for-in loops or desugar them, |
| 692 // instead of doing the ad-hoc resolution here. | 720 // instead of doing the ad-hoc resolution here. |
| 693 if (node.isAsync) { | 721 if (node.isAsync) { |
| 694 checkAssignable(node, getStreamElementType(iterable), node.variable.type); | 722 checkAssignable(node, getStreamElementType(iterable), node.variable.type); |
| 695 } else { | 723 } else { |
| 696 checkAssignable( | 724 checkAssignable( |
| 697 node, getIterableElementType(iterable), node.variable.type); | 725 node, getIterableElementType(iterable), node.variable.type); |
| 698 } | 726 } |
| 699 visitStatement(node.body); | 727 visitStatement(node.body); |
| 700 } | 728 } |
| 701 | 729 |
| 702 static final Name iteratorName = new Name('iterator'); | 730 static final Name iteratorName = new Name('iterator'); |
| 703 static final Name nextName = new Name('next'); | 731 static final Name currentName = new Name('current'); |
| 704 | 732 |
| 705 DartType getIterableElementType(DartType iterable) { | 733 DartType getIterableElementType(DartType iterable) { |
| 706 if (iterable is InterfaceType) { | 734 if (iterable is InterfaceType) { |
| 707 var iteratorGetter = | 735 var iteratorGetter = |
| 708 hierarchy.getInterfaceMember(iterable.classNode, iteratorName); | 736 hierarchy.getInterfaceMember(iterable.classNode, iteratorName); |
| 709 if (iteratorGetter == null) return const DynamicType(); | 737 if (iteratorGetter == null) return const DynamicType(); |
| 738 var castedIterable = hierarchy.getTypeAsInstanceOf( |
| 739 iterable, iteratorGetter.enclosingClass); |
| 710 var iteratorType = Substitution | 740 var iteratorType = Substitution |
| 711 .fromInterfaceType(iterable) | 741 .fromInterfaceType(castedIterable) |
| 712 .substituteType(iteratorGetter.getterType); | 742 .substituteType(iteratorGetter.getterType); |
| 713 if (iteratorType is InterfaceType) { | 743 if (iteratorType is InterfaceType) { |
| 714 var nextGetter = | 744 var currentGetter = |
| 715 hierarchy.getInterfaceMember(iteratorType.classNode, nextName); | 745 hierarchy.getInterfaceMember(iteratorType.classNode, currentName); |
| 716 if (nextGetter == null) return const DynamicType(); | 746 if (currentGetter == null) return const DynamicType(); |
| 747 var castedIteratorType = hierarchy.getTypeAsInstanceOf( |
| 748 iteratorType, currentGetter.enclosingClass); |
| 717 return Substitution | 749 return Substitution |
| 718 .fromInterfaceType(iteratorType) | 750 .fromInterfaceType(castedIteratorType) |
| 719 .substituteType(nextGetter.getterType); | 751 .substituteType(currentGetter.getterType); |
| 720 } | 752 } |
| 721 } | 753 } |
| 722 return const DynamicType(); | 754 return const DynamicType(); |
| 723 } | 755 } |
| 724 | 756 |
| 725 DartType getStreamElementType(DartType stream) { | 757 DartType getStreamElementType(DartType stream) { |
| 726 if (stream is InterfaceType) { | 758 if (stream is InterfaceType) { |
| 727 var asStream = | 759 var asStream = |
| 728 hierarchy.getTypeAsInstanceOf(stream, coreTypes.streamClass); | 760 hierarchy.getTypeAsInstanceOf(stream, coreTypes.streamClass); |
| 729 if (asStream == null) return const DynamicType(); | 761 if (asStream == null) return const DynamicType(); |
| 730 return asStream.typeArguments.single; | 762 return asStream.typeArguments.single; |
| 731 } | 763 } |
| 732 return const DynamicType(); | 764 return const DynamicType(); |
| 733 } | 765 } |
| 734 | 766 |
| 735 @override | 767 @override |
| 736 visitForStatement(ForStatement node) { | 768 visitForStatement(ForStatement node) { |
| 737 node.variables.forEach(visitVariableDeclaration); | 769 node.variables.forEach(visitVariableDeclaration); |
| 738 if (node.condition != null) { | 770 if (node.condition != null) { |
| 739 checkAssignableExpression(node.condition, environment.boolType); | 771 node.condition = |
| 772 checkAndDowncastExpression(node.condition, environment.boolType); |
| 740 } | 773 } |
| 741 node.updates.forEach(visitExpression); | 774 node.updates.forEach(visitExpression); |
| 742 visitStatement(node.body); | 775 visitStatement(node.body); |
| 743 } | 776 } |
| 744 | 777 |
| 745 @override | 778 @override |
| 746 visitFunctionDeclaration(FunctionDeclaration node) { | 779 visitFunctionDeclaration(FunctionDeclaration node) { |
| 747 handleNestedFunctionNode(node.function); | 780 handleNestedFunctionNode(node.function); |
| 748 } | 781 } |
| 749 | 782 |
| 750 @override | 783 @override |
| 751 visitIfStatement(IfStatement node) { | 784 visitIfStatement(IfStatement node) { |
| 752 checkAssignableExpression(node.condition, environment.boolType); | 785 node.condition = |
| 786 checkAndDowncastExpression(node.condition, environment.boolType); |
| 753 visitStatement(node.then); | 787 visitStatement(node.then); |
| 754 if (node.otherwise != null) { | 788 if (node.otherwise != null) { |
| 755 visitStatement(node.otherwise); | 789 visitStatement(node.otherwise); |
| 756 } | 790 } |
| 757 } | 791 } |
| 758 | 792 |
| 759 @override | 793 @override |
| 760 visitInvalidStatement(InvalidStatement node) {} | 794 visitInvalidStatement(InvalidStatement node) {} |
| 761 | 795 |
| 762 @override | 796 @override |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 | 832 |
| 799 @override | 833 @override |
| 800 visitTryFinally(TryFinally node) { | 834 visitTryFinally(TryFinally node) { |
| 801 visitStatement(node.body); | 835 visitStatement(node.body); |
| 802 visitStatement(node.finalizer); | 836 visitStatement(node.finalizer); |
| 803 } | 837 } |
| 804 | 838 |
| 805 @override | 839 @override |
| 806 visitVariableDeclaration(VariableDeclaration node) { | 840 visitVariableDeclaration(VariableDeclaration node) { |
| 807 if (node.initializer != null) { | 841 if (node.initializer != null) { |
| 808 checkAssignableExpression(node.initializer, node.type); | 842 node.initializer = |
| 843 checkAndDowncastExpression(node.initializer, node.type); |
| 809 } | 844 } |
| 810 } | 845 } |
| 811 | 846 |
| 812 @override | 847 @override |
| 813 visitWhileStatement(WhileStatement node) { | 848 visitWhileStatement(WhileStatement node) { |
| 814 checkAssignableExpression(node.condition, environment.boolType); | 849 node.condition = |
| 850 checkAndDowncastExpression(node.condition, environment.boolType); |
| 815 visitStatement(node.body); | 851 visitStatement(node.body); |
| 816 } | 852 } |
| 817 | 853 |
| 818 @override | 854 @override |
| 819 visitYieldStatement(YieldStatement node) { | 855 visitYieldStatement(YieldStatement node) { |
| 820 if (node.isYieldStar) { | 856 if (node.isYieldStar) { |
| 821 Class container = environment.currentAsyncMarker == AsyncMarker.AsyncStar | 857 Class container = environment.currentAsyncMarker == AsyncMarker.AsyncStar |
| 822 ? coreTypes.streamClass | 858 ? coreTypes.streamClass |
| 823 : coreTypes.iterableClass; | 859 : coreTypes.iterableClass; |
| 824 var type = visitExpression(node.expression); | 860 var type = visitExpression(node.expression); |
| 825 var asContainer = type is InterfaceType | 861 var asContainer = type is InterfaceType |
| 826 ? hierarchy.getTypeAsInstanceOf(type, container) | 862 ? hierarchy.getTypeAsInstanceOf(type, container) |
| 827 : null; | 863 : null; |
| 828 if (asContainer != null) { | 864 if (asContainer != null) { |
| 829 checkAssignable(node.expression, asContainer.typeArguments[0], | 865 checkAssignable(node.expression, asContainer.typeArguments[0], |
| 830 environment.yieldType); | 866 environment.yieldType); |
| 831 } else { | 867 } else { |
| 832 fail(node.expression, '$type is not an instance of $container'); | 868 fail(node.expression, '$type is not an instance of $container'); |
| 833 } | 869 } |
| 834 } else { | 870 } else { |
| 835 checkAssignableExpression(node.expression, environment.yieldType); | 871 node.expression = |
| 872 checkAndDowncastExpression(node.expression, environment.yieldType); |
| 836 } | 873 } |
| 837 } | 874 } |
| 838 | 875 |
| 839 @override | 876 @override |
| 840 visitFieldInitializer(FieldInitializer node) { | 877 visitFieldInitializer(FieldInitializer node) { |
| 841 checkAssignableExpression(node.value, node.field.type); | 878 node.value = checkAndDowncastExpression(node.value, node.field.type); |
| 842 } | 879 } |
| 843 | 880 |
| 844 @override | 881 @override |
| 845 visitRedirectingInitializer(RedirectingInitializer node) { | 882 visitRedirectingInitializer(RedirectingInitializer node) { |
| 846 handleCall(node.arguments, node.target.function, | 883 handleCall(node.arguments, node.target.function, |
| 847 typeParameters: const <TypeParameter>[]); | 884 typeParameters: const <TypeParameter>[]); |
| 848 } | 885 } |
| 849 | 886 |
| 850 @override | 887 @override |
| 851 visitSuperInitializer(SuperInitializer node) { | 888 visitSuperInitializer(SuperInitializer node) { |
| 852 handleCall(node.arguments, node.target.function, | 889 handleCall(node.arguments, node.target.function, |
| 853 typeParameters: const <TypeParameter>[]); | 890 typeParameters: const <TypeParameter>[], |
| 891 receiver: getSuperReceiverType(node.target)); |
| 854 } | 892 } |
| 855 | 893 |
| 856 @override | 894 @override |
| 857 visitLocalInitializer(LocalInitializer node) { | 895 visitLocalInitializer(LocalInitializer node) { |
| 858 visitVariableDeclaration(node.variable); | 896 visitVariableDeclaration(node.variable); |
| 859 } | 897 } |
| 860 | 898 |
| 861 @override | 899 @override |
| 862 visitInvalidInitializer(InvalidInitializer node) {} | 900 visitInvalidInitializer(InvalidInitializer node) {} |
| 863 } | 901 } |
| OLD | NEW |