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

Side by Side Diff: lib/type_checker.dart

Issue 2465893002: Add strong mode type checking pass. (Closed)
Patch Set: Update test expectations Created 4 years, 1 month 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4 library kernel.type_checker;
5
6 import 'ast.dart';
7 import 'class_hierarchy.dart';
8 import 'core_types.dart';
9 import 'type_algebra.dart';
10 import 'type_environment.dart';
11
12 /// Performs strong-mode type checking on the kernel IR.
13 ///
14 /// A concrete subclass of [TypeChecker] must implement [checkAssignable] and
15 /// [fail] in order to deal with subtyping requirements and error handling.
16 abstract class TypeChecker {
17 final CoreTypes coreTypes;
18 final ClassHierarchy hierarchy;
19 TypeEnvironment environment;
20
21 TypeChecker(this.coreTypes, this.hierarchy) {
22 environment = new TypeEnvironment(coreTypes, hierarchy);
23 }
24
25 void checkProgram(Program program) {
26 for (var library in program.libraries) {
27 if (library.importUri.scheme == 'dart') continue;
28 for (var class_ in library.classes) {
29 hierarchy.forEachOverridePair(class_,
30 (Member ownMember, Member superMember, bool isSetter) {
31 checkOverride(class_, ownMember, superMember, isSetter);
32 });
33 }
34 }
35 var visitor = new TypeCheckingVisitor(this, environment);
36 for (var library in program.libraries) {
37 if (library.importUri.scheme == 'dart') continue;
38 for (var class_ in library.classes) {
39 environment.thisType = class_.thisType;
40 for (var field in class_.fields) {
41 visitor.visitField(field);
42 }
43 for (var constructor in class_.constructors) {
44 visitor.visitConstructor(constructor);
45 }
46 for (var procedure in class_.procedures) {
47 visitor.visitProcedure(procedure);
48 }
49 }
50 environment.thisType = null;
51 for (var procedure in library.procedures) {
52 visitor.visitProcedure(procedure);
53 }
54 for (var field in library.fields) {
55 visitor.visitField(field);
56 }
57 }
58 }
59
60 DartType getterType(Class host, Member member) {
61 var hostType = hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
62 var substitution = Substitution.fromSupertype(hostType);
63 return substitution.substituteType(member.getterType);
64 }
65
66 DartType setterType(Class host, Member member) {
67 var hostType = hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
68 var substitution = Substitution.fromSupertype(hostType);
69 return substitution.substituteType(member.setterType, contravariant: true);
70 }
71
72 void checkOverride(
73 Class host, Member ownMember, Member superMember, bool isSetter) {
74 if (isSetter) {
75 checkAssignable(ownMember, setterType(host, superMember),
76 setterType(host, ownMember));
77 } else {
78 checkAssignable(ownMember, getterType(host, ownMember),
79 getterType(host, superMember));
80 }
81 }
82
83 /// Check that [from] is a subtype of [to].
84 ///
85 /// [where] is an AST node indicating roughly where the check is required.
86 void checkAssignable(TreeNode where, DartType from, DartType to);
87
88 /// Indicates that type checking failed.
89 void fail(TreeNode where, String message);
90 }
91
92 class TypeCheckingVisitor
93 implements
94 ExpressionVisitor<DartType>,
95 StatementVisitor<Null>,
96 MemberVisitor<Null>,
97 InitializerVisitor<Null> {
98 final TypeChecker checker;
99 final TypeEnvironment environment;
100
101 CoreTypes get coreTypes => environment.coreTypes;
102 ClassHierarchy get hierarchy => environment.hierarchy;
103 Class get currentClass => environment.thisType.classNode;
104
105 TypeCheckingVisitor(this.checker, this.environment);
106
107 void checkAssignable(TreeNode where, DartType from, DartType to) {
108 checker.checkAssignable(where, from, to);
109 }
110
111 void checkAssignableExpression(Expression from, DartType to) {
112 checker.checkAssignable(from, visitExpression(from), to);
113 }
114
115 void fail(TreeNode node, String message) {
116 checker.fail(node, message);
117 }
118
119 DartType visitExpression(Expression node) => node.accept(this);
120
121 void visitStatement(Statement node) {
122 node.accept(this);
123 }
124
125 void visitInitializer(Initializer node) {
126 node.accept(this);
127 }
128
129 defaultMember(Member node) => throw 'Unused';
130
131 DartType defaultBasicLiteral(BasicLiteral node) {
132 return defaultExpression(node);
133 }
134
135 DartType defaultExpression(Expression node) {
136 throw 'Unexpected expression ${node.runtimeType}';
137 }
138
139 defaultStatement(Statement node) {
140 throw 'Unexpected statement ${node.runtimeType}';
141 }
142
143 defaultInitializer(Initializer node) {
144 throw 'Unexpected initializer ${node.runtimeType}';
145 }
146
147 visitField(Field node) {
148 if (node.initializer != null) {
149 checkAssignableExpression(node.initializer, node.type);
150 }
151 }
152
153 visitConstructor(Constructor node) {
154 environment.returnType = null;
155 environment.yieldType = null;
156 node.initializers.forEach(visitInitializer);
157 handleFunctionNode(node.function);
158 }
159
160 visitProcedure(Procedure node) {
161 environment.returnType = node.function.returnType;
162 environment.yieldType = _getYieldType(node.function);
163 handleFunctionNode(node.function);
164 }
165
166 void handleFunctionNode(FunctionNode node) {
167 node.positionalParameters
168 .skip(node.requiredParameterCount)
169 .forEach(handleOptionalParameter);
170 node.namedParameters.forEach(handleOptionalParameter);
171 if (node.body != null) {
172 visitStatement(node.body);
173 }
174 }
175
176 void handleNestedFunctionNode(FunctionNode node) {
177 var oldReturn = environment.returnType;
178 var oldYield = environment.yieldType;
179 environment.returnType = node.returnType;
180 environment.yieldType = _getYieldType(node);
181 handleFunctionNode(node);
182 environment.returnType = oldReturn;
183 environment.yieldType = oldYield;
184 }
185
186 void handleOptionalParameter(VariableDeclaration parameter) {
187 if (parameter.initializer != null) {
188 checkAssignableExpression(parameter.initializer, parameter.type);
189 }
190 }
191
192 Substitution getReceiverType(
193 TreeNode access, Expression receiver, Member member) {
194 var type = visitExpression(receiver);
195 Class superclass = member.enclosingClass;
196 if (superclass.supertype == null) {
197 return Substitution.empty; // Members on Object are always accessible.
198 }
199 while (type is TypeParameterType) {
200 type = (type as TypeParameterType).parameter.bound;
201 }
202 if (type is BottomType) {
203 // The bottom type is a subtype of all types, so it should be allowed.
204 return Substitution.bottomForClass(superclass);
205 }
206 if (type is InterfaceType) {
207 // The receiver type should implement the interface declaring the member.
208 var upcastType = hierarchy.getTypeAsInstanceOf(type, superclass);
209 if (upcastType != null) {
210 return Substitution.fromInterfaceType(upcastType);
211 }
212 }
213 if (type is FunctionType && superclass == coreTypes.functionClass) {
214 assert(type.typeParameters.isEmpty);
215 return Substitution.empty;
216 }
217 // Note that we do not allow 'dynamic' here. Dynamic calls should not
218 // have a declared interface target.
219 fail(access, '$member is not accessible on a receiver of type $type');
220 return Substitution.bottomForClass(superclass); // Continue type checking.
221 }
222
223 Substitution getSuperReceiverType(Member member) {
224 return Substitution.fromSupertype(
225 hierarchy.getClassAsInstanceOf(currentClass, member.enclosingClass));
226 }
227
228 DartType handleCall(Arguments arguments, FunctionNode function,
229 {Substitution receiver: Substitution.empty,
230 List<TypeParameter> typeParameters}) {
231 typeParameters ??= function.typeParameters;
232 if (arguments.positional.length < function.requiredParameterCount) {
233 fail(arguments, 'Too few positional arguments');
234 return const BottomType();
235 }
236 if (arguments.positional.length > function.positionalParameters.length) {
237 fail(arguments, 'Too many positional arguments');
238 return const BottomType();
239 }
240 if (arguments.types.length != typeParameters.length) {
241 fail(arguments, 'Wrong number of type arguments');
242 return const BottomType();
243 }
244 var instantiation = Substitution.fromPairs(typeParameters, arguments.types);
245 var substitution = Substitution.combine(receiver, instantiation);
246 for (int i = 0; i < typeParameters.length; ++i) {
247 var argument = arguments.types[i];
248 var bound = substitution.substituteType(typeParameters[i].bound);
249 checkAssignable(arguments, argument, bound);
250 }
251 for (int i = 0; i < arguments.positional.length; ++i) {
252 var expectedType = substitution.substituteType(
253 function.positionalParameters[i].type,
254 contravariant: true);
255 checkAssignableExpression(arguments.positional[i], expectedType);
256 }
257 for (int i = 0; i < arguments.named.length; ++i) {
258 var argument = arguments.named[i];
259 bool found = false;
260 for (int j = 0; j < function.namedParameters.length; ++j) {
261 if (argument.name == function.namedParameters[j].name) {
262 var expectedType = substitution.substituteType(
263 function.namedParameters[j].type,
264 contravariant: true);
265 checkAssignableExpression(argument.value, expectedType);
266 found = true;
267 break;
268 }
269 }
270 if (!found) {
271 fail(argument.value, 'Unexpected named parameter: ${argument.name}');
272 return const BottomType();
273 }
274 }
275 return substitution.substituteType(function.returnType);
276 }
277
278 DartType _getYieldType(FunctionNode function) {
279 switch (function.asyncMarker) {
280 case AsyncMarker.Sync:
281 case AsyncMarker.Async:
282 return null;
283
284 case AsyncMarker.SyncStar:
285 case AsyncMarker.AsyncStar:
286 Class container = function.asyncMarker == AsyncMarker.SyncStar
287 ? coreTypes.iterableClass
288 : coreTypes.streamClass;
289 DartType returnType = function.returnType;
290 if (returnType is InterfaceType && returnType.classNode == container) {
291 return returnType.typeArguments.single;
292 }
293 return const DynamicType();
294
295 case AsyncMarker.SyncYielding:
296 return function.returnType;
297
298 default:
299 throw 'Unexpected async marker: ${function.asyncMarker}';
300 }
301 }
302
303 @override
304 DartType visitAsExpression(AsExpression node) {
305 visitExpression(node.operand);
306 return node.type;
307 }
308
309 @override
310 DartType visitAwaitExpression(AwaitExpression node) {
311 return environment.unfutureType(visitExpression(node.operand));
312 }
313
314 @override
315 DartType visitBlockExpression(BlockExpression node) {
316 visitStatement(node.body);
317 return visitExpression(node.value);
318 }
319
320 @override
321 DartType visitBoolLiteral(BoolLiteral node) {
322 return environment.boolType;
323 }
324
325 @override
326 DartType visitConditionalExpression(ConditionalExpression node) {
327 checkAssignableExpression(node.condition, environment.boolType);
328 if (node.staticType == null) {
329 var thenType = visitExpression(node.then);
330 var otherwiseType = visitExpression(node.otherwise);
331 if (thenType is BottomType) return otherwiseType;
332 if (otherwiseType is BottomType) return thenType;
333 return const DynamicType();
334 } else {
335 checkAssignableExpression(node.then, node.staticType);
336 checkAssignableExpression(node.otherwise, node.staticType);
337 return node.staticType;
338 }
339 }
340
341 @override
342 DartType visitConstructorInvocation(ConstructorInvocation node) {
343 Constructor target = node.target;
344 Arguments arguments = node.arguments;
345 Class class_ = target.enclosingClass;
346 handleCall(arguments, target.function,
347 typeParameters: class_.typeParameters);
348 return new InterfaceType(target.enclosingClass, arguments.types);
349 }
350
351 @override
352 DartType visitDirectMethodInvocation(DirectMethodInvocation node) {
353 return handleCall(node.arguments, node.target.function,
354 receiver: getReceiverType(node, node.receiver, node.target));
355 }
356
357 @override
358 DartType visitDirectPropertyGet(DirectPropertyGet node) {
359 var receiver = getReceiverType(node, node.receiver, node.target);
360 return receiver.substituteType(node.target.getterType);
361 }
362
363 @override
364 DartType visitDirectPropertySet(DirectPropertySet node) {
365 var receiver = getReceiverType(node, node.receiver, node.target);
366 var value = visitExpression(node.value);
367 checkAssignable(node, value,
368 receiver.substituteType(node.target.setterType, contravariant: true));
369 return value;
370 }
371
372 @override
373 DartType visitDoubleLiteral(DoubleLiteral node) {
374 return environment.doubleType;
375 }
376
377 @override
378 DartType visitFunctionExpression(FunctionExpression node) {
379 handleNestedFunctionNode(node.function);
380 return node.function.functionType;
381 }
382
383 @override
384 DartType visitIntLiteral(IntLiteral node) {
385 return environment.intType;
386 }
387
388 @override
389 DartType visitInvalidExpression(InvalidExpression node) {
390 return const BottomType();
391 }
392
393 @override
394 DartType visitIsExpression(IsExpression node) {
395 visitExpression(node.operand);
396 return environment.boolType;
397 }
398
399 @override
400 DartType visitLet(Let node) {
401 var value = visitExpression(node.variable.initializer);
402 if (node.variable.type is DynamicType) {
403 node.variable.type = value;
404 }
405 return visitExpression(node.body);
406 }
407
408 @override
409 DartType visitListLiteral(ListLiteral node) {
410 for (var item in node.expressions) {
411 checkAssignableExpression(item, node.typeArgument);
412 }
413 return environment.literalListType(node.typeArgument);
414 }
415
416 @override
417 DartType visitLogicalExpression(LogicalExpression node) {
418 checkAssignableExpression(node.left, environment.boolType);
419 checkAssignableExpression(node.right, environment.boolType);
420 return environment.boolType;
421 }
422
423 @override
424 DartType visitMapLiteral(MapLiteral node) {
425 for (var entry in node.entries) {
426 checkAssignableExpression(entry.key, node.keyType);
427 checkAssignableExpression(entry.value, node.valueType);
428 }
429 return environment.literalMapType(node.keyType, node.valueType);
430 }
431
432 DartType handleDynamicCall(DartType receiver, Arguments arguments) {
433 arguments.positional.forEach(visitExpression);
434 arguments.named.forEach((NamedExpression n) => visitExpression(n.value));
435 return const DynamicType();
436 }
437
438 DartType handleFunctionCall(
439 TreeNode access, FunctionType function, Arguments arguments) {
440 if (function.requiredParameterCount > arguments.positional.length) {
441 fail(access, 'Too few positional arguments');
442 return const BottomType();
443 }
444 if (function.positionalParameters.length < arguments.positional.length) {
445 fail(access, 'Too many positional arguments');
446 return const BottomType();
447 }
448 if (function.typeParameters.length != arguments.types.length) {
449 fail(access, 'Wrong number of type arguments');
450 return const BottomType();
451 }
452 var instantiation =
453 Substitution.fromPairs(function.typeParameters, arguments.types);
454 for (int i = 0; i < arguments.positional.length; ++i) {
455 var expectedType = instantiation.substituteType(
456 function.positionalParameters[i],
457 contravariant: true);
458 checkAssignableExpression(arguments.positional[i], expectedType);
459 }
460 for (int i = 0; i < arguments.named.length; ++i) {
461 var argument = arguments.named[i];
462 var expectedType = function.namedParameters[argument.name];
463 if (expectedType == null) {
464 fail(argument.value, 'Unexpected named parameter: ${argument.name}');
465 } else {
466 checkAssignableExpression(argument.value,
467 instantiation.substituteType(expectedType, contravariant: true));
468 }
469 }
470 return instantiation.substituteType(function.returnType);
471 }
472
473 @override
474 DartType visitMethodInvocation(MethodInvocation node) {
475 var target = node.interfaceTarget;
476 if (target == null) {
477 var receiver = visitExpression(node.receiver);
478 return (node.name.name == 'call' && receiver is FunctionType)
479 ? handleFunctionCall(node, receiver, node.arguments)
480 : handleDynamicCall(receiver, node.arguments);
481 } else if (environment.isOverloadedArithmeticOperator(target)) {
482 assert(node.arguments.positional.length == 1);
483 var receiver = visitExpression(node.receiver);
484 var argument = visitExpression(node.arguments.positional[0]);
485 return environment.getTypeOfOverloadedArithmetic(receiver, argument);
486 } else {
487 return handleCall(node.arguments, target.function,
488 receiver: getReceiverType(node, node.receiver, node.interfaceTarget));
489 }
490 }
491
492 @override
493 DartType visitPropertyGet(PropertyGet node) {
494 if (node.interfaceTarget == null) {
495 visitExpression(node.receiver);
496 return const DynamicType();
497 } else {
498 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
499 return receiver.substituteType(node.interfaceTarget.getterType);
500 }
501 }
502
503 @override
504 DartType visitPropertySet(PropertySet node) {
505 var value = visitExpression(node.value);
506 if (node.interfaceTarget != null) {
507 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
508 checkAssignable(
509 node.value,
510 value,
511 receiver.substituteType(node.interfaceTarget.setterType,
512 contravariant: true));
513 } else {
514 visitExpression(node.receiver);
515 }
516 return value;
517 }
518
519 @override
520 DartType visitNot(Not node) {
521 visitExpression(node.operand);
522 return environment.boolType;
523 }
524
525 @override
526 DartType visitNullLiteral(NullLiteral node) {
527 return const BottomType();
528 }
529
530 @override
531 DartType visitRethrow(Rethrow node) {
532 return const BottomType();
533 }
534
535 @override
536 DartType visitStaticGet(StaticGet node) {
537 return node.target.getterType;
538 }
539
540 @override
541 DartType visitStaticInvocation(StaticInvocation node) {
542 return handleCall(node.arguments, node.target.function);
543 }
544
545 @override
546 DartType visitStaticSet(StaticSet node) {
547 var value = visitExpression(node.value);
548 checkAssignable(node.value, value, node.target.setterType);
549 return value;
550 }
551
552 @override
553 DartType visitStringConcatenation(StringConcatenation node) {
554 node.expressions.forEach(visitExpression);
555 return environment.stringType;
556 }
557
558 @override
559 DartType visitStringLiteral(StringLiteral node) {
560 return environment.stringType;
561 }
562
563 @override
564 DartType visitSuperMethodInvocation(SuperMethodInvocation node) {
565 if (node.interfaceTarget == null) {
566 return handleDynamicCall(environment.thisType, node.arguments);
567 } else {
568 return handleCall(node.arguments, node.interfaceTarget.function,
569 receiver: getSuperReceiverType(node.interfaceTarget));
570 }
571 }
572
573 @override
574 DartType visitSuperPropertyGet(SuperPropertyGet node) {
575 if (node.interfaceTarget == null) {
576 return const DynamicType();
577 } else {
578 var receiver = getSuperReceiverType(node.interfaceTarget);
579 return receiver.substituteType(node.interfaceTarget.getterType);
580 }
581 }
582
583 @override
584 DartType visitSuperPropertySet(SuperPropertySet node) {
585 var value = visitExpression(node.value);
586 if (node.interfaceTarget != null) {
587 var receiver = getSuperReceiverType(node.interfaceTarget);
588 checkAssignable(
589 node.value,
590 value,
591 receiver.substituteType(node.interfaceTarget.setterType,
592 contravariant: true));
593 }
594 return value;
595 }
596
597 @override
598 DartType visitSymbolLiteral(SymbolLiteral node) {
599 return environment.symbolType;
600 }
601
602 @override
603 DartType visitThisExpression(ThisExpression node) {
604 return environment.thisType;
605 }
606
607 @override
608 DartType visitThrow(Throw node) {
609 visitExpression(node.expression);
610 return const BottomType();
611 }
612
613 @override
614 DartType visitTypeLiteral(TypeLiteral node) {
615 return environment.typeType;
616 }
617
618 @override
619 DartType visitVariableGet(VariableGet node) {
620 return node.promotedType ?? node.variable.type;
621 }
622
623 @override
624 DartType visitVariableSet(VariableSet node) {
625 var value = visitExpression(node.value);
626 checkAssignable(node.value, value, node.variable.type);
627 return value;
628 }
629
630 @override
631 visitAssertStatement(AssertStatement node) {
632 visitExpression(node.condition);
633 if (node.message != null) {
634 visitExpression(node.message);
635 }
636 }
637
638 @override
639 visitBlock(Block node) {
640 node.statements.forEach(visitStatement);
641 }
642
643 @override
644 visitBreakStatement(BreakStatement node) {}
645
646 @override
647 visitContinueSwitchStatement(ContinueSwitchStatement node) {}
648
649 @override
650 visitDoStatement(DoStatement node) {
651 visitStatement(node.body);
652 checkAssignableExpression(node.condition, environment.boolType);
653 }
654
655 @override
656 visitEmptyStatement(EmptyStatement node) {}
657
658 @override
659 visitExpressionStatement(ExpressionStatement node) {
660 visitExpression(node.expression);
661 }
662
663 @override
664 visitForInStatement(ForInStatement node) {
665 var iterable = visitExpression(node.iterable);
666 // TODO(asgerf): Store interface targets on for-in loops or desugar them,
667 // instead of doing the ad-hoc resolution here.
668 if (node.isAsync) {
669 checkAssignable(node, getStreamElementType(iterable), node.variable.type);
670 } else {
671 checkAssignable(
672 node, getIterableElementType(iterable), node.variable.type);
673 }
674 visitStatement(node.body);
675 }
676
677 static final Name iteratorName = new Name('iterator');
678 static final Name nextName = new Name('next');
679
680 DartType getIterableElementType(DartType iterable) {
681 if (iterable is InterfaceType) {
682 var iteratorGetter =
683 hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
684 if (iteratorGetter == null) return const DynamicType();
685 var iteratorType = Substitution
686 .fromInterfaceType(iterable)
687 .substituteType(iteratorGetter.getterType);
688 if (iteratorType is InterfaceType) {
689 var nextGetter =
690 hierarchy.getInterfaceMember(iteratorType.classNode, nextName);
691 if (nextGetter == null) return const DynamicType();
692 return Substitution
693 .fromInterfaceType(iteratorType)
694 .substituteType(nextGetter.getterType);
695 }
696 }
697 return const DynamicType();
698 }
699
700 DartType getStreamElementType(DartType stream) {
701 if (stream is InterfaceType) {
702 var asStream =
703 hierarchy.getTypeAsInstanceOf(stream, coreTypes.streamClass);
704 if (asStream == null) return const DynamicType();
705 return asStream.typeArguments.single;
706 }
707 return const DynamicType();
708 }
709
710 @override
711 visitForStatement(ForStatement node) {
712 node.variables.forEach(visitVariableDeclaration);
713 if (node.condition != null) {
714 checkAssignableExpression(node.condition, environment.boolType);
715 }
716 node.updates.forEach(visitExpression);
717 visitStatement(node.body);
718 }
719
720 @override
721 visitFunctionDeclaration(FunctionDeclaration node) {
722 handleNestedFunctionNode(node.function);
723 }
724
725 @override
726 visitIfStatement(IfStatement node) {
727 checkAssignableExpression(node.condition, environment.boolType);
728 visitStatement(node.then);
729 if (node.otherwise != null) {
730 visitStatement(node.otherwise);
731 }
732 }
733
734 @override
735 visitInvalidStatement(InvalidStatement node) {}
736
737 @override
738 visitLabeledStatement(LabeledStatement node) {
739 visitStatement(node.body);
740 }
741
742 @override
743 visitReturnStatement(ReturnStatement node) {
744 if (node.expression != null) {
745 if (environment.returnType == null) {
746 fail(node, 'Return of a value from void method');
747 } else {
748 checkAssignableExpression(node.expression, environment.returnType);
749 }
750 }
751 }
752
753 @override
754 visitSwitchStatement(SwitchStatement node) {
755 visitExpression(node.expression);
756 for (var switchCase in node.cases) {
757 switchCase.expressions.forEach(visitExpression);
758 visitStatement(switchCase.body);
759 }
760 }
761
762 @override
763 visitTryCatch(TryCatch node) {
764 visitStatement(node.body);
765 for (var catchClause in node.catches) {
766 visitStatement(catchClause.body);
767 }
768 }
769
770 @override
771 visitTryFinally(TryFinally node) {
772 visitStatement(node.body);
773 visitStatement(node.finalizer);
774 }
775
776 @override
777 visitVariableDeclaration(VariableDeclaration node) {
778 if (node.initializer != null) {
779 checkAssignableExpression(node.initializer, node.type);
780 }
781 }
782
783 @override
784 visitWhileStatement(WhileStatement node) {
785 checkAssignableExpression(node.condition, environment.boolType);
786 visitStatement(node.body);
787 }
788
789 @override
790 visitYieldStatement(YieldStatement node) {
791 checkAssignableExpression(node.expression, environment.yieldType);
792 }
793
794 @override
795 visitFieldInitializer(FieldInitializer node) {
796 checkAssignableExpression(node.value, node.field.type);
797 }
798
799 @override
800 visitRedirectingInitializer(RedirectingInitializer node) {
801 handleCall(node.arguments, node.target.function,
802 typeParameters: const <TypeParameter>[]);
803 }
804
805 @override
806 visitSuperInitializer(SuperInitializer node) {
807 handleCall(node.arguments, node.target.function,
808 typeParameters: const <TypeParameter>[]);
809 }
810
811 @override
812 visitLocalInitializer(LocalInitializer node) {
813 visitVariableDeclaration(node.variable);
814 }
815
816 @override
817 visitInvalidInitializer(InvalidInitializer node) {}
818 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698