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

Side by Side Diff: pkg/compiler/lib/src/typechecker.dart

Issue 962603002: Typecheck return with respect to async. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated and tested. Created 5 years, 9 months 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 | Annotate | Revision Log
« no previous file with comments | « pkg/compiler/lib/src/tree/nodes.dart ('k') | pkg/compiler/lib/src/warnings.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 4
5 part of dart2js; 5 part of dart2js;
6 6
7 class TypeCheckerTask extends CompilerTask { 7 class TypeCheckerTask extends CompilerTask {
8 TypeCheckerTask(Compiler compiler) : super(compiler); 8 TypeCheckerTask(Compiler compiler) : super(compiler);
9 String get name => "Type checker"; 9 String get name => "Type checker";
10 10
11 void check(TreeElements elements) { 11 void check(TreeElements elements) {
12 AstElement element = elements.analyzedElement; 12 AstElement element = elements.analyzedElement;
13 if (element.isTypedef) return;
14
13 compiler.withCurrentElement(element, () { 15 compiler.withCurrentElement(element, () {
14 measure(() { 16 measure(() {
15 Node tree = element.node; 17 Node tree = element.node;
16 TypeCheckerVisitor visitor = 18 TypeCheckerVisitor visitor =
17 new TypeCheckerVisitor(compiler, elements, compiler.types); 19 new TypeCheckerVisitor(compiler, elements, compiler.types);
18 if (element.isField) { 20 if (element.isField) {
19 visitor.analyzingInitializer = true; 21 visitor.analyzingInitializer = true;
20 } 22 }
21 tree.accept(visitor); 23 tree.accept(visitor);
22 }); 24 });
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 /// Returns [: true :] if the element can be access as an invocation. 56 /// Returns [: true :] if the element can be access as an invocation.
55 bool isCallable(Compiler compiler) { 57 bool isCallable(Compiler compiler) {
56 if (element != null && element.isAbstractField) { 58 if (element != null && element.isAbstractField) {
57 AbstractFieldElement abstractFieldElement = element; 59 AbstractFieldElement abstractFieldElement = element;
58 if (abstractFieldElement.getter == null) { 60 if (abstractFieldElement.getter == null) {
59 // Setters cannot be invoked as function invocations. 61 // Setters cannot be invoked as function invocations.
60 return false; 62 return false;
61 } 63 }
62 } 64 }
63 return compiler.types.isAssignable( 65 return compiler.types.isAssignable(
64 computeType(compiler), compiler.functionClass.computeType(compiler)); 66 computeType(compiler), compiler.coreTypes.functionType);
65 } 67 }
66 } 68 }
67 69
68 /// An access of a instance member. 70 /// An access of a instance member.
69 class MemberAccess extends ElementAccess { 71 class MemberAccess extends ElementAccess {
70 final MemberSignature member; 72 final MemberSignature member;
71 73
72 MemberAccess(MemberSignature this.member); 74 MemberAccess(MemberSignature this.member);
73 75
74 Element get element => member.declarations.first.element; 76 Element get element => member.declarations.first.element;
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 final Compiler compiler; 259 final Compiler compiler;
258 final TreeElements elements; 260 final TreeElements elements;
259 final Types types; 261 final Types types;
260 262
261 Node lastSeenNode; 263 Node lastSeenNode;
262 DartType expectedReturnType; 264 DartType expectedReturnType;
263 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; 265 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC;
264 266
265 final ClassElement currentClass; 267 final ClassElement currentClass;
266 268
269 /// The immediately enclosing field, method or constructor being analyzed.
270 ExecutableElement executableContext;
271
272 CoreTypes get coreTypes => compiler.coreTypes;
273
274 InterfaceType get intType => coreTypes.intType;
275 InterfaceType get doubleType => coreTypes.doubleType;
276 InterfaceType get boolType => coreTypes.boolType;
277 InterfaceType get stringType => coreTypes.stringType;
278
267 DartType thisType; 279 DartType thisType;
268 DartType superType; 280 DartType superType;
269 281
270 Link<DartType> cascadeTypes = const Link<DartType>(); 282 Link<DartType> cascadeTypes = const Link<DartType>();
271 283
272 bool analyzingInitializer = false; 284 bool analyzingInitializer = false;
273 285
274 DartType intType;
275 DartType doubleType;
276 DartType boolType;
277 DartType stringType;
278 DartType objectType;
279 DartType listType;
280
281 Map<Node, List<TypePromotion>> shownTypePromotionsMap = 286 Map<Node, List<TypePromotion>> shownTypePromotionsMap =
282 new Map<Node, List<TypePromotion>>(); 287 new Map<Node, List<TypePromotion>>();
283 288
284 Map<VariableElement, Link<TypePromotion>> typePromotionsMap = 289 Map<VariableElement, Link<TypePromotion>> typePromotionsMap =
285 new Map<VariableElement, Link<TypePromotion>>(); 290 new Map<VariableElement, Link<TypePromotion>>();
286 291
287 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); 292 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>();
288 293
289 void showTypePromotion(Node node, TypePromotion typePromotion) { 294 void showTypePromotion(Node node, TypePromotion typePromotion) {
290 List<TypePromotion> shownTypePromotions = 295 List<TypePromotion> shownTypePromotions =
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 } 335 }
331 336
332 DartType getKnownType(VariableElement element) { 337 DartType getKnownType(VariableElement element) {
333 TypePromotion typePromotion = getKnownTypePromotion(element); 338 TypePromotion typePromotion = getKnownTypePromotion(element);
334 if (typePromotion != null) return typePromotion.type; 339 if (typePromotion != null) return typePromotion.type;
335 return element.type; 340 return element.type;
336 } 341 }
337 342
338 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) 343 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types)
339 : this.elements = elements, 344 : this.elements = elements,
340 currentClass = elements.analyzedElement != null 345 this.executableContext = elements.analyzedElement,
346 this.currentClass = elements.analyzedElement != null
341 ? elements.analyzedElement.enclosingClass : null { 347 ? elements.analyzedElement.enclosingClass : null {
342 intType = compiler.intClass.computeType(compiler);
343 doubleType = compiler.doubleClass.computeType(compiler);
344 boolType = compiler.boolClass.computeType(compiler);
345 stringType = compiler.stringClass.computeType(compiler);
346 objectType = compiler.objectClass.computeType(compiler);
347 listType = compiler.listClass.computeType(compiler);
348 348
349 if (currentClass != null) { 349 if (currentClass != null) {
350 thisType = currentClass.thisType; 350 thisType = currentClass.thisType;
351 superType = currentClass.supertype; 351 superType = currentClass.supertype;
352 } else { 352 } else {
353 // If these are used, an error should have been reported by the resolver. 353 // If these are used, an error should have been reported by the resolver.
354 thisType = const DynamicType(); 354 thisType = const DynamicType();
355 superType = const DynamicType(); 355 superType = const DynamicType();
356 } 356 }
357 } 357 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 } 404 }
405 405
406 /// If [inInitializer] is true, assignment should be interpreted as write to 406 /// If [inInitializer] is true, assignment should be interpreted as write to
407 /// a field and not to a setter. 407 /// a field and not to a setter.
408 DartType analyze(Node node, {bool inInitializer: false}) { 408 DartType analyze(Node node, {bool inInitializer: false}) {
409 if (node == null) { 409 if (node == null) {
410 final String error = 'Unexpected node: null'; 410 final String error = 'Unexpected node: null';
411 if (lastSeenNode != null) { 411 if (lastSeenNode != null) {
412 compiler.internalError(lastSeenNode, error); 412 compiler.internalError(lastSeenNode, error);
413 } else { 413 } else {
414 compiler.internalError(elements.analyzedElement, error); 414 compiler.internalError(executableContext, error);
415 } 415 }
416 } else { 416 } else {
417 lastSeenNode = node; 417 lastSeenNode = node;
418 } 418 }
419 bool previouslyInitializer = analyzingInitializer; 419 bool previouslyInitializer = analyzingInitializer;
420 analyzingInitializer = inInitializer; 420 analyzingInitializer = inInitializer;
421 DartType result = node.accept(this); 421 DartType result = node.accept(this);
422 analyzingInitializer = previouslyInitializer; 422 analyzingInitializer = previouslyInitializer;
423 if (result == null) { 423 if (result == null) {
424 compiler.internalError(node, 'Type is null.'); 424 compiler.internalError(node, 'Type is null.');
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 } 592 }
593 593
594 DartType visitFunctionExpression(FunctionExpression node) { 594 DartType visitFunctionExpression(FunctionExpression node) {
595 DartType type; 595 DartType type;
596 DartType returnType; 596 DartType returnType;
597 DartType previousType; 597 DartType previousType;
598 final FunctionElement element = elements.getFunctionDefinition(node); 598 final FunctionElement element = elements.getFunctionDefinition(node);
599 assert(invariant(node, element != null, 599 assert(invariant(node, element != null,
600 message: 'FunctionExpression with no element')); 600 message: 'FunctionExpression with no element'));
601 if (Elements.isUnresolved(element)) return const DynamicType(); 601 if (Elements.isUnresolved(element)) return const DynamicType();
602 if (identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR) || 602 if (element.isGenerativeConstructor) {
603 identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY)) {
604 type = const DynamicType(); 603 type = const DynamicType();
605 returnType = const VoidType(); 604 returnType = const VoidType();
606 605
607 element.functionSignature.forEachParameter((ParameterElement parameter) { 606 element.functionSignature.forEachParameter((ParameterElement parameter) {
608 if (parameter.isInitializingFormal) { 607 if (parameter.isInitializingFormal) {
609 InitializingFormalElement fieldParameter = parameter; 608 InitializingFormalElement fieldParameter = parameter;
610 checkAssignable(parameter, parameter.type, 609 checkAssignable(parameter, parameter.type,
611 fieldParameter.fieldElement.computeType(compiler)); 610 fieldParameter.fieldElement.computeType(compiler));
612 } 611 }
613 }); 612 });
614 if (node.initializers != null) { 613 if (node.initializers != null) {
615 analyze(node.initializers, inInitializer: true); 614 analyze(node.initializers, inInitializer: true);
616 } 615 }
617 } else { 616 } else {
618 FunctionType functionType = element.computeType(compiler); 617 FunctionType functionType = element.computeType(compiler);
619 returnType = functionType.returnType; 618 returnType = functionType.returnType;
620 type = functionType; 619 type = functionType;
621 } 620 }
621 ExecutableElement previousExecutableContext = executableContext;
622 DartType previousReturnType = expectedReturnType; 622 DartType previousReturnType = expectedReturnType;
623 expectedReturnType = returnType; 623 expectedReturnType = returnType;
624 AsyncMarker previousAsyncMarker = currentAsyncMarker; 624 AsyncMarker previousAsyncMarker = currentAsyncMarker;
625
626 executableContext = element;
625 currentAsyncMarker = element.asyncMarker; 627 currentAsyncMarker = element.asyncMarker;
626 analyze(node.body); 628 analyze(node.body);
629
630 executableContext = previousExecutableContext;
627 expectedReturnType = previousReturnType; 631 expectedReturnType = previousReturnType;
628 currentAsyncMarker = previousAsyncMarker; 632 currentAsyncMarker = previousAsyncMarker;
629 return type; 633 return type;
630 } 634 }
631 635
632 DartType visitIdentifier(Identifier node) { 636 DartType visitIdentifier(Identifier node) {
633 if (node.isThis()) { 637 if (node.isThis()) {
634 return thisType; 638 return thisType;
635 } else if (node.isSuper()) { 639 } else if (node.isSuper()) {
636 return superType; 640 return superType;
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 DartType visitRethrow(Rethrow node) { 1572 DartType visitRethrow(Rethrow node) {
1569 return const StatementType(); 1573 return const StatementType();
1570 } 1574 }
1571 1575
1572 /** Dart Programming Language Specification: 11.10 Return */ 1576 /** Dart Programming Language Specification: 11.10 Return */
1573 DartType visitReturn(Return node) { 1577 DartType visitReturn(Return node) {
1574 if (identical(node.beginToken.stringValue, 'native')) { 1578 if (identical(node.beginToken.stringValue, 'native')) {
1575 return const StatementType(); 1579 return const StatementType();
1576 } 1580 }
1577 1581
1578 final expression = node.expression; 1582 final Node expression = node.expression;
1579 final isVoidFunction = expectedReturnType.isVoid;
1580 1583
1581 // Executing a return statement return e; [...] It is a static type warning 1584 // Executing a return statement return e; [...] It is a static type warning
1582 // if the type of e may not be assigned to the declared return type of the 1585 // if the type of e may not be assigned to the declared return type of the
1583 // immediately enclosing function. 1586 // immediately enclosing function.
1584 if (expression != null) { 1587 if (expression != null) {
1585 final expressionType = analyze(expression); 1588 DartType expressionType = analyze(expression);
1586 Element element = elements.analyzedElement; 1589 if (executableContext.isGenerativeConstructor) {
1587 if (element != null && element.isGenerativeConstructor) {
1588 // The resolver already emitted an error for this expression. 1590 // The resolver already emitted an error for this expression.
1589 } else if (isVoidFunction
1590 && !types.isAssignable(expressionType, const VoidType())) {
1591 reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID);
1592 } else { 1591 } else {
1593 checkAssignable(expression, expressionType, expectedReturnType); 1592 if (currentAsyncMarker == AsyncMarker.ASYNC) {
1593 expressionType = coreTypes.futureType(flatten(expressionType));
1594 }
1595 if (expectedReturnType.isVoid &&
1596 !types.isAssignable(expressionType, const VoidType())) {
1597 reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID);
1598 } else {
1599 checkAssignable(expression, expressionType, expectedReturnType);
1600 }
1594 } 1601 }
1595 1602
1596 // Let f be the function immediately enclosing a return statement of the
1597 // form 'return;' It is a static warning if both of the following conditions
1598 // hold:
1599 // - f is not a generative constructor.
1600 // - The return type of f may not be assigned to void.
1601 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { 1603 } else if (!types.isAssignable(expectedReturnType, const VoidType())) {
1604 // Let f be the function immediately enclosing a return statement of the
1605 // form 'return;' It is a static warning if both of the following
1606 // conditions hold:
1607 // - f is not a generative constructor.
1608 // - The return type of f may not be assigned to void.
1602 reportTypeWarning(node, MessageKind.RETURN_NOTHING, 1609 reportTypeWarning(node, MessageKind.RETURN_NOTHING,
1603 {'returnType': expectedReturnType}); 1610 {'returnType': expectedReturnType});
1604 } 1611 }
1605 return const StatementType(); 1612 return const StatementType();
1606 } 1613 }
1607 1614
1608 DartType visitThrow(Throw node) { 1615 DartType visitThrow(Throw node) {
1609 // TODO(johnniwinther): Handle reachability. 1616 // TODO(johnniwinther): Handle reachability.
1610 analyze(node.expression); 1617 analyze(node.expression);
1611 return const DynamicType(); 1618 return const DynamicType();
(...skipping 20 matching lines...) Expand all
1632 1639
1633 DartType visitAwait(Await node) { 1640 DartType visitAwait(Await node) {
1634 DartType expressionType = analyze(node.expression); 1641 DartType expressionType = analyze(node.expression);
1635 return flatten(expressionType); 1642 return flatten(expressionType);
1636 } 1643 }
1637 1644
1638 DartType visitYield(Yield node) { 1645 DartType visitYield(Yield node) {
1639 DartType resultType = analyze(node.expression); 1646 DartType resultType = analyze(node.expression);
1640 if (!node.hasStar) { 1647 if (!node.hasStar) {
1641 if (currentAsyncMarker.isAsync) { 1648 if (currentAsyncMarker.isAsync) {
1642 resultType = compiler.coreTypes.streamType(resultType); 1649 resultType = coreTypes.streamType(resultType);
1643 } else { 1650 } else {
1644 resultType = compiler.coreTypes.iterableType(resultType); 1651 resultType = coreTypes.iterableType(resultType);
1645 } 1652 }
1646 } else { 1653 } else {
1647 if (currentAsyncMarker.isAsync) { 1654 if (currentAsyncMarker.isAsync) {
1648 // The static type of expression must be assignable to Stream. 1655 // The static type of expression must be assignable to Stream.
1649 checkAssignable(node, resultType, compiler.coreTypes.streamType()); 1656 checkAssignable(node, resultType, coreTypes.streamType());
1650 } else { 1657 } else {
1651 // The static type of expression must be assignable to Iterable. 1658 // The static type of expression must be assignable to Iterable.
1652 checkAssignable(node, resultType, compiler.coreTypes.iterableType()); 1659 checkAssignable(node, resultType, coreTypes.iterableType());
1653 } 1660 }
1654 } 1661 }
1655 // The static type of the result must be assignable to the declared type. 1662 // The static type of the result must be assignable to the declared type.
1656 checkAssignable(node, resultType, expectedReturnType); 1663 checkAssignable(node, resultType, expectedReturnType);
1657 return const StatementType(); 1664 return const StatementType();
1658 } 1665 }
1659 1666
1660 DartType visitTypeAnnotation(TypeAnnotation node) { 1667 DartType visitTypeAnnotation(TypeAnnotation node) {
1661 return elements.getType(node); 1668 return elements.getType(node);
1662 } 1669 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1699 1706
1700 DartType visitConditional(Conditional node) { 1707 DartType visitConditional(Conditional node) {
1701 Expression condition = node.condition; 1708 Expression condition = node.condition;
1702 Expression thenExpression = node.thenExpression; 1709 Expression thenExpression = node.thenExpression;
1703 1710
1704 checkCondition(condition); 1711 checkCondition(condition);
1705 1712
1706 DartType thenType = analyzeInPromotedContext(condition, thenExpression); 1713 DartType thenType = analyzeInPromotedContext(condition, thenExpression);
1707 1714
1708 DartType elseType = analyze(node.elseExpression); 1715 DartType elseType = analyze(node.elseExpression);
1709 return compiler.types.computeLeastUpperBound(thenType, elseType); 1716 return types.computeLeastUpperBound(thenType, elseType);
1710 } 1717 }
1711 1718
1712 visitStringInterpolation(StringInterpolation node) { 1719 visitStringInterpolation(StringInterpolation node) {
1713 node.visitChildren(this); 1720 node.visitChildren(this);
1714 return stringType; 1721 return stringType;
1715 } 1722 }
1716 1723
1717 visitStringInterpolationPart(StringInterpolationPart node) { 1724 visitStringInterpolationPart(StringInterpolationPart node) {
1718 node.visitChildren(this); 1725 node.visitChildren(this);
1719 return stringType; 1726 return stringType;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1785 if (caseMatch == null) continue; 1792 if (caseMatch == null) continue;
1786 1793
1787 DartType caseType = analyze(caseMatch.expression); 1794 DartType caseType = analyze(caseMatch.expression);
1788 checkAssignable(caseMatch, expressionType, caseType); 1795 checkAssignable(caseMatch, expressionType, caseType);
1789 } 1796 }
1790 1797
1791 analyze(switchCase); 1798 analyze(switchCase);
1792 } 1799 }
1793 1800
1794 if (!hasDefaultCase && expressionType.isEnumType) { 1801 if (!hasDefaultCase && expressionType.isEnumType) {
1795 compiler.enqueuer.resolution.addDeferredAction( 1802 compiler.enqueuer.resolution.addDeferredAction(executableContext, () {
1796 elements.analyzedElement, () {
1797 Map<ConstantValue, FieldElement> enumValues = 1803 Map<ConstantValue, FieldElement> enumValues =
1798 <ConstantValue, FieldElement>{}; 1804 <ConstantValue, FieldElement>{};
1799 List<FieldElement> unreferencedFields = <FieldElement>[]; 1805 List<FieldElement> unreferencedFields = <FieldElement>[];
1800 EnumClassElement enumClass = expressionType.element; 1806 EnumClassElement enumClass = expressionType.element;
1801 enumClass.enumValues.forEach((FieldElement field) { 1807 enumClass.enumValues.forEach((FieldElement field) {
1802 ConstantExpression constantExpression = 1808 ConstantExpression constantExpression =
1803 compiler.constants.getConstantForVariable(field); 1809 compiler.constants.getConstantForVariable(field);
1804 if (constantExpression == null) { 1810 if (constantExpression == null) {
1805 // The field might not have been resolved. 1811 // The field might not have been resolved.
1806 unreferencedFields.add(field); 1812 unreferencedFields.add(field);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1854 1860
1855 visitTypedef(Typedef node) { 1861 visitTypedef(Typedef node) {
1856 // Do not typecheck [Typedef] nodes. 1862 // Do not typecheck [Typedef] nodes.
1857 } 1863 }
1858 1864
1859 visitNode(Node node) { 1865 visitNode(Node node) {
1860 compiler.internalError(node, 1866 compiler.internalError(node,
1861 'Unexpected node ${node.getObjectDescription()} in the type checker.'); 1867 'Unexpected node ${node.getObjectDescription()} in the type checker.');
1862 } 1868 }
1863 } 1869 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/tree/nodes.dart ('k') | pkg/compiler/lib/src/warnings.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698