| OLD | NEW |
| 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 library dart2js.typechecker; | 5 library dart2js.typechecker; |
| 6 | 6 |
| 7 import 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
| 8 import 'common/resolution.dart' show Resolution; | 8 import 'common/resolution.dart' show Resolution; |
| 9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
| 10 import 'common.dart'; | 10 import 'common.dart'; |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 } | 639 } |
| 640 | 640 |
| 641 visitFunctionDeclaration(FunctionDeclaration node) { | 641 visitFunctionDeclaration(FunctionDeclaration node) { |
| 642 analyze(node.function); | 642 analyze(node.function); |
| 643 } | 643 } |
| 644 | 644 |
| 645 ResolutionDartType visitFunctionExpression(FunctionExpression node) { | 645 ResolutionDartType visitFunctionExpression(FunctionExpression node) { |
| 646 ResolutionDartType type; | 646 ResolutionDartType type; |
| 647 ResolutionDartType returnType; | 647 ResolutionDartType returnType; |
| 648 final FunctionElement element = elements.getFunctionDefinition(node); | 648 final FunctionElement element = elements.getFunctionDefinition(node); |
| 649 assert(invariant(node, element != null, | 649 assert( |
| 650 message: 'FunctionExpression with no element')); | 650 element != null, failedAt(node, 'FunctionExpression with no element')); |
| 651 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); | 651 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); |
| 652 if (element.isGenerativeConstructor) { | 652 if (element.isGenerativeConstructor) { |
| 653 type = const ResolutionDynamicType(); | 653 type = const ResolutionDynamicType(); |
| 654 returnType = const ResolutionVoidType(); | 654 returnType = const ResolutionVoidType(); |
| 655 | 655 |
| 656 element.functionSignature.forEachParameter((ParameterElement parameter) { | 656 element.functionSignature.forEachParameter((ParameterElement parameter) { |
| 657 if (parameter.isInitializingFormal) { | 657 if (parameter.isInitializingFormal) { |
| 658 InitializingFormalElement fieldParameter = parameter; | 658 InitializingFormalElement fieldParameter = parameter; |
| 659 checkAssignable(parameter, parameter.type, | 659 checkAssignable(parameter, parameter.type, |
| 660 fieldParameter.fieldElement.computeType(resolution)); | 660 fieldParameter.fieldElement.computeType(resolution)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 683 return type; | 683 return type; |
| 684 } | 684 } |
| 685 | 685 |
| 686 ResolutionDartType visitIdentifier(Identifier node) { | 686 ResolutionDartType visitIdentifier(Identifier node) { |
| 687 if (node.isThis()) { | 687 if (node.isThis()) { |
| 688 return thisType; | 688 return thisType; |
| 689 } else if (node.isSuper()) { | 689 } else if (node.isSuper()) { |
| 690 return superType; | 690 return superType; |
| 691 } else { | 691 } else { |
| 692 TypedElement element = elements[node]; | 692 TypedElement element = elements[node]; |
| 693 assert(invariant(node, element != null, | 693 assert(element != null, failedAt(node, 'Missing element for identifier')); |
| 694 message: 'Missing element for identifier')); | 694 assert(element.isVariable || element.isParameter || element.isField, |
| 695 assert(invariant( | 695 failedAt(node, 'Unexpected context element ${element}')); |
| 696 node, element.isVariable || element.isParameter || element.isField, | |
| 697 message: 'Unexpected context element ${element}')); | |
| 698 return element.computeType(resolution); | 696 return element.computeType(resolution); |
| 699 } | 697 } |
| 700 } | 698 } |
| 701 | 699 |
| 702 visitIf(If node) { | 700 visitIf(If node) { |
| 703 Expression condition = node.condition.expression; | 701 Expression condition = node.condition.expression; |
| 704 Statement thenPart = node.thenPart; | 702 Statement thenPart = node.thenPart; |
| 705 | 703 |
| 706 checkCondition(node.condition); | 704 checkCondition(node.condition); |
| 707 analyzeInPromotedContext(condition, thenPart, mustHaveType: false); | 705 analyzeInPromotedContext(condition, thenPart, mustHaveType: false); |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1021 return const DynamicAccess(); | 1019 return const DynamicAccess(); |
| 1022 } | 1020 } |
| 1023 if (node.receiver != null) { | 1021 if (node.receiver != null) { |
| 1024 Element receiverElement = elements[node.receiver]; | 1022 Element receiverElement = elements[node.receiver]; |
| 1025 if (receiverElement != null) { | 1023 if (receiverElement != null) { |
| 1026 if (receiverElement.isPrefix) { | 1024 if (receiverElement.isPrefix) { |
| 1027 if (node.isConditional) { | 1025 if (node.isConditional) { |
| 1028 // Skip cases like `prefix?.topLevel`. | 1026 // Skip cases like `prefix?.topLevel`. |
| 1029 return const DynamicAccess(); | 1027 return const DynamicAccess(); |
| 1030 } | 1028 } |
| 1031 assert(invariant(node, element != null, | 1029 assert( |
| 1032 message: 'Prefixed node has no element.')); | 1030 element != null, failedAt(node, 'Prefixed node has no element.')); |
| 1033 return computeResolvedAccess(node, name, element, memberKind); | 1031 return computeResolvedAccess(node, name, element, memberKind); |
| 1034 } | 1032 } |
| 1035 } | 1033 } |
| 1036 // e.foo() for some expression e. | 1034 // e.foo() for some expression e. |
| 1037 ResolutionDartType receiverType = analyze(node.receiver); | 1035 ResolutionDartType receiverType = analyze(node.receiver); |
| 1038 if (receiverType.treatAsDynamic || receiverType.isVoid) { | 1036 if (receiverType.treatAsDynamic || receiverType.isVoid) { |
| 1039 return const DynamicAccess(); | 1037 return const DynamicAccess(); |
| 1040 } | 1038 } |
| 1041 return lookupMember( | 1039 return lookupMember( |
| 1042 node, receiverType, name, memberKind, elements[node.receiver], | 1040 node, receiverType, name, memberKind, elements[node.receiver], |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 return const ResolutionDynamicType(); | 1170 return const ResolutionDynamicType(); |
| 1173 } | 1171 } |
| 1174 | 1172 |
| 1175 Identifier selector = node.selector.asIdentifier(); | 1173 Identifier selector = node.selector.asIdentifier(); |
| 1176 if (Elements.isClosureSend(node, element)) { | 1174 if (Elements.isClosureSend(node, element)) { |
| 1177 if (element != null) { | 1175 if (element != null) { |
| 1178 if (element.isError) { | 1176 if (element.isError) { |
| 1179 // foo() where foo is erroneous | 1177 // foo() where foo is erroneous |
| 1180 return analyzeInvocation(node, const DynamicAccess()); | 1178 return analyzeInvocation(node, const DynamicAccess()); |
| 1181 } else { | 1179 } else { |
| 1182 assert(invariant(node, element.isLocal, | 1180 assert(element.isLocal, |
| 1183 message: "Unexpected element $element in closure send.")); | 1181 failedAt(node, "Unexpected element $element in closure send.")); |
| 1184 // foo() where foo is a local or a parameter. | 1182 // foo() where foo is a local or a parameter. |
| 1185 return analyzeInvocation(node, createPromotedAccess(element)); | 1183 return analyzeInvocation(node, createPromotedAccess(element)); |
| 1186 } | 1184 } |
| 1187 } else { | 1185 } else { |
| 1188 // exp() where exp is some complex expression like (o) or foo(). | 1186 // exp() where exp is some complex expression like (o) or foo(). |
| 1189 ResolutionDartType type = analyze(node.selector); | 1187 ResolutionDartType type = analyze(node.selector); |
| 1190 return analyzeInvocation(node, new TypeAccess(type)); | 1188 return analyzeInvocation(node, new TypeAccess(type)); |
| 1191 } | 1189 } |
| 1192 } else if (Elements.isMalformed(element) && selector == null) { | 1190 } else if (Elements.isMalformed(element) && selector == null) { |
| 1193 // exp() where exp is an erroneous construct like `new Unresolved()`. | 1191 // exp() where exp is an erroneous construct like `new Unresolved()`. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 return boolType; | 1292 return boolType; |
| 1295 } else if (identical(name, '??')) { | 1293 } else if (identical(name, '??')) { |
| 1296 final Node argument = node.arguments.head; | 1294 final Node argument = node.arguments.head; |
| 1297 final ResolutionDartType argumentType = analyze(argument); | 1295 final ResolutionDartType argumentType = analyze(argument); |
| 1298 return types.computeLeastUpperBound(receiverType, argumentType); | 1296 return types.computeLeastUpperBound(receiverType, argumentType); |
| 1299 } | 1297 } |
| 1300 String operatorName = selector.source; | 1298 String operatorName = selector.source; |
| 1301 if (identical(name, '-') && node.arguments.isEmpty) { | 1299 if (identical(name, '-') && node.arguments.isEmpty) { |
| 1302 operatorName = 'unary-'; | 1300 operatorName = 'unary-'; |
| 1303 } | 1301 } |
| 1304 assert(invariant( | 1302 assert( |
| 1305 node, | |
| 1306 identical(name, '+') || | 1303 identical(name, '+') || |
| 1307 identical(name, '=') || | 1304 identical(name, '=') || |
| 1308 identical(name, '-') || | 1305 identical(name, '-') || |
| 1309 identical(name, '*') || | 1306 identical(name, '*') || |
| 1310 identical(name, '/') || | 1307 identical(name, '/') || |
| 1311 identical(name, '%') || | 1308 identical(name, '%') || |
| 1312 identical(name, '~/') || | 1309 identical(name, '~/') || |
| 1313 identical(name, '|') || | 1310 identical(name, '|') || |
| 1314 identical(name, '&') || | 1311 identical(name, '&') || |
| 1315 identical(name, '^') || | 1312 identical(name, '^') || |
| 1316 identical(name, '~') || | 1313 identical(name, '~') || |
| 1317 identical(name, '<<') || | 1314 identical(name, '<<') || |
| 1318 identical(name, '>>') || | 1315 identical(name, '>>') || |
| 1319 identical(name, '<') || | 1316 identical(name, '<') || |
| 1320 identical(name, '>') || | 1317 identical(name, '>') || |
| 1321 identical(name, '<=') || | 1318 identical(name, '<=') || |
| 1322 identical(name, '>=') || | 1319 identical(name, '>=') || |
| 1323 identical(name, '[]'), | 1320 identical(name, '[]'), |
| 1324 message: 'Unexpected operator $name')); | 1321 failedAt(node, 'Unexpected operator $name')); |
| 1325 | 1322 |
| 1326 // TODO(karlklose): handle `void` in expression context by calling | 1323 // TODO(karlklose): handle `void` in expression context by calling |
| 1327 // [analyzeNonVoid] instead of [analyze]. | 1324 // [analyzeNonVoid] instead of [analyze]. |
| 1328 ElementAccess access = receiverType.isVoid | 1325 ElementAccess access = receiverType.isVoid |
| 1329 ? const DynamicAccess() | 1326 ? const DynamicAccess() |
| 1330 : lookupMember( | 1327 : lookupMember( |
| 1331 node, receiverType, operatorName, MemberKind.OPERATOR, null); | 1328 node, receiverType, operatorName, MemberKind.OPERATOR, null); |
| 1332 LinkBuilder<ResolutionDartType> argumentTypesBuilder = | 1329 LinkBuilder<ResolutionDartType> argumentTypesBuilder = |
| 1333 new LinkBuilder<ResolutionDartType>(); | 1330 new LinkBuilder<ResolutionDartType>(); |
| 1334 ResolutionDartType resultType = | 1331 ResolutionDartType resultType = |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 return list.length < 2 ? const ResolutionDynamicType() : list[1]; | 1370 return list.length < 2 ? const ResolutionDynamicType() : list[1]; |
| 1374 } | 1371 } |
| 1375 | 1372 |
| 1376 /** | 1373 /** |
| 1377 * Checks [: target o= value :] for some operator o, and returns the type | 1374 * Checks [: target o= value :] for some operator o, and returns the type |
| 1378 * of the result. This method also handles increment/decrement expressions | 1375 * of the result. This method also handles increment/decrement expressions |
| 1379 * like [: target++ :]. | 1376 * like [: target++ :]. |
| 1380 */ | 1377 */ |
| 1381 ResolutionDartType checkAssignmentOperator(SendSet node, String operatorName, | 1378 ResolutionDartType checkAssignmentOperator(SendSet node, String operatorName, |
| 1382 Node valueNode, ResolutionDartType value) { | 1379 Node valueNode, ResolutionDartType value) { |
| 1383 assert(invariant(node, !node.isIndex)); | 1380 assert(!node.isIndex, failedAt(node)); |
| 1384 Element setterElement = elements[node]; | 1381 Element setterElement = elements[node]; |
| 1385 Element getterElement = elements[node.selector]; | 1382 Element getterElement = elements[node.selector]; |
| 1386 Identifier selector = node.selector; | 1383 Identifier selector = node.selector; |
| 1387 ResolutionDartType getter = computeAccessType( | 1384 ResolutionDartType getter = computeAccessType( |
| 1388 node, selector.source, getterElement, MemberKind.GETTER); | 1385 node, selector.source, getterElement, MemberKind.GETTER); |
| 1389 ResolutionDartType setter = computeAccessType( | 1386 ResolutionDartType setter = computeAccessType( |
| 1390 node, selector.source, setterElement, MemberKind.SETTER); | 1387 node, selector.source, setterElement, MemberKind.SETTER); |
| 1391 // [operator] is the type of operator+ or operator- on [target]. | 1388 // [operator] is the type of operator+ or operator- on [target]. |
| 1392 ResolutionDartType operator = | 1389 ResolutionDartType operator = |
| 1393 lookupMemberType(node, getter, operatorName, MemberKind.OPERATOR); | 1390 lookupMemberType(node, getter, operatorName, MemberKind.OPERATOR); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1408 return const ResolutionDynamicType(); | 1405 return const ResolutionDynamicType(); |
| 1409 } | 1406 } |
| 1410 | 1407 |
| 1411 /** | 1408 /** |
| 1412 * Checks [: base[key] o= value :] for some operator o, and returns the type | 1409 * Checks [: base[key] o= value :] for some operator o, and returns the type |
| 1413 * of the result. This method also handles increment/decrement expressions | 1410 * of the result. This method also handles increment/decrement expressions |
| 1414 * like [: base[key]++ :]. | 1411 * like [: base[key]++ :]. |
| 1415 */ | 1412 */ |
| 1416 ResolutionDartType checkIndexAssignmentOperator(SendSet node, | 1413 ResolutionDartType checkIndexAssignmentOperator(SendSet node, |
| 1417 String operatorName, Node valueNode, ResolutionDartType value) { | 1414 String operatorName, Node valueNode, ResolutionDartType value) { |
| 1418 assert(invariant(node, node.isIndex)); | 1415 assert(node.isIndex, failedAt(node)); |
| 1419 final ResolutionDartType base = analyze(node.receiver); | 1416 final ResolutionDartType base = analyze(node.receiver); |
| 1420 final Node keyNode = node.arguments.head; | 1417 final Node keyNode = node.arguments.head; |
| 1421 final ResolutionDartType key = analyze(keyNode); | 1418 final ResolutionDartType key = analyze(keyNode); |
| 1422 | 1419 |
| 1423 // [indexGet] is the type of operator[] on [base]. | 1420 // [indexGet] is the type of operator[] on [base]. |
| 1424 ResolutionDartType indexGet = | 1421 ResolutionDartType indexGet = |
| 1425 lookupMemberType(node, base, '[]', MemberKind.OPERATOR); | 1422 lookupMemberType(node, base, '[]', MemberKind.OPERATOR); |
| 1426 if (indexGet is ResolutionFunctionType) { | 1423 if (indexGet is ResolutionFunctionType) { |
| 1427 ResolutionFunctionType indexGetType = indexGet; | 1424 ResolutionFunctionType indexGetType = indexGet; |
| 1428 ResolutionDartType indexGetKey = firstType(indexGetType.parameterTypes); | 1425 ResolutionDartType indexGetKey = firstType(indexGetType.parameterTypes); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1640 return constructorType; | 1637 return constructorType; |
| 1641 } | 1638 } |
| 1642 | 1639 |
| 1643 ResolutionDartType visitNewExpression(NewExpression node) { | 1640 ResolutionDartType visitNewExpression(NewExpression node) { |
| 1644 Element element = elements[node.send]; | 1641 Element element = elements[node.send]; |
| 1645 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); | 1642 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); |
| 1646 | 1643 |
| 1647 checkPrivateAccess(node, element, element.name); | 1644 checkPrivateAccess(node, element, element.name); |
| 1648 | 1645 |
| 1649 ResolutionDartType newType = elements.getType(node); | 1646 ResolutionDartType newType = elements.getType(node); |
| 1650 assert(invariant(node, newType != null, | 1647 assert(newType != null, |
| 1651 message: "No new type registered in $elements.")); | 1648 failedAt(node, "No new type registered in $elements.")); |
| 1652 ResolutionDartType constructorType = | 1649 ResolutionDartType constructorType = |
| 1653 computeConstructorType(element, newType); | 1650 computeConstructorType(element, newType); |
| 1654 analyzeArguments(node.send, element, constructorType); | 1651 analyzeArguments(node.send, element, constructorType); |
| 1655 return newType; | 1652 return newType; |
| 1656 } | 1653 } |
| 1657 | 1654 |
| 1658 ResolutionDartType visitLiteralList(LiteralList node) { | 1655 ResolutionDartType visitLiteralList(LiteralList node) { |
| 1659 ResolutionInterfaceType listType = elements.getType(node); | 1656 ResolutionInterfaceType listType = elements.getType(node); |
| 1660 ResolutionDartType listElementType = firstType(listType.typeArguments); | 1657 ResolutionDartType listElementType = firstType(listType.typeArguments); |
| 1661 for (Link<Node> link = node.elements.nodes; | 1658 for (Link<Node> link = node.elements.nodes; |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1792 ResolutionDartType expressionType = analyzeNonVoid(initializer); | 1789 ResolutionDartType expressionType = analyzeNonVoid(initializer); |
| 1793 checkAssignable(spannable, expressionType, declaredType); | 1790 checkAssignable(spannable, expressionType, declaredType); |
| 1794 } | 1791 } |
| 1795 | 1792 |
| 1796 visitVariableDefinitions(VariableDefinitions node) { | 1793 visitVariableDefinitions(VariableDefinitions node) { |
| 1797 ResolutionDartType type = analyzeVariableTypeAnnotation(node); | 1794 ResolutionDartType type = analyzeVariableTypeAnnotation(node); |
| 1798 for (Link<Node> link = node.definitions.nodes; | 1795 for (Link<Node> link = node.definitions.nodes; |
| 1799 !link.isEmpty; | 1796 !link.isEmpty; |
| 1800 link = link.tail) { | 1797 link = link.tail) { |
| 1801 Node definition = link.head; | 1798 Node definition = link.head; |
| 1802 invariant(definition, definition is Identifier || definition is SendSet, | 1799 assert(definition is Identifier || definition is SendSet, |
| 1803 message: 'expected identifier or initialization'); | 1800 failedAt(definition, 'expected identifier or initialization')); |
| 1804 if (definition is SendSet) { | 1801 if (definition is SendSet) { |
| 1805 SendSet initialization = definition; | 1802 SendSet initialization = definition; |
| 1806 analyzeVariableInitializer(initialization.assignmentOperator, type, | 1803 analyzeVariableInitializer(initialization.assignmentOperator, type, |
| 1807 initialization.arguments.head); | 1804 initialization.arguments.head); |
| 1808 // TODO(sigmund): explore inferring a type for `var` using the RHS (like | 1805 // TODO(sigmund): explore inferring a type for `var` using the RHS (like |
| 1809 // DDC does), for example: | 1806 // DDC does), for example: |
| 1810 // if (node.type == null && node.modifiers.isVar && | 1807 // if (node.type == null && node.modifiers.isVar && |
| 1811 // !initializer.isDynamic) { | 1808 // !initializer.isDynamic) { |
| 1812 // var variable = elements[definition]; | 1809 // var variable = elements[definition]; |
| 1813 // if (variable != null) { | 1810 // if (variable != null) { |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2057 | 2054 |
| 2058 visitTypedef(Typedef node) { | 2055 visitTypedef(Typedef node) { |
| 2059 // Do not typecheck [Typedef] nodes. | 2056 // Do not typecheck [Typedef] nodes. |
| 2060 } | 2057 } |
| 2061 | 2058 |
| 2062 visitNode(Node node) { | 2059 visitNode(Node node) { |
| 2063 reporter.internalError(node, | 2060 reporter.internalError(node, |
| 2064 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 2061 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
| 2065 } | 2062 } |
| 2066 } | 2063 } |
| OLD | NEW |