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

Side by Side Diff: lib/type_checker.dart

Issue 2465893002: Add strong mode type checking pass. (Closed)
Patch Set: Merge with master and remove visitBlockExpression 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
« no previous file with comments | « lib/type_algebra.dart ('k') | lib/type_environment.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 visitBoolLiteral(BoolLiteral node) {
316 return environment.boolType;
317 }
318
319 @override
320 DartType visitConditionalExpression(ConditionalExpression node) {
321 checkAssignableExpression(node.condition, environment.boolType);
322 if (node.staticType == null) {
323 var thenType = visitExpression(node.then);
324 var otherwiseType = visitExpression(node.otherwise);
325 if (thenType is BottomType) return otherwiseType;
326 if (otherwiseType is BottomType) return thenType;
327 return const DynamicType();
328 } else {
329 checkAssignableExpression(node.then, node.staticType);
330 checkAssignableExpression(node.otherwise, node.staticType);
331 return node.staticType;
332 }
333 }
334
335 @override
336 DartType visitConstructorInvocation(ConstructorInvocation node) {
337 Constructor target = node.target;
338 Arguments arguments = node.arguments;
339 Class class_ = target.enclosingClass;
340 handleCall(arguments, target.function,
341 typeParameters: class_.typeParameters);
342 return new InterfaceType(target.enclosingClass, arguments.types);
343 }
344
345 @override
346 DartType visitDirectMethodInvocation(DirectMethodInvocation node) {
347 return handleCall(node.arguments, node.target.function,
348 receiver: getReceiverType(node, node.receiver, node.target));
349 }
350
351 @override
352 DartType visitDirectPropertyGet(DirectPropertyGet node) {
353 var receiver = getReceiverType(node, node.receiver, node.target);
354 return receiver.substituteType(node.target.getterType);
355 }
356
357 @override
358 DartType visitDirectPropertySet(DirectPropertySet node) {
359 var receiver = getReceiverType(node, node.receiver, node.target);
360 var value = visitExpression(node.value);
361 checkAssignable(node, value,
362 receiver.substituteType(node.target.setterType, contravariant: true));
363 return value;
364 }
365
366 @override
367 DartType visitDoubleLiteral(DoubleLiteral node) {
368 return environment.doubleType;
369 }
370
371 @override
372 DartType visitFunctionExpression(FunctionExpression node) {
373 handleNestedFunctionNode(node.function);
374 return node.function.functionType;
375 }
376
377 @override
378 DartType visitIntLiteral(IntLiteral node) {
379 return environment.intType;
380 }
381
382 @override
383 DartType visitInvalidExpression(InvalidExpression node) {
384 return const BottomType();
385 }
386
387 @override
388 DartType visitIsExpression(IsExpression node) {
389 visitExpression(node.operand);
390 return environment.boolType;
391 }
392
393 @override
394 DartType visitLet(Let node) {
395 var value = visitExpression(node.variable.initializer);
396 if (node.variable.type is DynamicType) {
397 node.variable.type = value;
398 }
399 return visitExpression(node.body);
400 }
401
402 @override
403 DartType visitListLiteral(ListLiteral node) {
404 for (var item in node.expressions) {
405 checkAssignableExpression(item, node.typeArgument);
406 }
407 return environment.literalListType(node.typeArgument);
408 }
409
410 @override
411 DartType visitLogicalExpression(LogicalExpression node) {
412 checkAssignableExpression(node.left, environment.boolType);
413 checkAssignableExpression(node.right, environment.boolType);
414 return environment.boolType;
415 }
416
417 @override
418 DartType visitMapLiteral(MapLiteral node) {
419 for (var entry in node.entries) {
420 checkAssignableExpression(entry.key, node.keyType);
421 checkAssignableExpression(entry.value, node.valueType);
422 }
423 return environment.literalMapType(node.keyType, node.valueType);
424 }
425
426 DartType handleDynamicCall(DartType receiver, Arguments arguments) {
427 arguments.positional.forEach(visitExpression);
428 arguments.named.forEach((NamedExpression n) => visitExpression(n.value));
429 return const DynamicType();
430 }
431
432 DartType handleFunctionCall(
433 TreeNode access, FunctionType function, Arguments arguments) {
434 if (function.requiredParameterCount > arguments.positional.length) {
435 fail(access, 'Too few positional arguments');
436 return const BottomType();
437 }
438 if (function.positionalParameters.length < arguments.positional.length) {
439 fail(access, 'Too many positional arguments');
440 return const BottomType();
441 }
442 if (function.typeParameters.length != arguments.types.length) {
443 fail(access, 'Wrong number of type arguments');
444 return const BottomType();
445 }
446 var instantiation =
447 Substitution.fromPairs(function.typeParameters, arguments.types);
448 for (int i = 0; i < arguments.positional.length; ++i) {
449 var expectedType = instantiation.substituteType(
450 function.positionalParameters[i],
451 contravariant: true);
452 checkAssignableExpression(arguments.positional[i], expectedType);
453 }
454 for (int i = 0; i < arguments.named.length; ++i) {
455 var argument = arguments.named[i];
456 var expectedType = function.namedParameters[argument.name];
457 if (expectedType == null) {
458 fail(argument.value, 'Unexpected named parameter: ${argument.name}');
459 } else {
460 checkAssignableExpression(argument.value,
461 instantiation.substituteType(expectedType, contravariant: true));
462 }
463 }
464 return instantiation.substituteType(function.returnType);
465 }
466
467 @override
468 DartType visitMethodInvocation(MethodInvocation node) {
469 var target = node.interfaceTarget;
470 if (target == null) {
471 var receiver = visitExpression(node.receiver);
472 return (node.name.name == 'call' && receiver is FunctionType)
473 ? handleFunctionCall(node, receiver, node.arguments)
474 : handleDynamicCall(receiver, node.arguments);
475 } else if (environment.isOverloadedArithmeticOperator(target)) {
476 assert(node.arguments.positional.length == 1);
477 var receiver = visitExpression(node.receiver);
478 var argument = visitExpression(node.arguments.positional[0]);
479 return environment.getTypeOfOverloadedArithmetic(receiver, argument);
480 } else {
481 return handleCall(node.arguments, target.function,
482 receiver: getReceiverType(node, node.receiver, node.interfaceTarget));
483 }
484 }
485
486 @override
487 DartType visitPropertyGet(PropertyGet node) {
488 if (node.interfaceTarget == null) {
489 visitExpression(node.receiver);
490 return const DynamicType();
491 } else {
492 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
493 return receiver.substituteType(node.interfaceTarget.getterType);
494 }
495 }
496
497 @override
498 DartType visitPropertySet(PropertySet node) {
499 var value = visitExpression(node.value);
500 if (node.interfaceTarget != null) {
501 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
502 checkAssignable(
503 node.value,
504 value,
505 receiver.substituteType(node.interfaceTarget.setterType,
506 contravariant: true));
507 } else {
508 visitExpression(node.receiver);
509 }
510 return value;
511 }
512
513 @override
514 DartType visitNot(Not node) {
515 visitExpression(node.operand);
516 return environment.boolType;
517 }
518
519 @override
520 DartType visitNullLiteral(NullLiteral node) {
521 return const BottomType();
522 }
523
524 @override
525 DartType visitRethrow(Rethrow node) {
526 return const BottomType();
527 }
528
529 @override
530 DartType visitStaticGet(StaticGet node) {
531 return node.target.getterType;
532 }
533
534 @override
535 DartType visitStaticInvocation(StaticInvocation node) {
536 return handleCall(node.arguments, node.target.function);
537 }
538
539 @override
540 DartType visitStaticSet(StaticSet node) {
541 var value = visitExpression(node.value);
542 checkAssignable(node.value, value, node.target.setterType);
543 return value;
544 }
545
546 @override
547 DartType visitStringConcatenation(StringConcatenation node) {
548 node.expressions.forEach(visitExpression);
549 return environment.stringType;
550 }
551
552 @override
553 DartType visitStringLiteral(StringLiteral node) {
554 return environment.stringType;
555 }
556
557 @override
558 DartType visitSuperMethodInvocation(SuperMethodInvocation node) {
559 if (node.interfaceTarget == null) {
560 return handleDynamicCall(environment.thisType, node.arguments);
561 } else {
562 return handleCall(node.arguments, node.interfaceTarget.function,
563 receiver: getSuperReceiverType(node.interfaceTarget));
564 }
565 }
566
567 @override
568 DartType visitSuperPropertyGet(SuperPropertyGet node) {
569 if (node.interfaceTarget == null) {
570 return const DynamicType();
571 } else {
572 var receiver = getSuperReceiverType(node.interfaceTarget);
573 return receiver.substituteType(node.interfaceTarget.getterType);
574 }
575 }
576
577 @override
578 DartType visitSuperPropertySet(SuperPropertySet node) {
579 var value = visitExpression(node.value);
580 if (node.interfaceTarget != null) {
581 var receiver = getSuperReceiverType(node.interfaceTarget);
582 checkAssignable(
583 node.value,
584 value,
585 receiver.substituteType(node.interfaceTarget.setterType,
586 contravariant: true));
587 }
588 return value;
589 }
590
591 @override
592 DartType visitSymbolLiteral(SymbolLiteral node) {
593 return environment.symbolType;
594 }
595
596 @override
597 DartType visitThisExpression(ThisExpression node) {
598 return environment.thisType;
599 }
600
601 @override
602 DartType visitThrow(Throw node) {
603 visitExpression(node.expression);
604 return const BottomType();
605 }
606
607 @override
608 DartType visitTypeLiteral(TypeLiteral node) {
609 return environment.typeType;
610 }
611
612 @override
613 DartType visitVariableGet(VariableGet node) {
614 return node.promotedType ?? node.variable.type;
615 }
616
617 @override
618 DartType visitVariableSet(VariableSet node) {
619 var value = visitExpression(node.value);
620 checkAssignable(node.value, value, node.variable.type);
621 return value;
622 }
623
624 @override
625 visitAssertStatement(AssertStatement node) {
626 visitExpression(node.condition);
627 if (node.message != null) {
628 visitExpression(node.message);
629 }
630 }
631
632 @override
633 visitBlock(Block node) {
634 node.statements.forEach(visitStatement);
635 }
636
637 @override
638 visitBreakStatement(BreakStatement node) {}
639
640 @override
641 visitContinueSwitchStatement(ContinueSwitchStatement node) {}
642
643 @override
644 visitDoStatement(DoStatement node) {
645 visitStatement(node.body);
646 checkAssignableExpression(node.condition, environment.boolType);
647 }
648
649 @override
650 visitEmptyStatement(EmptyStatement node) {}
651
652 @override
653 visitExpressionStatement(ExpressionStatement node) {
654 visitExpression(node.expression);
655 }
656
657 @override
658 visitForInStatement(ForInStatement node) {
659 var iterable = visitExpression(node.iterable);
660 // TODO(asgerf): Store interface targets on for-in loops or desugar them,
661 // instead of doing the ad-hoc resolution here.
662 if (node.isAsync) {
663 checkAssignable(node, getStreamElementType(iterable), node.variable.type);
664 } else {
665 checkAssignable(
666 node, getIterableElementType(iterable), node.variable.type);
667 }
668 visitStatement(node.body);
669 }
670
671 static final Name iteratorName = new Name('iterator');
672 static final Name nextName = new Name('next');
673
674 DartType getIterableElementType(DartType iterable) {
675 if (iterable is InterfaceType) {
676 var iteratorGetter =
677 hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
678 if (iteratorGetter == null) return const DynamicType();
679 var iteratorType = Substitution
680 .fromInterfaceType(iterable)
681 .substituteType(iteratorGetter.getterType);
682 if (iteratorType is InterfaceType) {
683 var nextGetter =
684 hierarchy.getInterfaceMember(iteratorType.classNode, nextName);
685 if (nextGetter == null) return const DynamicType();
686 return Substitution
687 .fromInterfaceType(iteratorType)
688 .substituteType(nextGetter.getterType);
689 }
690 }
691 return const DynamicType();
692 }
693
694 DartType getStreamElementType(DartType stream) {
695 if (stream is InterfaceType) {
696 var asStream =
697 hierarchy.getTypeAsInstanceOf(stream, coreTypes.streamClass);
698 if (asStream == null) return const DynamicType();
699 return asStream.typeArguments.single;
700 }
701 return const DynamicType();
702 }
703
704 @override
705 visitForStatement(ForStatement node) {
706 node.variables.forEach(visitVariableDeclaration);
707 if (node.condition != null) {
708 checkAssignableExpression(node.condition, environment.boolType);
709 }
710 node.updates.forEach(visitExpression);
711 visitStatement(node.body);
712 }
713
714 @override
715 visitFunctionDeclaration(FunctionDeclaration node) {
716 handleNestedFunctionNode(node.function);
717 }
718
719 @override
720 visitIfStatement(IfStatement node) {
721 checkAssignableExpression(node.condition, environment.boolType);
722 visitStatement(node.then);
723 if (node.otherwise != null) {
724 visitStatement(node.otherwise);
725 }
726 }
727
728 @override
729 visitInvalidStatement(InvalidStatement node) {}
730
731 @override
732 visitLabeledStatement(LabeledStatement node) {
733 visitStatement(node.body);
734 }
735
736 @override
737 visitReturnStatement(ReturnStatement node) {
738 if (node.expression != null) {
739 if (environment.returnType == null) {
740 fail(node, 'Return of a value from void method');
741 } else {
742 checkAssignableExpression(node.expression, environment.returnType);
743 }
744 }
745 }
746
747 @override
748 visitSwitchStatement(SwitchStatement node) {
749 visitExpression(node.expression);
750 for (var switchCase in node.cases) {
751 switchCase.expressions.forEach(visitExpression);
752 visitStatement(switchCase.body);
753 }
754 }
755
756 @override
757 visitTryCatch(TryCatch node) {
758 visitStatement(node.body);
759 for (var catchClause in node.catches) {
760 visitStatement(catchClause.body);
761 }
762 }
763
764 @override
765 visitTryFinally(TryFinally node) {
766 visitStatement(node.body);
767 visitStatement(node.finalizer);
768 }
769
770 @override
771 visitVariableDeclaration(VariableDeclaration node) {
772 if (node.initializer != null) {
773 checkAssignableExpression(node.initializer, node.type);
774 }
775 }
776
777 @override
778 visitWhileStatement(WhileStatement node) {
779 checkAssignableExpression(node.condition, environment.boolType);
780 visitStatement(node.body);
781 }
782
783 @override
784 visitYieldStatement(YieldStatement node) {
785 checkAssignableExpression(node.expression, environment.yieldType);
786 }
787
788 @override
789 visitFieldInitializer(FieldInitializer node) {
790 checkAssignableExpression(node.value, node.field.type);
791 }
792
793 @override
794 visitRedirectingInitializer(RedirectingInitializer node) {
795 handleCall(node.arguments, node.target.function,
796 typeParameters: const <TypeParameter>[]);
797 }
798
799 @override
800 visitSuperInitializer(SuperInitializer node) {
801 handleCall(node.arguments, node.target.function,
802 typeParameters: const <TypeParameter>[]);
803 }
804
805 @override
806 visitLocalInitializer(LocalInitializer node) {
807 visitVariableDeclaration(node.variable);
808 }
809
810 @override
811 visitInvalidInitializer(InvalidInitializer node) {}
812 }
OLDNEW
« no previous file with comments | « lib/type_algebra.dart ('k') | lib/type_environment.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698