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 |