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

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: Allow return; in generators. 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
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 /// Returns [: true :] if the element can be access as an invocation. 54 /// Returns [: true :] if the element can be access as an invocation.
55 bool isCallable(Compiler compiler) { 55 bool isCallable(Compiler compiler) {
56 if (element != null && element.isAbstractField) { 56 if (element != null && element.isAbstractField) {
57 AbstractFieldElement abstractFieldElement = element; 57 AbstractFieldElement abstractFieldElement = element;
58 if (abstractFieldElement.getter == null) { 58 if (abstractFieldElement.getter == null) {
59 // Setters cannot be invoked as function invocations. 59 // Setters cannot be invoked as function invocations.
60 return false; 60 return false;
61 } 61 }
62 } 62 }
63 return compiler.types.isAssignable( 63 return compiler.types.isAssignable(
64 computeType(compiler), compiler.functionClass.computeType(compiler)); 64 computeType(compiler), compiler.coreTypes.functionType);
65 } 65 }
66 } 66 }
67 67
68 /// An access of a instance member. 68 /// An access of a instance member.
69 class MemberAccess extends ElementAccess { 69 class MemberAccess extends ElementAccess {
70 final MemberSignature member; 70 final MemberSignature member;
71 71
72 MemberAccess(MemberSignature this.member); 72 MemberAccess(MemberSignature this.member);
73 73
74 Element get element => member.declarations.first.element; 74 Element get element => member.declarations.first.element;
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 final Compiler compiler; 257 final Compiler compiler;
258 final TreeElements elements; 258 final TreeElements elements;
259 final Types types; 259 final Types types;
260 260
261 Node lastSeenNode; 261 Node lastSeenNode;
262 DartType expectedReturnType; 262 DartType expectedReturnType;
263 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; 263 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC;
264 264
265 final ClassElement currentClass; 265 final ClassElement currentClass;
266 266
267 /// The immediately enclosing field, method or constructor being analyzed.
268 ExecutableElement executableContext;
269
270 CoreTypes get coreTypes => compiler.coreTypes;
271
272 InterfaceType get intType => coreTypes.intType;
273 InterfaceType get doubleType => coreTypes.doubleType;
274 InterfaceType get boolType => coreTypes.boolType;
275 InterfaceType get stringType => coreTypes.stringType;
276
267 DartType thisType; 277 DartType thisType;
268 DartType superType; 278 DartType superType;
269 279
270 Link<DartType> cascadeTypes = const Link<DartType>(); 280 Link<DartType> cascadeTypes = const Link<DartType>();
271 281
272 bool analyzingInitializer = false; 282 bool analyzingInitializer = false;
273 283
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 = 284 Map<Node, List<TypePromotion>> shownTypePromotionsMap =
282 new Map<Node, List<TypePromotion>>(); 285 new Map<Node, List<TypePromotion>>();
283 286
284 Map<VariableElement, Link<TypePromotion>> typePromotionsMap = 287 Map<VariableElement, Link<TypePromotion>> typePromotionsMap =
285 new Map<VariableElement, Link<TypePromotion>>(); 288 new Map<VariableElement, Link<TypePromotion>>();
286 289
287 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); 290 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>();
288 291
289 void showTypePromotion(Node node, TypePromotion typePromotion) { 292 void showTypePromotion(Node node, TypePromotion typePromotion) {
290 List<TypePromotion> shownTypePromotions = 293 List<TypePromotion> shownTypePromotions =
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 } 333 }
331 334
332 DartType getKnownType(VariableElement element) { 335 DartType getKnownType(VariableElement element) {
333 TypePromotion typePromotion = getKnownTypePromotion(element); 336 TypePromotion typePromotion = getKnownTypePromotion(element);
334 if (typePromotion != null) return typePromotion.type; 337 if (typePromotion != null) return typePromotion.type;
335 return element.type; 338 return element.type;
336 } 339 }
337 340
338 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) 341 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types)
339 : this.elements = elements, 342 : this.elements = elements,
340 currentClass = elements.analyzedElement != null 343 this.executableContext = elements.analyzedElement,
344 this.currentClass = elements.analyzedElement != null
341 ? elements.analyzedElement.enclosingClass : null { 345 ? 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 346
349 if (currentClass != null) { 347 if (currentClass != null) {
350 thisType = currentClass.thisType; 348 thisType = currentClass.thisType;
351 superType = currentClass.supertype; 349 superType = currentClass.supertype;
352 } else { 350 } else {
353 // If these are used, an error should have been reported by the resolver. 351 // If these are used, an error should have been reported by the resolver.
354 thisType = const DynamicType(); 352 thisType = const DynamicType();
355 superType = const DynamicType(); 353 superType = const DynamicType();
356 } 354 }
357 } 355 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 } 402 }
405 403
406 /// If [inInitializer] is true, assignment should be interpreted as write to 404 /// If [inInitializer] is true, assignment should be interpreted as write to
407 /// a field and not to a setter. 405 /// a field and not to a setter.
408 DartType analyze(Node node, {bool inInitializer: false}) { 406 DartType analyze(Node node, {bool inInitializer: false}) {
409 if (node == null) { 407 if (node == null) {
410 final String error = 'Unexpected node: null'; 408 final String error = 'Unexpected node: null';
411 if (lastSeenNode != null) { 409 if (lastSeenNode != null) {
412 compiler.internalError(lastSeenNode, error); 410 compiler.internalError(lastSeenNode, error);
413 } else { 411 } else {
414 compiler.internalError(elements.analyzedElement, error); 412 compiler.internalError(executableContext, error);
415 } 413 }
416 } else { 414 } else {
417 lastSeenNode = node; 415 lastSeenNode = node;
418 } 416 }
419 bool previouslyInitializer = analyzingInitializer; 417 bool previouslyInitializer = analyzingInitializer;
420 analyzingInitializer = inInitializer; 418 analyzingInitializer = inInitializer;
421 DartType result = node.accept(this); 419 DartType result = node.accept(this);
422 analyzingInitializer = previouslyInitializer; 420 analyzingInitializer = previouslyInitializer;
423 if (result == null) { 421 if (result == null) {
424 compiler.internalError(node, 'Type is null.'); 422 compiler.internalError(node, 'Type is null.');
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 } 590 }
593 591
594 DartType visitFunctionExpression(FunctionExpression node) { 592 DartType visitFunctionExpression(FunctionExpression node) {
595 DartType type; 593 DartType type;
596 DartType returnType; 594 DartType returnType;
597 DartType previousType; 595 DartType previousType;
598 final FunctionElement element = elements.getFunctionDefinition(node); 596 final FunctionElement element = elements.getFunctionDefinition(node);
599 assert(invariant(node, element != null, 597 assert(invariant(node, element != null,
600 message: 'FunctionExpression with no element')); 598 message: 'FunctionExpression with no element'));
601 if (Elements.isUnresolved(element)) return const DynamicType(); 599 if (Elements.isUnresolved(element)) return const DynamicType();
602 if (identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR) || 600 if (element.isGenerativeConstructor) {
603 identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY)) {
604 type = const DynamicType(); 601 type = const DynamicType();
605 returnType = const VoidType(); 602 returnType = const VoidType();
606 603
607 element.functionSignature.forEachParameter((ParameterElement parameter) { 604 element.functionSignature.forEachParameter((ParameterElement parameter) {
608 if (parameter.isInitializingFormal) { 605 if (parameter.isInitializingFormal) {
609 InitializingFormalElement fieldParameter = parameter; 606 InitializingFormalElement fieldParameter = parameter;
610 checkAssignable(parameter, parameter.type, 607 checkAssignable(parameter, parameter.type,
611 fieldParameter.fieldElement.computeType(compiler)); 608 fieldParameter.fieldElement.computeType(compiler));
612 } 609 }
613 }); 610 });
614 if (node.initializers != null) { 611 if (node.initializers != null) {
615 analyze(node.initializers, inInitializer: true); 612 analyze(node.initializers, inInitializer: true);
616 } 613 }
617 } else { 614 } else {
618 FunctionType functionType = element.computeType(compiler); 615 FunctionType functionType = element.computeType(compiler);
619 returnType = functionType.returnType; 616 returnType = functionType.returnType;
620 type = functionType; 617 type = functionType;
621 } 618 }
619 ExecutableElement previousExecutableContext = executableContext;
622 DartType previousReturnType = expectedReturnType; 620 DartType previousReturnType = expectedReturnType;
623 expectedReturnType = returnType; 621 expectedReturnType = returnType;
624 AsyncMarker previousAsyncMarker = currentAsyncMarker; 622 AsyncMarker previousAsyncMarker = currentAsyncMarker;
623
624 executableContext = element;
625 currentAsyncMarker = element.asyncMarker; 625 currentAsyncMarker = element.asyncMarker;
626 analyze(node.body); 626 analyze(node.body);
627
628 executableContext = previousExecutableContext;
627 expectedReturnType = previousReturnType; 629 expectedReturnType = previousReturnType;
628 currentAsyncMarker = previousAsyncMarker; 630 currentAsyncMarker = previousAsyncMarker;
629 return type; 631 return type;
630 } 632 }
631 633
632 DartType visitIdentifier(Identifier node) { 634 DartType visitIdentifier(Identifier node) {
633 if (node.isThis()) { 635 if (node.isThis()) {
634 return thisType; 636 return thisType;
635 } else if (node.isSuper()) { 637 } else if (node.isSuper()) {
636 return superType; 638 return superType;
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 DartType visitRethrow(Rethrow node) { 1570 DartType visitRethrow(Rethrow node) {
1569 return const StatementType(); 1571 return const StatementType();
1570 } 1572 }
1571 1573
1572 /** Dart Programming Language Specification: 11.10 Return */ 1574 /** Dart Programming Language Specification: 11.10 Return */
1573 DartType visitReturn(Return node) { 1575 DartType visitReturn(Return node) {
1574 if (identical(node.beginToken.stringValue, 'native')) { 1576 if (identical(node.beginToken.stringValue, 'native')) {
1575 return const StatementType(); 1577 return const StatementType();
1576 } 1578 }
1577 1579
1578 final expression = node.expression; 1580 final Node expression = node.expression;
1579 final isVoidFunction = expectedReturnType.isVoid;
1580 1581
1581 // Executing a return statement return e; [...] It is a static type warning 1582 // 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 1583 // if the type of e may not be assigned to the declared return type of the
1583 // immediately enclosing function. 1584 // immediately enclosing function.
1584 if (expression != null) { 1585 if (expression != null) {
1585 final expressionType = analyze(expression); 1586 DartType expressionType = analyze(expression);
1586 Element element = elements.analyzedElement; 1587 if (executableContext.isGenerativeConstructor) {
1587 if (element != null && element.isGenerativeConstructor) {
1588 // The resolver already emitted an error for this expression. 1588 // 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 { 1589 } else {
1593 checkAssignable(expression, expressionType, expectedReturnType); 1590 switch (currentAsyncMarker) {
1591 case AsyncMarker.ASYNC:
floitsch 2015/02/26 15:24:14 No need for a switch.
Johnni Winther 2015/03/02 10:30:58 Done.
1592 expressionType = coreTypes.futureType(flatten(expressionType));
1593 break;
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();
1612 } 1619 }
1613 1620
1614 /// Flatten [type] by recursively removing enclosing `Future` annotations. 1621 /// Flatten [type] by recursively removing enclosing `Future` annotations.
1615 /// 1622 ///
1616 /// For instance: 1623 /// For instance:
1617 /// flatten(T) = T 1624 /// flatten(T) = T
1618 /// flatten(Future<T>) = T 1625 /// flatten(Future<T>) = T
1619 /// flatten(Future<Future<T>>) = T 1626 /// flatten(Future<Future<T>>) = T
1620 /// 1627 ///
1621 /// This method is used in the static typing of await and type checking of 1628 /// This method is used in the static typing of await and type checking of
1622 /// return. 1629 /// return.
1623 DartType flatten(DartType type) { 1630 DartType flatten(DartType type) {
1624 if (type is InterfaceType) { 1631 if (type is InterfaceType) {
1625 InterfaceType futureType = type.asInstanceOf(compiler.futureClass); 1632 InterfaceType futureType = type.asInstanceOf(coreTypes.futureClass);
1626 if (futureType != null) { 1633 if (futureType != null) {
1627 return flatten(futureType.typeArguments.first); 1634 return flatten(futureType.typeArguments.first);
1628 } 1635 }
1629 } 1636 }
1630 return type; 1637 return type;
1631 } 1638 }
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