Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 simple_types_inferrer; | 5 library simple_types_inferrer; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue, LinkedHashSet; | 7 import 'dart:collection' show Queue, LinkedHashSet; |
| 8 | 8 |
| 9 import '../closure.dart' show ClosureClassMap, ClosureScope; | 9 import '../closure.dart' show ClosureClassMap, ClosureScope; |
| 10 import '../dart_types.dart' show DartType, FunctionType, TypeKind; | 10 import '../dart_types.dart' show DartType, FunctionType, TypeKind; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 SentinelTypeMask(this.name) : super(null, 0, false); | 106 SentinelTypeMask(this.name) : super(null, 0, false); |
| 107 | 107 |
| 108 bool operator==(other) { | 108 bool operator==(other) { |
| 109 return identical(this, other); | 109 return identical(this, other); |
| 110 } | 110 } |
| 111 | 111 |
| 112 TypeMask nullable() { | 112 TypeMask nullable() { |
| 113 throw 'Unsupported operation'; | 113 throw 'Unsupported operation'; |
| 114 } | 114 } |
| 115 | 115 |
| 116 TypeMask intersection(TypeMask other, Compiler compiler) { | |
| 117 return other; | |
| 118 } | |
| 119 | |
| 116 bool get isNullable => true; | 120 bool get isNullable => true; |
| 117 | 121 |
| 118 String toString() => '$name sentinel type mask'; | 122 String toString() => '$name sentinel type mask'; |
| 119 } | 123 } |
| 120 | 124 |
| 121 final OPTIMISTIC = 0; | 125 final OPTIMISTIC = 0; |
| 122 final RETRY = 1; | 126 final RETRY = 1; |
| 123 final PESSIMISTIC = 2; | 127 final PESSIMISTIC = 2; |
| 124 | 128 |
| 125 class SimpleTypesInferrer extends TypesInferrer { | 129 class SimpleTypesInferrer extends TypesInferrer { |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 bool isNativeElement(Element element) { | 646 bool isNativeElement(Element element) { |
| 643 if (element.isNative()) return true; | 647 if (element.isNative()) return true; |
| 644 return element.isMember() | 648 return element.isMember() |
| 645 && element.getEnclosingClass().isNative() | 649 && element.getEnclosingClass().isNative() |
| 646 && element.isField(); | 650 && element.isField(); |
| 647 } | 651 } |
| 648 | 652 |
| 649 bool internalRecordType(Element analyzedElement, | 653 bool internalRecordType(Element analyzedElement, |
| 650 TypeMask newType, | 654 TypeMask newType, |
| 651 Map<Element, TypeMask> types) { | 655 Map<Element, TypeMask> types) { |
| 656 if (compiler.trustTypeAnnotations) { | |
| 657 var annotation = analyzedElement.computeType(compiler); | |
| 658 if (types == returnTypeOf) { | |
| 659 assert(annotation is FunctionType); | |
| 660 annotation = annotation.returnType; | |
| 661 } | |
| 662 newType = narrowType(newType, annotation); | |
| 663 } | |
| 664 | |
| 652 // Fields and native methods of native classes are handled | 665 // Fields and native methods of native classes are handled |
| 653 // specially when querying for their type or return type. | 666 // specially when querying for their type or return type. |
| 654 if (isNativeElement(analyzedElement)) return false; | 667 if (isNativeElement(analyzedElement)) return false; |
| 655 assert(newType != null); | 668 assert(newType != null); |
| 656 TypeMask existing = types[analyzedElement]; | 669 TypeMask existing = types[analyzedElement]; |
| 657 types[analyzedElement] = newType; | 670 types[analyzedElement] = newType; |
| 658 // If the return type is useful, say it has changed. | 671 // If the return type is useful, say it has changed. |
| 659 return existing != newType | 672 return existing != newType |
| 660 && !isDynamicType(newType) | 673 && !isDynamicType(newType) |
| 661 && newType != nullType; | 674 && newType != nullType; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 677 var elementType = element.computeType(compiler); | 690 var elementType = element.computeType(compiler); |
| 678 if (elementType.kind != TypeKind.FUNCTION) { | 691 if (elementType.kind != TypeKind.FUNCTION) { |
| 679 return dynamicType; | 692 return dynamicType; |
| 680 } | 693 } |
| 681 return typeOfNativeBehavior( | 694 return typeOfNativeBehavior( |
| 682 native.NativeBehavior.ofMethod(element, compiler)); | 695 native.NativeBehavior.ofMethod(element, compiler)); |
| 683 }); | 696 }); |
| 684 } | 697 } |
| 685 TypeMask returnType = returnTypeOf[element]; | 698 TypeMask returnType = returnTypeOf[element]; |
| 686 if (returnType == null) { | 699 if (returnType == null) { |
| 687 return dynamicType; | 700 if (compiler.trustTypeAnnotations |
| 701 && (element.isFunction() | |
| 702 || element.isGetter() | |
| 703 || element.isFactoryConstructor())) { | |
| 704 returnType = narrowType( | |
|
kasperl
2013/05/16 13:17:20
Couldn't you do the narrowing when you record? (li
ngeoffray
2013/05/17 14:34:25
This is in case the element has not been analyzed
| |
| 705 dynamicType, element.computeType(compiler).returnType); | |
| 706 } else { | |
| 707 returnType = dynamicType; | |
| 708 } | |
| 688 } | 709 } |
| 689 assert(returnType != null); | 710 assert(returnType != null); |
| 690 return returnType; | 711 return returnType; |
| 691 } | 712 } |
| 692 | 713 |
| 693 TypeMask typeOfNativeBehavior(native.NativeBehavior nativeBehavior) { | 714 TypeMask typeOfNativeBehavior(native.NativeBehavior nativeBehavior) { |
| 694 if (nativeBehavior == null) return dynamicType; | 715 if (nativeBehavior == null) return dynamicType; |
| 695 List typesReturned = nativeBehavior.typesReturned; | 716 List typesReturned = nativeBehavior.typesReturned; |
| 696 if (typesReturned.isEmpty) return dynamicType; | 717 if (typesReturned.isEmpty) return dynamicType; |
| 697 TypeMask returnType; | 718 TypeMask returnType; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 742 element = element.implementation; | 763 element = element.implementation; |
| 743 if (isNativeElement(element) && element.isField()) { | 764 if (isNativeElement(element) && element.isField()) { |
| 744 var type = typeOf.putIfAbsent(element, () { | 765 var type = typeOf.putIfAbsent(element, () { |
| 745 return new TypeMask.subtype(element.computeType(compiler).asRaw()); | 766 return new TypeMask.subtype(element.computeType(compiler).asRaw()); |
| 746 }); | 767 }); |
| 747 assert(type != null); | 768 assert(type != null); |
| 748 return type; | 769 return type; |
| 749 } | 770 } |
| 750 TypeMask type = typeOf[element]; | 771 TypeMask type = typeOf[element]; |
| 751 if (type == null) { | 772 if (type == null) { |
| 752 return dynamicType; | 773 if (compiler.trustTypeAnnotations |
| 774 && (element.isField() | |
| 775 || element.isParameter())) { | |
| 776 type = narrowType(dynamicType, element.computeType(compiler)); | |
| 777 } else { | |
| 778 type = dynamicType; | |
| 779 } | |
| 753 } | 780 } |
| 754 assert(type != null); | 781 assert(type != null); |
| 755 return type; | 782 return type; |
| 756 } | 783 } |
| 757 | 784 |
| 758 /** | 785 /** |
| 759 * Returns the union of the types of all elements that match | 786 * Returns the union of the types of all elements that match |
| 760 * the called [selector]. | 787 * the called [selector]. |
| 761 */ | 788 */ |
| 762 TypeMask typeOfSelector(Selector selector) { | 789 TypeMask typeOfSelector(Selector selector) { |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1239 return secondType; | 1266 return secondType; |
| 1240 } else if (isDynamicType(firstType)) { | 1267 } else if (isDynamicType(firstType)) { |
| 1241 return firstType; | 1268 return firstType; |
| 1242 } else { | 1269 } else { |
| 1243 TypeMask union = firstType.union(secondType, compiler); | 1270 TypeMask union = firstType.union(secondType, compiler); |
| 1244 // TODO(kasperl): If the union isn't nullable it seems wasteful | 1271 // TODO(kasperl): If the union isn't nullable it seems wasteful |
| 1245 // to use dynamic. Fix that. | 1272 // to use dynamic. Fix that. |
| 1246 return union.containsAll(compiler) ? dynamicType : union; | 1273 return union.containsAll(compiler) ? dynamicType : union; |
| 1247 } | 1274 } |
| 1248 } | 1275 } |
| 1276 | |
| 1277 TypeMask narrowType(TypeMask type, DartType annotation) { | |
| 1278 if (annotation.isDynamic) return type; | |
| 1279 TypeMask otherType; | |
| 1280 if (annotation.kind == TypeKind.TYPEDEF | |
| 1281 || annotation.kind == TypeKind.FUNCTION) { | |
| 1282 otherType = functionType.nullable(); | |
| 1283 } else if (annotation.kind != TypeKind.INTERFACE) { | |
| 1284 return type; | |
| 1285 } else { | |
| 1286 otherType = new TypeMask.subtype(annotation); | |
| 1287 } | |
| 1288 return type.intersection(otherType, compiler); | |
| 1289 } | |
| 1249 } | 1290 } |
| 1250 | 1291 |
| 1251 /** | 1292 /** |
| 1252 * Placeholder for inferred arguments types on sends. | 1293 * Placeholder for inferred arguments types on sends. |
| 1253 */ | 1294 */ |
| 1254 class ArgumentsTypes { | 1295 class ArgumentsTypes { |
| 1255 final List<TypeMask> positional; | 1296 final List<TypeMask> positional; |
| 1256 final Map<SourceString, TypeMask> named; | 1297 final Map<SourceString, TypeMask> named; |
| 1257 ArgumentsTypes(this.positional, named) | 1298 ArgumentsTypes(this.positional, named) |
| 1258 : this.named = (named == null) ? new Map<SourceString, TypeMask>() : named; | 1299 : this.named = (named == null) ? new Map<SourceString, TypeMask>() : named; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1318 assert(type != null); | 1359 assert(type != null); |
| 1319 if (capturedAndBoxed.contains(local) || inTryBlock) { | 1360 if (capturedAndBoxed.contains(local) || inTryBlock) { |
| 1320 // If a local is captured and boxed, or is set in a try block, | 1361 // If a local is captured and boxed, or is set in a try block, |
| 1321 // we compute the LUB of its assignments. | 1362 // we compute the LUB of its assignments. |
| 1322 // | 1363 // |
| 1323 // We don't know if an assignment in a try block | 1364 // We don't know if an assignment in a try block |
| 1324 // will be executed, so all assigments in that block are | 1365 // will be executed, so all assigments in that block are |
| 1325 // potential types after we have left it. | 1366 // potential types after we have left it. |
| 1326 type = inferrer.computeLUB(locals[local], type); | 1367 type = inferrer.computeLUB(locals[local], type); |
| 1327 } | 1368 } |
| 1328 locals[local] = type; | 1369 locals[local] = type; |
|
kasperl
2013/05/16 13:17:20
Shouldn't this use narrowing as well?
ngeoffray
2013/05/17 14:34:25
Done.
| |
| 1329 } | 1370 } |
| 1330 | 1371 |
| 1331 void setCapturedAndBoxed(Element local) { | 1372 void setCapturedAndBoxed(Element local) { |
| 1332 capturedAndBoxed.add(local); | 1373 capturedAndBoxed.add(local); |
| 1333 } | 1374 } |
| 1334 | 1375 |
| 1335 /** | 1376 /** |
| 1336 * Merge handlers [first] and [second] into [:this:] and returns | 1377 * Merge handlers [first] and [second] into [:this:] and returns |
| 1337 * whether the merge changed one of the variables types in [first]. | 1378 * whether the merge changed one of the variables types in [first]. |
| 1338 */ | 1379 */ |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2021 return inferrer.boolType; | 2062 return inferrer.boolType; |
| 2022 } else if (const SourceString("!") == op.source) { | 2063 } else if (const SourceString("!") == op.source) { |
| 2023 node.visitChildren(this); | 2064 node.visitChildren(this); |
| 2024 return inferrer.boolType; | 2065 return inferrer.boolType; |
| 2025 } else if (const SourceString("is") == op.source) { | 2066 } else if (const SourceString("is") == op.source) { |
| 2026 node.visitChildren(this); | 2067 node.visitChildren(this); |
| 2027 return inferrer.boolType; | 2068 return inferrer.boolType; |
| 2028 } else if (const SourceString("as") == op.source) { | 2069 } else if (const SourceString("as") == op.source) { |
| 2029 TypeMask receiverType = visit(node.receiver); | 2070 TypeMask receiverType = visit(node.receiver); |
| 2030 DartType type = elements.getType(node.arguments.head); | 2071 DartType type = elements.getType(node.arguments.head); |
| 2031 if (type.isDynamic) return receiverType; | 2072 return inferrer.narrowType(receiverType, type); |
| 2032 TypeMask asType = type.kind == TypeKind.TYPEDEF | |
| 2033 ? inferrer.functionType.nullable() | |
| 2034 : new TypeMask.subtype(type); | |
| 2035 // TODO(ngeoffray): Remove when inferrer.dynamicType is a proper | |
| 2036 // TypeMask. | |
| 2037 if (inferrer.isDynamicType(receiverType)) return asType; | |
| 2038 return receiverType.intersection(asType, compiler); | |
| 2039 } else if (node.isParameterCheck) { | 2073 } else if (node.isParameterCheck) { |
| 2040 node.visitChildren(this); | 2074 node.visitChildren(this); |
| 2041 return inferrer.boolType; | 2075 return inferrer.boolType; |
| 2042 } else if (node.argumentsNode is Prefix) { | 2076 } else if (node.argumentsNode is Prefix) { |
| 2043 // Unary operator. | 2077 // Unary operator. |
| 2044 return visitDynamicSend(node); | 2078 return visitDynamicSend(node); |
| 2045 } else if (const SourceString('===') == op.source | 2079 } else if (const SourceString('===') == op.source |
| 2046 || const SourceString('!==') == op.source) { | 2080 || const SourceString('!==') == op.source) { |
| 2047 node.visitChildren(this); | 2081 node.visitChildren(this); |
| 2048 return inferrer.boolType; | 2082 return inferrer.boolType; |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2355 } | 2389 } |
| 2356 | 2390 |
| 2357 TypeMask visitParenthesizedExpression(ParenthesizedExpression node) { | 2391 TypeMask visitParenthesizedExpression(ParenthesizedExpression node) { |
| 2358 return visit(node.expression); | 2392 return visit(node.expression); |
| 2359 } | 2393 } |
| 2360 | 2394 |
| 2361 void internalError(String reason, {Node node}) { | 2395 void internalError(String reason, {Node node}) { |
| 2362 compiler.internalError(reason, node: node); | 2396 compiler.internalError(reason, node: node); |
| 2363 } | 2397 } |
| 2364 } | 2398 } |
| OLD | NEW |