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

Side by Side Diff: lib/type_checker.dart

Issue 2465893002: Add strong mode type checking pass. (Closed)
Patch Set: Clean up some spurious changes 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.function.positionalParameters
Kevin Millikin (Google) 2016/11/01 13:03:01 This checks the optional parameters twice, both he
asgerf 2016/11/01 13:59:36 You are right, this was not supposed to be here.
157 .skip(node.function.requiredParameterCount)
158 .forEach(handleOptionalParameter);
159 node.function.namedParameters.forEach(handleOptionalParameter);
160 node.initializers.forEach(visitInitializer);
161 handleFunctionNode(node.function);
162 }
163
164 visitProcedure(Procedure node) {
165 environment.returnType = node.function.returnType;
166 environment.yieldType = _getYieldType(node.function);
167 handleFunctionNode(node.function);
168 }
169
170 void handleFunctionNode(FunctionNode node) {
171 node.positionalParameters
172 .skip(node.requiredParameterCount)
173 .forEach(handleOptionalParameter);
174 node.namedParameters.forEach(handleOptionalParameter);
175 if (node.body != null) {
176 visitStatement(node.body);
177 }
178 }
179
180 void handleNestedFunctionNode(FunctionNode node) {
181 var oldReturn = environment.returnType;
182 var oldYield = environment.yieldType;
183 environment.returnType = node.returnType;
184 environment.yieldType = _getYieldType(node);
185 handleFunctionNode(node);
186 environment.returnType = oldReturn;
187 environment.yieldType = oldYield;
188 }
189
190 void handleOptionalParameter(VariableDeclaration parameter) {
191 if (parameter.initializer != null) {
192 checkAssignableExpression(parameter.initializer, parameter.type);
193 }
194 }
195
196 Substitution getReceiverType(
197 TreeNode access, Expression receiver, Member member) {
198 var type = visitExpression(receiver);
199 Class superclass = member.enclosingClass;
200 if (superclass.supertype == null) {
201 return Substitution.empty; // Members on Object are always accessible.
202 }
203 while (type is TypeParameterType) {
204 type = (type as TypeParameterType).parameter.bound;
205 }
206 if (type is BottomType) {
207 // The bottom type is a subtype of all types, so it should be allowed.
208 return Substitution.bottomForClass(superclass);
209 }
210 if (type is InterfaceType) {
211 // The receiver type should implement the interface declaring the member.
212 var upcastType = hierarchy.getTypeAsInstanceOf(type, superclass);
213 if (upcastType != null) {
214 return Substitution.fromInterfaceType(upcastType);
215 }
216 }
217 if (type is FunctionType && superclass == coreTypes.functionClass) {
218 assert(type.typeParameters.isEmpty);
219 return Substitution.empty;
220 }
221 // Note that we do not allow 'dynamic' here. Dynamic calls should not
222 // have a declared interface target.
223 fail(access, '$member is not accessible on a receiver of type $type');
224 return Substitution.bottomForClass(superclass); // Continue type checking.
225 }
226
227 Substitution getSuperReceiverType(Member member) {
228 return Substitution.fromSupertype(
229 hierarchy.getClassAsInstanceOf(currentClass, member.enclosingClass));
230 }
231
232 DartType handleCall(Arguments arguments, FunctionNode function,
233 {Substitution receiver: Substitution.empty,
234 List<TypeParameter> typeParameters}) {
235 typeParameters ??= function.typeParameters;
236 if (arguments.positional.length < function.requiredParameterCount) {
237 fail(arguments, 'Too few positional arguments');
238 return const BottomType();
239 }
240 if (arguments.positional.length > function.positionalParameters.length) {
241 fail(arguments, 'Too many positional arguments');
242 return const BottomType();
243 }
244 if (arguments.types.length != typeParameters.length) {
245 fail(arguments, 'Wrong number of type arguments');
246 return const BottomType();
247 }
248 var instantiation = Substitution.fromPairs(typeParameters, arguments.types);
249 var substitution = Substitution.combine(receiver, instantiation);
250 for (int i = 0; i < typeParameters.length; ++i) {
251 var argument = arguments.types[i];
252 var bound = substitution.substituteType(typeParameters[i].bound);
253 checkAssignable(arguments, argument, bound);
254 }
255 for (int i = 0; i < arguments.positional.length; ++i) {
256 var expectedType = substitution.substituteType(
257 function.positionalParameters[i].type,
258 contravariant: true);
259 checkAssignableExpression(arguments.positional[i], expectedType);
260 }
261 for (int i = 0; i < arguments.named.length; ++i) {
262 var argument = arguments.named[i];
263 bool found = false;
264 for (int j = 0; j < function.namedParameters.length; ++j) {
265 if (argument.name == function.namedParameters[j].name) {
266 var expectedType = substitution.substituteType(
267 function.namedParameters[j].type,
268 contravariant: true);
269 checkAssignableExpression(argument.value, expectedType);
270 found = true;
271 break;
272 }
273 }
274 if (!found) {
275 fail(argument.value, 'Unexpected named parameter: ${argument.name}');
276 return const BottomType();
277 }
278 }
279 return substitution.substituteType(function.returnType);
280 }
281
282 DartType _getYieldType(FunctionNode function) {
283 switch (function.asyncMarker) {
284 case AsyncMarker.Sync:
285 case AsyncMarker.Async:
286 return null;
287
288 case AsyncMarker.SyncStar:
289 case AsyncMarker.AsyncStar:
290 Class container = function.asyncMarker == AsyncMarker.SyncStar
291 ? coreTypes.iterableClass
292 : coreTypes.streamClass;
293 DartType returnType = function.returnType;
294 if (returnType is InterfaceType && returnType.classNode == container) {
295 return returnType.typeArguments.single;
296 }
297 return const DynamicType();
298
299 case AsyncMarker.SyncYielding:
300 return function.returnType;
301
302 default:
303 throw 'Unexpected async marker: ${function.asyncMarker}';
304 }
305 }
306
307 @override
308 DartType visitAsExpression(AsExpression node) {
309 visitExpression(node.operand);
310 return node.type;
311 }
312
313 @override
314 DartType visitAwaitExpression(AwaitExpression node) {
315 return environment.unfutureType(visitExpression(node.operand));
316 }
317
318 @override
319 DartType visitBlockExpression(BlockExpression node) {
320 visitStatement(node.body);
321 return visitExpression(node.value);
322 }
323
324 @override
325 DartType visitBoolLiteral(BoolLiteral node) {
326 return environment.boolType;
327 }
328
329 @override
330 DartType visitConditionalExpression(ConditionalExpression node) {
331 checkAssignableExpression(node.condition, environment.boolType);
332 if (node.staticType == null) {
333 var thenType = visitExpression(node.then);
334 var otherwiseType = visitExpression(node.otherwise);
335 if (thenType is BottomType) return otherwiseType;
336 if (otherwiseType is BottomType) return thenType;
337 return const DynamicType();
338 } else {
339 checkAssignableExpression(node.then, node.staticType);
340 checkAssignableExpression(node.otherwise, node.staticType);
341 return node.staticType;
342 }
343 }
344
345 @override
346 DartType visitConstructorInvocation(ConstructorInvocation node) {
347 Constructor target = node.target;
348 Arguments arguments = node.arguments;
349 Class class_ = target.enclosingClass;
350 handleCall(arguments, target.function,
351 typeParameters: class_.typeParameters);
352 return new InterfaceType(target.enclosingClass, arguments.types);
353 }
354
355 @override
356 DartType visitDirectMethodInvocation(DirectMethodInvocation node) {
357 return handleCall(node.arguments, node.target.function,
358 receiver: getReceiverType(node, node.receiver, node.target));
359 }
360
361 @override
362 DartType visitDirectPropertyGet(DirectPropertyGet node) {
363 var receiver = getReceiverType(node, node.receiver, node.target);
364 return receiver.substituteType(node.target.getterType);
365 }
366
367 @override
368 DartType visitDirectPropertySet(DirectPropertySet node) {
369 var receiver = getReceiverType(node, node.receiver, node.target);
370 var value = visitExpression(node.value);
371 checkAssignable(node, value,
372 receiver.substituteType(node.target.setterType, contravariant: true));
373 return value;
374 }
375
376 @override
377 DartType visitDoubleLiteral(DoubleLiteral node) {
378 return environment.doubleType;
379 }
380
381 @override
382 DartType visitFunctionExpression(FunctionExpression node) {
383 handleNestedFunctionNode(node.function);
384 return node.function.functionType;
385 }
386
387 @override
388 DartType visitIntLiteral(IntLiteral node) {
389 return environment.intType;
390 }
391
392 @override
393 DartType visitInvalidExpression(InvalidExpression node) {
394 return const BottomType();
395 }
396
397 @override
398 DartType visitIsExpression(IsExpression node) {
399 visitExpression(node.operand);
400 return environment.boolType;
401 }
402
403 @override
404 DartType visitLet(Let node) {
405 var value = visitExpression(node.variable.initializer);
406 if (node.variable.type is DynamicType) {
407 node.variable.type = value;
408 }
409 return visitExpression(node.body);
410 }
411
412 @override
413 DartType visitListLiteral(ListLiteral node) {
414 for (var item in node.expressions) {
415 checkAssignableExpression(item, node.typeArgument);
416 }
417 return environment.literalListType(node.typeArgument);
418 }
419
420 @override
421 DartType visitLogicalExpression(LogicalExpression node) {
422 checkAssignableExpression(node.left, environment.boolType);
423 checkAssignableExpression(node.right, environment.boolType);
424 return environment.boolType;
425 }
426
427 @override
428 DartType visitMapLiteral(MapLiteral node) {
429 for (var entry in node.entries) {
430 checkAssignableExpression(entry.key, node.keyType);
431 checkAssignableExpression(entry.value, node.valueType);
432 }
433 return environment.literalMapType(node.keyType, node.valueType);
434 }
435
436 DartType handleDynamicCall(DartType receiver, Arguments arguments) {
437 arguments.positional.forEach(visitExpression);
438 arguments.named.forEach((NamedExpression n) => visitExpression(n.value));
439 return const DynamicType();
440 }
441
442 DartType handleFunctionCall(
443 TreeNode access, FunctionType function, Arguments arguments) {
444 if (function.requiredParameterCount > arguments.positional.length) {
445 fail(access, 'Too few positional arguments');
446 return const BottomType();
447 }
448 if (function.positionalParameters.length < arguments.positional.length) {
449 fail(access, 'Too many positional arguments');
450 return const BottomType();
451 }
452 if (function.typeParameters.length != arguments.types.length) {
453 fail(access, 'Wrong number of type arguments');
454 return const BottomType();
455 }
456 var instantiation =
457 Substitution.fromPairs(function.typeParameters, arguments.types);
458 for (int i = 0; i < arguments.positional.length; ++i) {
459 var expectedType = instantiation.substituteType(
460 function.positionalParameters[i],
461 contravariant: true);
462 checkAssignableExpression(arguments.positional[i], expectedType);
463 }
464 for (int i = 0; i < arguments.named.length; ++i) {
465 var argument = arguments.named[i];
466 var expectedType = function.namedParameters[argument.name];
467 if (expectedType == null) {
468 fail(argument.value, 'Unexpected named parameter: ${argument.name}');
469 } else {
470 checkAssignableExpression(argument.value,
471 instantiation.substituteType(expectedType, contravariant: true));
472 }
473 }
474 return instantiation.substituteType(function.returnType);
475 }
476
477 @override
478 DartType visitMethodInvocation(MethodInvocation node) {
479 var target = node.interfaceTarget;
480 if (target == null) {
481 var receiver = visitExpression(node.receiver);
482 return (node.name.name == 'call' && receiver is FunctionType)
483 ? handleFunctionCall(node, receiver, node.arguments)
484 : handleDynamicCall(receiver, node.arguments);
485 } else if (environment.isOverloadedArithmeticOperator(target)) {
486 assert(node.arguments.positional.length == 1);
487 var receiver = visitExpression(node.receiver);
488 var argument = visitExpression(node.arguments.positional[0]);
489 return environment.getTypeOfOverloadedArithmetic(receiver, argument);
490 } else {
491 return handleCall(node.arguments, target.function,
492 receiver: getReceiverType(node, node.receiver, node.interfaceTarget));
493 }
494 }
495
496 @override
497 DartType visitPropertyGet(PropertyGet node) {
498 if (node.interfaceTarget == null) {
499 visitExpression(node.receiver);
500 return const DynamicType();
501 } else {
502 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
503 return receiver.substituteType(node.interfaceTarget.getterType);
504 }
505 }
506
507 @override
508 DartType visitPropertySet(PropertySet node) {
509 var value = visitExpression(node.value);
510 if (node.interfaceTarget != null) {
511 var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
512 checkAssignable(
513 node.value,
514 value,
515 receiver.substituteType(node.interfaceTarget.setterType,
516 contravariant: true));
517 } else {
518 visitExpression(node.receiver);
519 }
520 return value;
521 }
522
523 @override
524 DartType visitNot(Not node) {
525 visitExpression(node.operand);
526 return environment.boolType;
527 }
528
529 @override
530 DartType visitNullLiteral(NullLiteral node) {
531 return const BottomType();
532 }
533
534 @override
535 DartType visitRethrow(Rethrow node) {
536 return const BottomType();
537 }
538
539 @override
540 DartType visitStaticGet(StaticGet node) {
541 return node.target.getterType;
542 }
543
544 @override
545 DartType visitStaticInvocation(StaticInvocation node) {
546 return handleCall(node.arguments, node.target.function);
547 }
548
549 @override
550 DartType visitStaticSet(StaticSet node) {
551 var value = visitExpression(node.value);
552 checkAssignable(node.value, value, node.target.setterType);
553 return value;
554 }
555
556 @override
557 DartType visitStringConcatenation(StringConcatenation node) {
558 node.expressions.forEach(visitExpression);
559 return environment.stringType;
560 }
561
562 @override
563 DartType visitStringLiteral(StringLiteral node) {
564 return environment.stringType;
565 }
566
567 @override
568 DartType visitSuperMethodInvocation(SuperMethodInvocation node) {
569 if (node.interfaceTarget == null) {
570 return handleDynamicCall(environment.thisType, node.arguments);
571 } else {
572 return handleCall(node.arguments, node.interfaceTarget.function,
573 receiver: getSuperReceiverType(node.interfaceTarget));
574 }
575 }
576
577 @override
578 DartType visitSuperPropertyGet(SuperPropertyGet node) {
579 if (node.interfaceTarget == null) {
580 return const DynamicType();
581 } else {
582 var receiver = getSuperReceiverType(node.interfaceTarget);
583 return receiver.substituteType(node.interfaceTarget.getterType);
584 }
585 }
586
587 @override
588 DartType visitSuperPropertySet(SuperPropertySet node) {
589 var value = visitExpression(node.value);
590 if (node.interfaceTarget != null) {
591 var receiver = getSuperReceiverType(node.interfaceTarget);
592 checkAssignable(
593 node.value,
594 value,
595 receiver.substituteType(node.interfaceTarget.setterType,
596 contravariant: true));
597 }
598 return value;
599 }
600
601 @override
602 DartType visitSymbolLiteral(SymbolLiteral node) {
603 return environment.symbolType;
604 }
605
606 @override
607 DartType visitThisExpression(ThisExpression node) {
608 return environment.thisType;
609 }
610
611 @override
612 DartType visitThrow(Throw node) {
613 visitExpression(node.expression);
614 return const BottomType();
615 }
616
617 @override
618 DartType visitTypeLiteral(TypeLiteral node) {
619 return environment.typeType;
620 }
621
622 @override
623 DartType visitVariableGet(VariableGet node) {
624 return node.promotedType ?? node.variable.type;
625 }
626
627 @override
628 DartType visitVariableSet(VariableSet node) {
629 var value = visitExpression(node.value);
630 checkAssignable(node.value, value, node.variable.type);
631 return value;
632 }
633
634 @override
635 visitAssertStatement(AssertStatement node) {
636 visitExpression(node.condition);
637 if (node.message != null) {
638 visitExpression(node.message);
639 }
640 }
641
642 @override
643 visitBlock(Block node) {
644 node.statements.forEach(visitStatement);
645 }
646
647 @override
648 visitBreakStatement(BreakStatement node) {}
649
650 @override
651 visitContinueSwitchStatement(ContinueSwitchStatement node) {}
652
653 @override
654 visitDoStatement(DoStatement node) {
655 visitStatement(node.body);
656 checkAssignableExpression(node.condition, environment.boolType);
657 }
658
659 @override
660 visitEmptyStatement(EmptyStatement node) {}
661
662 @override
663 visitExpressionStatement(ExpressionStatement node) {
664 visitExpression(node.expression);
665 }
666
667 @override
668 visitForInStatement(ForInStatement node) {
669 var iterable = visitExpression(node.iterable);
670 // TODO(asgerf): Store interface targets on for-in loops or desugar them,
671 // instead of doing the ad-hoc resolution here.
672 if (node.isAsync) {
673 checkAssignable(node, getStreamElementType(iterable), node.variable.type);
674 } else {
675 checkAssignable(
676 node, getIterableElementType(iterable), node.variable.type);
677 }
678 visitStatement(node.body);
679 }
680
681 static final Name iteratorName = new Name('iterator');
682 static final Name nextName = new Name('next');
683
684 DartType getIterableElementType(DartType iterable) {
685 if (iterable is InterfaceType) {
686 var iteratorGetter =
687 hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
688 if (iteratorGetter == null) return const DynamicType();
689 var iteratorType = Substitution
690 .fromInterfaceType(iterable)
691 .substituteType(iteratorGetter.getterType);
692 if (iteratorType is InterfaceType) {
693 var nextGetter =
694 hierarchy.getInterfaceMember(iteratorType.classNode, nextName);
695 if (nextGetter == null) return const DynamicType();
696 return Substitution
697 .fromInterfaceType(iteratorType)
698 .substituteType(nextGetter.getterType);
699 }
700 }
701 return const DynamicType();
702 }
703
704 DartType getStreamElementType(DartType stream) {
705 if (stream is InterfaceType) {
706 var asStream =
707 hierarchy.getTypeAsInstanceOf(stream, coreTypes.streamClass);
708 if (asStream == null) return const DynamicType();
709 return asStream.typeArguments.single;
710 }
711 return const DynamicType();
712 }
713
714 @override
715 visitForStatement(ForStatement node) {
716 node.variables.forEach(visitVariableDeclaration);
717 if (node.condition != null) {
718 checkAssignableExpression(node.condition, environment.boolType);
719 }
720 node.updates.forEach(visitExpression);
721 visitStatement(node.body);
722 }
723
724 @override
725 visitFunctionDeclaration(FunctionDeclaration node) {
726 handleNestedFunctionNode(node.function);
727 }
728
729 @override
730 visitIfStatement(IfStatement node) {
731 checkAssignableExpression(node.condition, environment.boolType);
732 visitStatement(node.then);
733 if (node.otherwise != null) {
734 visitStatement(node.otherwise);
735 }
736 }
737
738 @override
739 visitInvalidStatement(InvalidStatement node) {}
740
741 @override
742 visitLabeledStatement(LabeledStatement node) {
743 visitStatement(node.body);
744 }
745
746 @override
747 visitReturnStatement(ReturnStatement node) {
748 if (node.expression != null) {
749 if (environment.returnType == null) {
750 fail(node, 'Return from void method');
Kevin Millikin (Google) 2016/11/01 13:03:01 Return a value from void method.
asgerf 2016/11/01 13:59:36 Done.
751 } else {
752 checkAssignableExpression(node.expression, environment.returnType);
753 }
754 }
755 }
756
757 @override
758 visitSwitchStatement(SwitchStatement node) {
759 visitExpression(node.expression);
760 for (var switchCase in node.cases) {
761 switchCase.expressions.forEach(visitExpression);
762 visitStatement(switchCase.body);
763 }
764 }
765
766 @override
767 visitTryCatch(TryCatch node) {
768 visitStatement(node.body);
769 for (var catchClause in node.catches) {
770 visitStatement(catchClause.body);
771 }
772 }
773
774 @override
775 visitTryFinally(TryFinally node) {
776 visitStatement(node.body);
777 visitStatement(node.finalizer);
778 }
779
780 @override
781 visitVariableDeclaration(VariableDeclaration node) {
782 if (node.initializer != null) {
783 checkAssignableExpression(node.initializer, node.type);
784 }
785 }
786
787 @override
788 visitWhileStatement(WhileStatement node) {
789 checkAssignableExpression(node.condition, environment.boolType);
790 visitStatement(node.body);
791 }
792
793 @override
794 visitYieldStatement(YieldStatement node) {
795 checkAssignableExpression(node.expression, environment.yieldType);
796 }
797
798 @override
799 visitFieldInitializer(FieldInitializer node) {
800 checkAssignableExpression(node.value, node.field.type);
801 }
802
803 @override
804 visitRedirectingInitializer(RedirectingInitializer node) {
805 handleCall(node.arguments, node.target.function,
806 typeParameters: const <TypeParameter>[]);
807 }
808
809 @override
810 visitSuperInitializer(SuperInitializer node) {
811 handleCall(node.arguments, node.target.function,
812 typeParameters: const <TypeParameter>[]);
813 }
814
815 @override
816 visitLocalInitializer(LocalInitializer node) {
817 visitVariableDeclaration(node.variable);
818 }
819
820 @override
821 visitInvalidInitializer(InvalidInitializer node) {}
822 }
OLDNEW
« lib/type_algebra.dart ('K') | « lib/type_algebra.dart ('k') | lib/type_environment.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698